dsh-paste-code-block 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,7 +25,7 @@ Copying a 200‑line stack trace, an API response, or a long log into a chat inp
25
25
  - 🧩 **Auto block detection** — pasted text with ``` fences, newlines, heavy indentation, or length ≥ 96 becomes a card; ordinary short prose pastes through untouched.
26
26
  - 🏷️ **Language tags** — auto-detects Python / JS / JSON / YAML / SQL / bash / HTML·XML / C++ / Go / Ruby (incl. shebangs); plain-text blocks are tagged `text`.
27
27
  - ✏️ **In-card editing** — edit the content right in the detail card; the edited text is exactly what gets sent. Plus copy, collapse/expand, and hide.
28
- - 🈯 **Localized names** — chips are named in the current DSH language: `复制代码块1` / `Code block #1`, `复制文本块N` / `Text block #N`. Switching **Settings → Language** live-retitles every chip.
28
+ - 🈯 **Localized names** — chips are named in the current DSH language: `代码块 1` / `Code #1`, `文本块 N` / `Text #N`. A leading glyph and tint tells the two apart at a glance — `</>` blue for code, `Aa` gray for text. Switching **Settings → Language** live-retitles every chip.
29
29
  - × **One-click remove** — every chip carries its own `×` delete button (the detail card has one too); a removed number is recycled immediately.
30
30
  - 📤 **Fenced restore on send** — each card expands back into a ```` ```lang … ``` ```` block when you send; a failed send automatically refills the input.
31
31
  - 🔢 **Smart numbering** — code and text count apart; the smallest free number is always reused.
@@ -43,7 +43,7 @@ Chip labels, tooltips, line counts, and the send-time error notice all render th
43
43
 
44
44
  - **New pastes** are named in whatever language is active at paste time.
45
45
  - **Existing chips** are re-titled live when you flip 设置 → 语言 / Settings → Language — no reload needed.
46
- - Clicks and deletes match chips **across languages**: a `复制代码块2` chip still resolves to its block after switching to English (where it now reads `Code block #2`), and vice versa.
46
+ - Clicks and deletes match chips **across languages**: a `代码块 2` chip still resolves to its block after switching to English (where it now reads `Code #2`), and vice versa.
47
47
 
48
48
  ## Install
49
49
 
@@ -65,7 +65,7 @@ dsh plugin --profile web add file:/path/to/dsh-paste-code-block # from a local
65
65
  ## Usage
66
66
 
67
67
  1. Copy any code or multi-line text from anywhere.
68
- 2. Paste into the DSH input → it collapses into a chip such as `复制代码块1` / `Code block #1`.
68
+ 2. Paste into the DSH input → it collapses into a chip such as `代码块 1` / `Code #1`.
69
69
  3. Click the chip to open the card: read, edit inline, copy, collapse. Click the chip's (or the card's) `×` to delete that block.
70
70
  4. Send — the full original text goes out as a proper fenced code block.
71
71
 
package/README.zh-CN.md CHANGED
@@ -25,7 +25,7 @@
25
25
  - 🧩 **智能识别**:粘贴内容带 ``` 围栏、含换行、明显缩进、或长度 ≥ 96 → 收成卡片;普通短文本照常粘贴,绝不打扰。
26
26
  - 🏷️ **语言标签**:自动识别 Python / JS / JSON / YAML / SQL / bash / HTML·XML / C++ / Go / Ruby 等(可识别 shebang);纯文本块标为 `text`。
27
27
  - ✏️ **卡片内编辑**:详情卡里直接修改内容,发送的正是编辑后的文本;另有复制、折叠/展开、收起。
28
- - 🈯 **名称本地化**:芯片按当前 DSH 界面语言命名——`复制代码块1` / `Code block #1`、`复制文本块N` / `Text block #N`;在「设置 → 语言」切换后所有芯片即时改名。
28
+ - 🈯 **名称本地化**:芯片按当前 DSH 界面语言命名——`代码块 1` / `Code #1`、`文本块 N` / `Text #N`;前缀图标与配色一眼区分两类块(代码 `</>` 蓝色、文本 `Aa` 灰色);在「设置 → 语言」切换后所有芯片即时改名。
29
29
  - × **一键删除**:每个芯片自带 `×` 删除按钮(详情卡上也有);删掉的块编号立刻回收复用。
30
30
  - 📤 **发送还原**:发送时每个卡片展开还原为 ```` ```lang … ``` ```` 围栏代码块;发送失败自动回填输入框。
31
31
  - 🔢 **智能编号**:代码与文本分开计数,永远分配最小可用号。
@@ -43,7 +43,7 @@
43
43
 
44
44
  - **新粘贴**的块按粘贴时的界面语言命名。
45
45
  - **已插入的芯片**在 设置 → 语言 切换后原地改名,无需刷新页面。
46
- - 点击与删除**跨语言匹配**:切到英文后,原来叫 `复制代码块2` 的芯片(此时显示 `Code block #2`)依然指向同一个块,反之亦然。
46
+ - 点击与删除**跨语言匹配**:切到英文后,原来叫 `代码块 2` 的芯片(此时显示 `Code #2`)依然指向同一个块,反之亦然。
47
47
 
48
48
  ## 安装
49
49
 
@@ -65,7 +65,7 @@ dsh plugin --profile web add file:/path/to/dsh-paste-code-block # 从本地目
65
65
  ## 使用
66
66
 
67
67
  1. 在任意地方复制一段代码 / 一段多行文本。
68
- 2. 在 DSH 输入框粘贴 → 折叠成 `复制代码块1` 这样的芯片。
68
+ 2. 在 DSH 输入框粘贴 → 折叠成 `代码块 1` 这样的芯片。
69
69
  3. 点芯片打开详情卡:阅读、就地编辑、复制、折叠;点芯片(或卡片)上的 `×` 删除该块。
70
70
  4. 发送——完整原文以围栏代码块形式发出。
71
71
 
package/docs/design.md CHANGED
@@ -48,7 +48,7 @@ mechanism that renders file/upload references inline. The plugin registers a sou
48
48
  - `codec.clipboardText` → `''` (the chip leaves no visible text on copy)
49
49
  - `codec.serialize(ref)` → the block's fenced ```` ```lang … ``` ```` text
50
50
 
51
- The chip label is the localized human-readable badge (`复制代码块N` / `Code block #N` — see §9);
51
+ The chip label is the localized human-readable badge (`代码块 N` / `Code #N` — see §9);
52
52
  clicking it opens the detail card, and each chip carries a `×` button that deletes the block
53
53
  (see §10).
54
54
 
@@ -70,7 +70,7 @@ Numbers are tracked **per session, split by type** (`code` vs `text`):
70
70
  - `nextLabel` always allocates the **smallest free integer** (`while (used.has(n)) n++`).
71
71
  - Deleting a chip frees its number; the next paste reuses it.
72
72
 
73
- So `复制代码块1` … `复制代码块N` and `复制文本块1` … `复制文本块M` each count independently and
73
+ So `代码块 1` … `代码块 N` and `文本块 1` … `文本块 M` each count independently and
74
74
  stay dense after removals.
75
75
 
76
76
  ## 6. Markdown vs. code detection
@@ -112,6 +112,15 @@ Block names are produced through **DSH's own locale service**, the same one firs
112
112
  - The dock slot entry declares `locale: NS`, so the renderer hands it a fresh `t` seat **and
113
113
  re-renders it on every locale revision**.
114
114
 
115
+ **Naming and visual identity (0.1.3).** A chip is a *reference badge*, not an action button, so
116
+ the pre-0.1.3 names carried a verb nobody invokes on it — `复制代码块N` / `Code block #N` read
117
+ like a command and burned width inside the composer. Current names are noun + number
118
+ (`代码块 1` / `Code #1`). The code/text distinction moved from wording to visuals: `scanChips`
119
+ tags every chip host with `data-pcb-type`, and CSS renders a leading glyph — `</>` for code
120
+ (mono, business-primary) and `Aa` for text (neutral gray) — plus a soft blue tint on code
121
+ chips. Pre-0.1.3 labels stay parseable through the `legacyLabels` table, so chips inserted by
122
+ an older bundle keep their click/✕/retitle identity until the next locale-synced retitle.
123
+
115
124
  **Chip retitling across switches.** The chip label is *insert-time* content: Lexical caches the
116
125
  label inside the decorator node, and React never re-renders those node bodies while the node
117
126
  state is unchanged. So on a locale switch the plugin: (1) recomputes `block.label` for every
Binary file
@@ -1,4 +1,4 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="700" viewBox="0 0 1200 700">
2
2
  <rect width="1200" height="700" fill="#0d1220"/>
3
- <text x="40" y="56" font-size="26" fill="#e6ecf8" font-family="Noto Sans SC" font-weight="700">粘贴长代码 / 长文本 → 输入框里只留一张整洁卡片</text><text x="40" y="86" font-size="14.5" fill="#93a3c0" font-family="Noto Sans SC">Paste long code or text into the DSH composer — it lands as a tidy, collapsible card, never a wall of text</text><rect x="40" y="112" width="720" height="516" rx="16" fill="#151c2f"/><rect x="40" y="112" width="720" height="516" rx="16" fill="none" stroke="#2a3450" stroke-width="1"/><text x="64" y="140" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">DSH Web · 输入框 / composer</text><rect x="64" y="152" width="672" height="96" rx="10" fill="#10162a"/><rect x="64" y="152" width="672" height="96" rx="10" fill="none" stroke="#232c45" stroke-width="1"/><rect x="80" y="168" width="142" height="27" rx="7" fill="#1d2742"/><rect x="80" y="168" width="142" height="27" rx="7" fill="none" stroke="#3a4a75" stroke-width="1"/><text x="91" y="186" font-size="12.5" fill="#cdd9f2" font-family="Noto Sans SC">复制代码块1</text><text x="206" y="187" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="236" y="168" width="142" height="27" rx="7" fill="#1d2742"/><rect x="236" y="168" width="142" height="27" rx="7" fill="none" stroke="#3a4a75" stroke-width="1"/><text x="247" y="186" font-size="12.5" fill="#cdd9f2" font-family="Noto Sans SC">复制文本块1</text><text x="362" y="187" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="392" y="168" width="142" height="27" rx="7" fill="#1d2742"/><rect x="392" y="168" width="142" height="27" rx="7" fill="none" stroke="#3a4a75" stroke-width="1"/><text x="403" y="186" font-size="12.5" fill="#cdd9f2" font-family="Noto Sans SC">复制代码块2</text><text x="518" y="187" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><circle cx="518" cy="181.5" r="11" fill="none" stroke="#ff7b7b" stroke-width="1.6" stroke-dasharray="4 3"/><text x="80" y="234" font-size="13" fill="#5b6a8a" font-family="Noto Sans SC">帮我分析这段代码,重点是并发问题…</text><rect x="64" y="268" width="672" height="312" rx="12" fill="#131a2c"/><rect x="64" y="268" width="672" height="312" rx="12" fill="none" stroke="#232c45" stroke-width="1"/><rect x="80" y="282" width="60" height="22" rx="8" fill="#1c2b4d"/><text x="90" y="297" font-size="11.5" fill="#7aa2ff" font-family="JetBrains Mono">python</text><text x="154" y="297" font-size="11.5" fill="#5b6a8a" font-family="Noto Sans SC">42 行</text><path d="M 610 291 L 617 284.5 L 624 291" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><rect x="642" y="284" width="11" height="13" rx="2" fill="none"/><rect x="642" y="284" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><rect x="647" y="288" width="11" height="13" rx="2" fill="#131a2c"/><rect x="647" y="288" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><path d="M 680 284.5 L 673.5 290.5 L 680 297" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><text x="708" y="296.5" font-size="16" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><circle cx="708" cy="291" r="12" fill="none" stroke="#ff7b7b" stroke-width="1.6" stroke-dasharray="4 3"/><rect x="80" y="318" width="640" height="240" rx="8" fill="#0b1120"/><text x="98" y="348" font-size="13" fill="#c792ea" font-family="JetBrains Mono">def </text><text x="132" y="348" font-size="13" fill="#7aa2ff" font-family="JetBrains Mono">analyze</text><text x="180" y="348" font-size="13" fill="#d6deeb" font-family="JetBrains Mono">(chunks):</text><text x="98" y="376" font-size="13" fill="#d6deeb" font-family="JetBrains Mono"> total = 0</text><text x="98" y="404" font-size="13" fill="#d6deeb" font-family="JetBrains Mono"> results = []</text><text x="98" y="432" font-size="13" fill="#c792ea" font-family="JetBrains Mono"> for </text><text x="132" y="432" font-size="13" fill="#d6deeb" font-family="JetBrains Mono">c</text><text x="143" y="432" font-size="13" fill="#c792ea" font-family="JetBrains Mono"> in </text><text x="164" y="432" font-size="13" fill="#d6deeb" font-family="JetBrains Mono">chunks</text><text x="213" y="432" font-size="13" fill="#d6deeb" font-family="JetBrains Mono">:</text><text x="224" y="432" font-size="13" fill="#5b6a8a" font-family="JetBrains Mono"># 42 rows total — full, editable</text><text x="98" y="460" font-size="13" fill="#d6deeb" font-family="JetBrains Mono"> total += len(c.text)</text><text x="98" y="488" font-size="13" fill="#c792ea" font-family="JetBrains Mono"> return </text><text x="148" y="488" font-size="13" fill="#7aa2ff" font-family="JetBrains Mono">sorted</text><text x="198" y="488" font-size="13" fill="#d6deeb" font-family="JetBrains Mono">(results)[-5:]</text><rect x="98" y="504" width="520" height="1.6" fill="#232c45"/><text x="98" y="528" font-size="11.5" fill="#5b6a8a" font-family="Noto Sans SC">卡片内直接编辑 · 编辑后的文本即发送内容</text><rect x="664" y="596" width="72" height="28" rx="8" fill="#3b5bdb"/><text x="700" y="615" font-size="13.5" fill="#fff" font-family="Noto Sans SC" text-anchor="middle">发送</text><path d="M 806 168 C 675.5 168, 675.5 182, 545 182" stroke="#5b6a8a" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="820" cy="168" r="13" fill="#3b5bdb"/><text x="820" y="172.5" font-size="13.5" fill="#fff" font-family="Noto Sans SC" text-anchor="middle">1</text><text x="842" y="169" font-size="15" fill="#e6ecf8" font-family="Noto Sans SC">点击芯片 → 展开 / 收起详情卡</text><text x="842" y="189" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">click a chip to open its card</text><path d="M 806 262 C 753 262, 753 291, 700 291" stroke="#5b6a8a" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="820" cy="268" r="13" fill="#3b5bdb"/><text x="820" y="272.5" font-size="13.5" fill="#fff" font-family="Noto Sans SC" text-anchor="middle">2</text><text x="842" y="269" font-size="15" fill="#e6ecf8" font-family="Noto Sans SC">× 一键删除对应块,编号自动回收复用</text><text x="842" y="289" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">one-click remove · the number is recycled</text><path d="M 806 372 C 764 372, 764 430, 722 430" stroke="#5b6a8a" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="820" cy="372" r="13" fill="#3b5bdb"/><text x="820" y="376.5" font-size="13.5" fill="#fff" font-family="Noto Sans SC" text-anchor="middle">3</text><text x="842" y="373" font-size="15" fill="#e6ecf8" font-family="Noto Sans SC">详情卡:编辑 / 复制 / 折叠</text><text x="842" y="393" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">edit, copy, collapse — all inline</text><line x1="756" y1="612" x2="806" y2="612" stroke="#5b6a8a" stroke-width="1.4"/><path d="M 806 612 l -8 -4 v 8 z" stroke="#5b6a8a" stroke-width="1" fill="#5b6a8a" stroke-linecap="round" stroke-linejoin="round"/><rect x="812" y="470" width="348" height="150" rx="12" fill="#10162a"/><rect x="812" y="470" width="348" height="150" rx="12" fill="none" stroke="#232c45" stroke-width="1"/><text x="832" y="496" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">发送后 · on send</text><text x="832" y="524" font-size="12.5" fill="#93a3c0" font-family="JetBrains Mono">```python</text><text x="832" y="548" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono">def analyze(chunks):</text><text x="832" y="572" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono"> ...完整原始文本...</text><text x="832" y="596" font-size="12.5" fill="#93a3c0" font-family="JetBrains Mono">```</text><circle cx="820" cy="662" r="13" fill="#3b5bdb"/><text x="820" y="666.5" font-size="13.5" fill="#fff" font-family="Noto Sans SC" text-anchor="middle">4</text><text x="842" y="663" font-size="15" fill="#e6ecf8" font-family="Noto Sans SC">发送时自动还原为围栏代码块</text><text x="842" y="683" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">restored as a fenced code block on send</text><text x="40" y="662" font-size="12.5" fill="#5b6a8a" font-family="Noto Sans SC">PC 与移动端 Web 通用 · 深浅主题自适应 · 标签随 DSH 界面语言自动切换(中文 / English)</text>
3
+ <text x="40" y="56" font-size="26" fill="#e6ecf8" font-family="Noto Sans SC" font-weight="700">粘贴长代码 / 长文本 → 输入框里只留一张整洁卡片</text><text x="40" y="86" font-size="14.5" fill="#93a3c0" font-family="Noto Sans SC">Paste long code or text into the DSH composer — it lands as a tidy, collapsible card, never a wall of text</text><rect x="40" y="112" width="720" height="516" rx="16" fill="#151c2f"/><rect x="40" y="112" width="720" height="516" rx="16" fill="none" stroke="#2a3450" stroke-width="1"/><text x="64" y="140" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">DSH Web · 输入框 / composer</text><rect x="64" y="152" width="672" height="96" rx="10" fill="#10162a"/><rect x="64" y="152" width="672" height="96" rx="10" fill="none" stroke="#232c45" stroke-width="1"/><rect x="80" y="168" width="126" height="27" rx="7" fill="#151e3c"/><rect x="80" y="168" width="126" height="27" rx="7" fill="none" stroke="#263777" stroke-width="1"/><text x="89" y="185.5" font-size="10.5" fill="#7aa2ff" font-family="JetBrains Mono" font-weight="700">&lt;/&gt;</text><text x="112" y="186" font-size="12.5" fill="#8fb0ff" font-family="Noto Sans SC">代码块 1</text><text x="196" y="187" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="214" y="168" width="126" height="27" rx="7" fill="#1d2742"/><rect x="214" y="168" width="126" height="27" rx="7" fill="none" stroke="#3a4a75" stroke-width="1"/><text x="223" y="185.5" font-size="10.5" fill="#93a3c0" font-family="Noto Sans SC" font-weight="700">Aa</text><text x="243" y="186" font-size="12.5" fill="#cdd9f2" font-family="Noto Sans SC">文本块 1</text><text x="330" y="187" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="348" y="168" width="126" height="27" rx="7" fill="#151e3c"/><rect x="348" y="168" width="126" height="27" rx="7" fill="none" stroke="#263777" stroke-width="1"/><text x="357" y="185.5" font-size="10.5" fill="#7aa2ff" font-family="JetBrains Mono" font-weight="700">&lt;/&gt;</text><text x="380" y="186" font-size="12.5" fill="#8fb0ff" font-family="Noto Sans SC">代码块 2</text><text x="464" y="187" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><circle cx="464" cy="181.5" r="11" fill="none" stroke="#ff7b7b" stroke-width="1.6" stroke-dasharray="4 3"/><text x="80" y="234" font-size="13" fill="#5b6a8a" font-family="Noto Sans SC">帮我分析这段代码,重点是并发问题…</text><rect x="64" y="268" width="672" height="312" rx="12" fill="#131a2c"/><rect x="64" y="268" width="672" height="312" rx="12" fill="none" stroke="#232c45" stroke-width="1"/><rect x="80" y="282" width="60" height="22" rx="8" fill="#1c2b4d"/><text x="90" y="297" font-size="11.5" fill="#7aa2ff" font-family="JetBrains Mono">python</text><text x="154" y="297" font-size="11.5" fill="#5b6a8a" font-family="Noto Sans SC">42 行</text><path d="M 610 291 L 617 284.5 L 624 291" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><rect x="642" y="284" width="11" height="13" rx="2" fill="none"/><rect x="642" y="284" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><rect x="647" y="288" width="11" height="13" rx="2" fill="#131a2c"/><rect x="647" y="288" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><path d="M 680 284.5 L 673.5 290.5 L 680 297" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><text x="708" y="296.5" font-size="16" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><circle cx="708" cy="291" r="12" fill="none" stroke="#ff7b7b" stroke-width="1.6" stroke-dasharray="4 3"/><rect x="80" y="318" width="640" height="240" rx="8" fill="#0b1120"/><text x="98" y="348" font-size="13" fill="#c792ea" font-family="JetBrains Mono">def </text><text x="132" y="348" font-size="13" fill="#7aa2ff" font-family="JetBrains Mono">analyze</text><text x="180" y="348" font-size="13" fill="#d6deeb" font-family="JetBrains Mono">(chunks):</text><text x="98" y="376" font-size="13" fill="#d6deeb" font-family="JetBrains Mono"> total = 0</text><text x="98" y="404" font-size="13" fill="#d6deeb" font-family="JetBrains Mono"> results = []</text><text x="98" y="432" font-size="13" fill="#c792ea" font-family="JetBrains Mono"> for </text><text x="132" y="432" font-size="13" fill="#d6deeb" font-family="JetBrains Mono">c</text><text x="143" y="432" font-size="13" fill="#c792ea" font-family="JetBrains Mono"> in </text><text x="164" y="432" font-size="13" fill="#d6deeb" font-family="JetBrains Mono">chunks</text><text x="213" y="432" font-size="13" fill="#d6deeb" font-family="JetBrains Mono">:</text><text x="224" y="432" font-size="13" fill="#5b6a8a" font-family="JetBrains Mono"># 42 rows total — full, editable</text><text x="98" y="460" font-size="13" fill="#d6deeb" font-family="JetBrains Mono"> total += len(c.text)</text><text x="98" y="488" font-size="13" fill="#c792ea" font-family="JetBrains Mono"> return </text><text x="148" y="488" font-size="13" fill="#7aa2ff" font-family="JetBrains Mono">sorted</text><text x="198" y="488" font-size="13" fill="#d6deeb" font-family="JetBrains Mono">(results)[-5:]</text><rect x="98" y="504" width="520" height="1.6" fill="#232c45"/><text x="98" y="528" font-size="11.5" fill="#5b6a8a" font-family="Noto Sans SC">卡片内直接编辑 · 编辑后的文本即发送内容</text><rect x="664" y="596" width="72" height="28" rx="8" fill="#3b5bdb"/><text x="700" y="615" font-size="13.5" fill="#fff" font-family="Noto Sans SC" text-anchor="middle">发送</text><path d="M 806 168 C 675.5 168, 675.5 182, 545 182" stroke="#5b6a8a" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="820" cy="168" r="13" fill="#3b5bdb"/><text x="820" y="172.5" font-size="13.5" fill="#fff" font-family="Noto Sans SC" text-anchor="middle">1</text><text x="842" y="169" font-size="15" fill="#e6ecf8" font-family="Noto Sans SC">点击芯片 → 展开 / 收起详情卡</text><text x="842" y="189" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">click a chip to open its card</text><path d="M 806 262 C 753 262, 753 291, 700 291" stroke="#5b6a8a" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="820" cy="268" r="13" fill="#3b5bdb"/><text x="820" y="272.5" font-size="13.5" fill="#fff" font-family="Noto Sans SC" text-anchor="middle">2</text><text x="842" y="269" font-size="15" fill="#e6ecf8" font-family="Noto Sans SC">× 一键删除对应块,编号自动回收复用</text><text x="842" y="289" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">one-click remove · the number is recycled</text><path d="M 806 372 C 764 372, 764 430, 722 430" stroke="#5b6a8a" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="820" cy="372" r="13" fill="#3b5bdb"/><text x="820" y="376.5" font-size="13.5" fill="#fff" font-family="Noto Sans SC" text-anchor="middle">3</text><text x="842" y="373" font-size="15" fill="#e6ecf8" font-family="Noto Sans SC">详情卡:编辑 / 复制 / 折叠</text><text x="842" y="393" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">edit, copy, collapse — all inline</text><line x1="756" y1="612" x2="806" y2="612" stroke="#5b6a8a" stroke-width="1.4"/><path d="M 806 612 l -8 -4 v 8 z" stroke="#5b6a8a" stroke-width="1" fill="#5b6a8a" stroke-linecap="round" stroke-linejoin="round"/><rect x="812" y="470" width="348" height="150" rx="12" fill="#10162a"/><rect x="812" y="470" width="348" height="150" rx="12" fill="none" stroke="#232c45" stroke-width="1"/><text x="832" y="496" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">发送后 · on send</text><text x="832" y="524" font-size="12.5" fill="#93a3c0" font-family="JetBrains Mono">```python</text><text x="832" y="548" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono">def analyze(chunks):</text><text x="832" y="572" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono"> ...完整原始文本...</text><text x="832" y="596" font-size="12.5" fill="#93a3c0" font-family="JetBrains Mono">```</text><circle cx="820" cy="662" r="13" fill="#3b5bdb"/><text x="820" y="666.5" font-size="13.5" fill="#fff" font-family="Noto Sans SC" text-anchor="middle">4</text><text x="842" y="663" font-size="15" fill="#e6ecf8" font-family="Noto Sans SC">发送时自动还原为围栏代码块</text><text x="842" y="683" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">restored as a fenced code block on send</text><text x="40" y="662" font-size="12.5" fill="#5b6a8a" font-family="Noto Sans SC">PC 与移动端 Web 通用 · 深浅主题自适应 · 标签随 DSH 界面语言自动切换(中文 / English)</text>
4
4
  </svg>
Binary file
@@ -1,4 +1,4 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="464" viewBox="0 0 1200 464">
2
2
  <rect width="1200" height="464" fill="#0d1220"/>
3
- <text x="40" y="50" font-size="22" fill="#e6ecf8" font-family="Noto Sans SC" font-weight="700">块名称跟随 DSH 界面语言 · Block names follow the UI language</text><rect x="36" y="84" width="548" height="296" rx="14" fill="#151c2f"/><rect x="36" y="84" width="548" height="296" rx="14" fill="none" stroke="#2a3450" stroke-width="1"/><rect x="60" y="108" width="226" height="28" rx="14" fill="#0b1120"/><rect x="60" y="108" width="226" height="28" rx="14" fill="none" stroke="#232c45" stroke-width="1"/><text x="76" y="126" font-size="12.5" fill="#93a3c0" font-family="Noto Sans SC">设置 → 语言:中文</text><rect x="60" y="158" width="142" height="27" rx="7" fill="#1d2742"/><rect x="60" y="158" width="142" height="27" rx="7" fill="none" stroke="#3a4a75" stroke-width="1"/><text x="71" y="176" font-size="12.5" fill="#cdd9f2" font-family="Noto Sans SC">复制代码块1</text><text x="186" y="177" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="210" y="158" width="142" height="27" rx="7" fill="#1d2742"/><rect x="210" y="158" width="142" height="27" rx="7" fill="none" stroke="#3a4a75" stroke-width="1"/><text x="221" y="176" font-size="12.5" fill="#cdd9f2" font-family="Noto Sans SC">复制文本块1</text><text x="336" y="177" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="60" y="206" width="500" height="148" rx="10" fill="#131a2c"/><rect x="60" y="206" width="500" height="148" rx="10" fill="none" stroke="#232c45" stroke-width="1"/><rect x="76" y="220" width="62" height="20" rx="7" fill="#1c2b4d"/><text x="86" y="234" font-size="11" fill="#7aa2ff" font-family="JetBrains Mono">python</text><text x="152" y="234" font-size="11" fill="#5b6a8a" font-family="Noto Sans SC">18 行</text><path d="M 436 229 L 443 222.5 L 450 229" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><rect x="468" y="222" width="11" height="13" rx="2" fill="none"/><rect x="468" y="222" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><rect x="473" y="226" width="11" height="13" rx="2" fill="#131a2c"/><rect x="473" y="226" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><path d="M 506 222.5 L 499.5 228.5 L 506 235" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><text x="534" y="234.5" font-size="16" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><text x="76" y="266" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono">def analyze(chunks):</text><text x="76" y="290" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono"> total = 0</text><text x="76" y="314" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono"> return sorted(results)</text><rect x="616" y="84" width="548" height="296" rx="14" fill="#151c2f"/><rect x="616" y="84" width="548" height="296" rx="14" fill="none" stroke="#2a3450" stroke-width="1"/><rect x="640" y="108" width="226" height="28" rx="14" fill="#0b1120"/><rect x="640" y="108" width="226" height="28" rx="14" fill="none" stroke="#232c45" stroke-width="1"/><text x="656" y="126" font-size="12.5" fill="#93a3c0" font-family="Noto Sans SC">Settings → Language: English</text><rect x="640" y="158" width="150" height="27" rx="7" fill="#1d2742"/><rect x="640" y="158" width="150" height="27" rx="7" fill="none" stroke="#3a4a75" stroke-width="1"/><text x="651" y="176" font-size="12.5" fill="#cdd9f2" font-family="Noto Sans SC">Code block #1</text><text x="774" y="177" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="798" y="158" width="150" height="27" rx="7" fill="#1d2742"/><rect x="798" y="158" width="150" height="27" rx="7" fill="none" stroke="#3a4a75" stroke-width="1"/><text x="809" y="176" font-size="12.5" fill="#cdd9f2" font-family="Noto Sans SC">Text block #1</text><text x="932" y="177" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="640" y="206" width="500" height="148" rx="10" fill="#131a2c"/><rect x="640" y="206" width="500" height="148" rx="10" fill="none" stroke="#232c45" stroke-width="1"/><rect x="656" y="220" width="62" height="20" rx="7" fill="#1c2b4d"/><text x="666" y="234" font-size="11" fill="#7aa2ff" font-family="JetBrains Mono">python</text><text x="732" y="234" font-size="11" fill="#5b6a8a" font-family="Noto Sans SC">18 lines</text><path d="M 1016 229 L 1023 222.5 L 1030 229" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><rect x="1048" y="222" width="11" height="13" rx="2" fill="none"/><rect x="1048" y="222" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><rect x="1053" y="226" width="11" height="13" rx="2" fill="#131a2c"/><rect x="1053" y="226" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><path d="M 1086 222.5 L 1079.5 228.5 L 1086 235" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><text x="1114" y="234.5" font-size="16" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><text x="656" y="266" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono">def analyze(chunks):</text><text x="656" y="290" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono"> total = 0</text><text x="656" y="314" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono"> return sorted(results)</text><path d="M 590 226 h 20 m -7 -6 l 7 6 l -7 6 M 610 246 h -20 m 7 6 l -7 -6 l 7 -6" stroke="#7aa2ff" stroke-width="2.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/><text x="600" y="284" font-size="11" fill="#5b6a8a" font-family="Noto Sans SC" text-anchor="middle">切换</text><text x="600" y="300" font-size="10.5" fill="#5b6a8a" font-family="Noto Sans SC" text-anchor="middle">live</text><text x="40" y="416" font-size="13.5" fill="#93a3c0" font-family="Noto Sans SC">语言切换即时生效:新粘贴的块用新语言命名,已插入的芯片也会同步改名</text><text x="40" y="438" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">Switch anytime — new pastes land in the new language, existing chips retitle live</text>
3
+ <text x="40" y="50" font-size="22" fill="#e6ecf8" font-family="Noto Sans SC" font-weight="700">块名称跟随 DSH 界面语言 · Block names follow the UI language</text><rect x="36" y="84" width="548" height="296" rx="14" fill="#151c2f"/><rect x="36" y="84" width="548" height="296" rx="14" fill="none" stroke="#2a3450" stroke-width="1"/><rect x="60" y="108" width="226" height="28" rx="14" fill="#0b1120"/><rect x="60" y="108" width="226" height="28" rx="14" fill="none" stroke="#232c45" stroke-width="1"/><text x="76" y="126" font-size="12.5" fill="#93a3c0" font-family="Noto Sans SC">设置 → 语言:中文</text><rect x="60" y="158" width="126" height="27" rx="7" fill="#1a2341"/><rect x="60" y="158" width="126" height="27" rx="7" fill="none" stroke="#2a3b7a" stroke-width="1"/><text x="69" y="175.5" font-size="10.5" fill="#7aa2ff" font-family="JetBrains Mono" font-weight="700">&lt;/&gt;</text><text x="92" y="176" font-size="12.5" fill="#8fb0ff" font-family="Noto Sans SC">代码块 1</text><text x="176" y="177" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="194" y="158" width="126" height="27" rx="7" fill="#1d2742"/><rect x="194" y="158" width="126" height="27" rx="7" fill="none" stroke="#3a4a75" stroke-width="1"/><text x="203" y="175.5" font-size="10.5" fill="#93a3c0" font-family="Noto Sans SC" font-weight="700">Aa</text><text x="223" y="176" font-size="12.5" fill="#cdd9f2" font-family="Noto Sans SC">文本块 1</text><text x="310" y="177" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="60" y="206" width="500" height="148" rx="10" fill="#131a2c"/><rect x="60" y="206" width="500" height="148" rx="10" fill="none" stroke="#232c45" stroke-width="1"/><rect x="76" y="220" width="62" height="20" rx="7" fill="#1c2b4d"/><text x="86" y="234" font-size="11" fill="#7aa2ff" font-family="JetBrains Mono">python</text><text x="152" y="234" font-size="11" fill="#5b6a8a" font-family="Noto Sans SC">18 行</text><path d="M 436 229 L 443 222.5 L 450 229" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><rect x="468" y="222" width="11" height="13" rx="2" fill="none"/><rect x="468" y="222" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><rect x="473" y="226" width="11" height="13" rx="2" fill="#131a2c"/><rect x="473" y="226" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><path d="M 506 222.5 L 499.5 228.5 L 506 235" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><text x="534" y="234.5" font-size="16" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><text x="76" y="266" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono">def analyze(chunks):</text><text x="76" y="290" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono"> total = 0</text><text x="76" y="314" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono"> return sorted(results)</text><rect x="616" y="84" width="548" height="296" rx="14" fill="#151c2f"/><rect x="616" y="84" width="548" height="296" rx="14" fill="none" stroke="#2a3450" stroke-width="1"/><rect x="640" y="108" width="226" height="28" rx="14" fill="#0b1120"/><rect x="640" y="108" width="226" height="28" rx="14" fill="none" stroke="#232c45" stroke-width="1"/><text x="656" y="126" font-size="12.5" fill="#93a3c0" font-family="Noto Sans SC">Settings → Language: English</text><rect x="640" y="158" width="122" height="27" rx="7" fill="#1a2341"/><rect x="640" y="158" width="122" height="27" rx="7" fill="none" stroke="#2a3b7a" stroke-width="1"/><text x="649" y="175.5" font-size="10.5" fill="#7aa2ff" font-family="JetBrains Mono" font-weight="700">&lt;/&gt;</text><text x="672" y="176" font-size="12.5" fill="#8fb0ff" font-family="Noto Sans SC">Code #1</text><text x="751" y="177" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="770" y="158" width="122" height="27" rx="7" fill="#1d2742"/><rect x="770" y="158" width="122" height="27" rx="7" fill="none" stroke="#3a4a75" stroke-width="1"/><text x="779" y="175.5" font-size="10.5" fill="#93a3c0" font-family="Noto Sans SC" font-weight="700">Aa</text><text x="799" y="176" font-size="12.5" fill="#cdd9f2" font-family="Noto Sans SC">Text #1</text><text x="881" y="177" font-size="15" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><rect x="640" y="206" width="500" height="148" rx="10" fill="#131a2c"/><rect x="640" y="206" width="500" height="148" rx="10" fill="none" stroke="#232c45" stroke-width="1"/><rect x="656" y="220" width="62" height="20" rx="7" fill="#1c2b4d"/><text x="666" y="234" font-size="11" fill="#7aa2ff" font-family="JetBrains Mono">python</text><text x="732" y="234" font-size="11" fill="#5b6a8a" font-family="Noto Sans SC">18 lines</text><path d="M 1016 229 L 1023 222.5 L 1030 229" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><rect x="1048" y="222" width="11" height="13" rx="2" fill="none"/><rect x="1048" y="222" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><rect x="1053" y="226" width="11" height="13" rx="2" fill="#131a2c"/><rect x="1053" y="226" width="11" height="13" rx="2" fill="none" stroke="#93a3c0" stroke-width="1"/><path d="M 1086 222.5 L 1079.5 228.5 L 1086 235" stroke="#93a3c0" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/><text x="1114" y="234.5" font-size="16" fill="#ff7b7b" font-family="Noto Sans SC" text-anchor="middle">×</text><text x="656" y="266" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono">def analyze(chunks):</text><text x="656" y="290" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono"> total = 0</text><text x="656" y="314" font-size="12.5" fill="#d6deeb" font-family="JetBrains Mono"> return sorted(results)</text><path d="M 590 226 h 20 m -7 -6 l 7 6 l -7 6 M 610 246 h -20 m 7 6 l -7 -6 l 7 -6" stroke="#7aa2ff" stroke-width="2.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/><text x="600" y="284" font-size="11" fill="#5b6a8a" font-family="Noto Sans SC" text-anchor="middle">切换</text><text x="600" y="300" font-size="10.5" fill="#5b6a8a" font-family="Noto Sans SC" text-anchor="middle">live</text><text x="40" y="416" font-size="13.5" fill="#93a3c0" font-family="Noto Sans SC">语言切换即时生效:新粘贴的块用新语言命名,已插入的芯片也会同步改名</text><text x="40" y="438" font-size="12" fill="#5b6a8a" font-family="Noto Sans SC">Switch anytime — new pastes land in the new language, existing chips retitle live</text>
4
4
  </svg>
@@ -0,0 +1,20 @@
1
+ // Regenerate the README mockup PNGs from the SVG sources in this folder.
2
+ // Dev-only helper (not loaded by the plugin). Requires: npm i @resvg/resvg-js
3
+ // and the fonts referenced below (apt: fonts-noto-cjk fonts-jetbrains-mono).
4
+ const fs = require('fs')
5
+ const path = require('path')
6
+ const { Resvg } = require('@resvg/resvg-js')
7
+
8
+ const FONTS = [
9
+ '/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
10
+ '/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc',
11
+ '/usr/share/fonts/truetype/jetbrains-mono/JetBrainsMono-Regular.ttf',
12
+ '/usr/share/fonts/truetype/jetbrains-mono/JetBrainsMono-Bold.ttf',
13
+ ]
14
+ for (const name of ['hero', 'languages', 'workflow']) {
15
+ let src = fs.readFileSync(path.join(__dirname, name + '.svg'), 'utf8')
16
+ src = src.split('font-family="Noto Sans SC"').join('font-family="Noto Sans CJK SC"')
17
+ const r = new Resvg(src, { fitTo: { mode: 'zoom', value: 2 }, font: { fontFiles: FONTS, loadSystemFonts: false, defaultFontFamily: 'Noto Sans CJK SC', sansSerifFamily: 'Noto Sans CJK SC', monospaceFamily: 'JetBrains Mono' } })
18
+ fs.writeFileSync(path.join(__dirname, name + '.png'), r.render().asPng())
19
+ console.log('rendered', name + '.png')
20
+ }
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-paste-code-block",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Cherry Studio-style paste for DSH Web: pasted text/code becomes a bordered, collapsible, language-tagged card with localized names (中文/English) and a one-click remove button; restored as a fenced code block on send.",
5
5
  "license": "MIT",
6
6
  "author": "DSH paste-code-block contributors",
@@ -65,17 +65,28 @@
65
65
  "react": "^18.2.0"
66
66
  },
67
67
  "peerDependenciesMeta": {
68
- "@deepseek-ai/dsh-client-ui-conversation": { "optional": true },
69
- "@deepseek-ai/dsh-client-ui-input-trigger": { "optional": true },
70
- "@deepseek-ai/dsh-client-ui-slots": { "optional": true },
71
- "@deepseek-ai/dsh-client-locale": { "optional": true },
72
- "react": { "optional": true }
68
+ "@deepseek-ai/dsh-client-ui-conversation": {
69
+ "optional": true
70
+ },
71
+ "@deepseek-ai/dsh-client-ui-input-trigger": {
72
+ "optional": true
73
+ },
74
+ "@deepseek-ai/dsh-client-ui-slots": {
75
+ "optional": true
76
+ },
77
+ "@deepseek-ai/dsh-client-locale": {
78
+ "optional": true
79
+ },
80
+ "react": {
81
+ "optional": true
82
+ }
73
83
  },
74
84
  "engines": {
75
85
  "node": ">=20"
76
86
  },
77
87
  "scripts": {
78
88
  "check": "node --check src/index.js && node --check src/i18n.js && node --check src/chip-nodes.js && node --check src/projection.js && node --check src/client.js",
79
- "test": "node --test 'tests/**/*.test.js'"
89
+ "test": "node --test 'tests/**/*.test.js'",
90
+ "render:images": "node docs/images/render.cjs"
80
91
  }
81
92
  }
package/src/client.js CHANGED
@@ -94,8 +94,8 @@ window.__ModuleLoader__.load({
94
94
  const NS = 'paste-code-block'
95
95
  const L10N = {
96
96
  zh: {
97
- 'block.code': '复制代码块{n}',
98
- 'block.text': '复制文本块{n}',
97
+ 'block.code': '代码块 {n}',
98
+ 'block.text': '文本块 {n}',
99
99
  'detail.aria': '代码块详情',
100
100
  'slot.label': '粘贴代码块详情',
101
101
  'lines.one': '{count} 行',
@@ -111,8 +111,8 @@ window.__ModuleLoader__.load({
111
111
  'error.remove': '无法删除该块,请重试',
112
112
  },
113
113
  en: {
114
- 'block.code': 'Code block #{n}',
115
- 'block.text': 'Text block #{n}',
114
+ 'block.code': 'Code #{n}',
115
+ 'block.text': 'Text #{n}',
116
116
  'detail.aria': 'Block details',
117
117
  'slot.label': 'Pasted block details',
118
118
  'lines.one': '{count} line',
@@ -147,15 +147,22 @@ window.__ModuleLoader__.load({
147
147
  }
148
148
  }
149
149
 
150
+ // Pre-0.1.3 chip labels: no longer rendered, still recognized (see below).
151
+ const LEGACY_L10N = {
152
+ zh: { 'block.code': '复制代码块{n}', 'block.text': '复制文本块{n}' },
153
+ en: { 'block.code': 'Code block #{n}', 'block.text': 'Text block #{n}' },
154
+ }
155
+
150
156
  /**
151
- * Recognize a rendered block label in ANY shipped locale and recover its
152
- * `{ type, n }` identity — this keeps chip clicks, ✕ deletes, and the
153
- * locale-switch retitling correct even for chips inserted under a
154
- * different language than the one currently active. Null otherwise.
157
+ * Recognize a rendered block label in ANY shipped locale (or a pre-0.1.3
158
+ * legacy locale) and recover its `{ type, n }` identity — this keeps chip
159
+ * clicks, ✕ deletes, and the locale-switch retitling correct even for
160
+ * chips inserted under a different language than the one currently
161
+ * active. Null otherwise.
155
162
  */
156
163
  function parseBlockLabel(text) {
157
164
  if (!text) return null
158
- for (const dict of [L10N.zh, L10N.en]) {
165
+ for (const dict of [L10N.zh, L10N.en, LEGACY_L10N.zh, LEGACY_L10N.en]) {
159
166
  for (const key of ['block.code', 'block.text']) {
160
167
  const pattern = new RegExp(
161
168
  '^' +
@@ -201,8 +208,8 @@ window.__ModuleLoader__.load({
201
208
  /**
202
209
  * Parse pasted text into a block, or null when it is ordinary short prose
203
210
  * that should paste plainly. `isCode` drives both the chip label
204
- * (i18n key `block.code` vs `block.text`, e.g. "复制代码块N" / "Code block
205
- * #N") and the fenced language on send.
211
+ * (i18n key `block.code` vs `block.text`, e.g. "代码块 N" / "Code #N")
212
+ * and the fenced language on send.
206
213
  */
207
214
  function parseBlock(raw) {
208
215
  const text = String(raw || '').replace(/^\uFEFF/, '')
@@ -849,6 +856,25 @@ window.__ModuleLoader__.load({
849
856
  /* the label text (the trailing ✕ element is ours — never ellipsis it) */
850
857
  [data-composer-chip="${SOURCE}"] > span > span:not(.${CHIP_X_CLASS}){font-weight:500!important;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
851
858
 
859
+ /* --- type identity: leading glyph + tint (data-pcb-type set by scanChips) --- */
860
+ [data-composer-chip="${SOURCE}"][data-pcb-type="code"] > span{
861
+ border-color:var(--dsh-pcb-code-border,rgba(76,110,245,.38))!important;
862
+ background:var(--dsh-pcb-code-bg,rgba(76,110,245,.09))!important;
863
+ color:var(--dsw-alias-state-business-primary,#4c6ef5)!important
864
+ }
865
+ [data-composer-chip="${SOURCE}"][data-pcb-type="code"]:hover > span{
866
+ border-color:var(--dsw-alias-state-business-primary,#4c6ef5)!important;
867
+ background:var(--dsh-pcb-code-bg-hover,rgba(76,110,245,.16))!important
868
+ }
869
+ [data-composer-chip="${SOURCE}"][data-pcb-type="code"] > span::before{
870
+ content:'</>';flex:none;font-family:var(--dsw-font-mono,ui-monospace,Menlo,Consolas,monospace);
871
+ font-size:10px;font-weight:700;line-height:16px;opacity:.9
872
+ }
873
+ [data-composer-chip="${SOURCE}"][data-pcb-type="text"] > span::before{
874
+ content:'Aa';flex:none;font-size:10px;font-weight:700;line-height:16px;
875
+ letter-spacing:.2px;color:var(--dsw-alias-label-tertiary)
876
+ }
877
+
852
878
  /* --- per-chip ✕ delete button (element we own, appended inside the chip) --- */
853
879
  .${CHIP_X_CLASS}{
854
880
  box-sizing:border-box;flex:none;width:16px;height:16px;display:inline-grid;place-items:center;
@@ -923,6 +949,11 @@ window.__ModuleLoader__.load({
923
949
  if (!sid) continue
924
950
  const block = controller.listFor(sid).find((b) => b.type === parsed.type && b.labelNumber === parsed.n)
925
951
  if (!block) continue
952
+ // Tag the chip host with its type so CSS can render the leading
953
+ // glyph and tint (code = blue `</>`, text = neutral `Aa`).
954
+ if (host.getAttribute('data-pcb-type') !== parsed.type) {
955
+ host.setAttribute('data-pcb-type', parsed.type)
956
+ }
926
957
  // Retitle the chip to the current language. Lexical caches the
927
958
  // insert-time label inside the node, so on a Settings → Language
928
959
  // switch (or a chip that remounted with the old label) the DOM is
package/src/i18n.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * dsh-paste-code-block — locale dictionaries and label logic (pure, no DOM).
3
3
  *
4
- * Canonical source for the user-visible names of pasted blocks ("复制代码块N"
5
- * vs "Code block #N", etc.). The browser half (`client.js`) embeds its own
4
+ * Canonical source for the user-visible names of pasted blocks ("代码块 1"
5
+ * vs "Code #1", etc.). The browser half (`client.js`) embeds its own
6
6
  * copy of this logic because DSH's client module loader resolves *package
7
7
  * names*, not relative ESM files; this module is the single place where that
8
8
  * logic is unit-tested. **Keep `src/i18n.js` and the embedded copy in
@@ -19,8 +19,8 @@ export const NS = 'paste-code-block'
19
19
 
20
20
  /** Simplified Chinese dictionary (the key-set source of truth). */
21
21
  export const zh = {
22
- 'block.code': '复制代码块{n}',
23
- 'block.text': '复制文本块{n}',
22
+ 'block.code': '代码块 {n}',
23
+ 'block.text': '文本块 {n}',
24
24
  'detail.aria': '代码块详情',
25
25
  'slot.label': '粘贴代码块详情',
26
26
  'lines.one': '{count} 行',
@@ -38,8 +38,8 @@ export const zh = {
38
38
 
39
39
  /** English dictionary, key-identical to the Chinese source of truth. */
40
40
  export const en = {
41
- 'block.code': 'Code block #{n}',
42
- 'block.text': 'Text block #{n}',
41
+ 'block.code': 'Code #{n}',
42
+ 'block.text': 'Text #{n}',
43
43
  'detail.aria': 'Block details',
44
44
  'slot.label': 'Pasted block details',
45
45
  'lines.one': '{count} line',
@@ -58,6 +58,16 @@ export const en = {
58
58
  /** Shipped dictionaries keyed by locale id (mirrors DSH's built-in zh/en set). */
59
59
  export const dictionaries = { zh, en }
60
60
 
61
+ /**
62
+ * Pre-0.1.3 chip labels ("复制代码块N" / "Code block #N" …). No longer
63
+ * rendered, but still recognized by `parseBlockLabel` so chips inserted by an
64
+ * older bundle keep resolving to their block after an in-place page refresh.
65
+ */
66
+ export const legacyLabels = {
67
+ zh: { 'block.code': '复制代码块{n}', 'block.text': '复制文本块{n}' },
68
+ en: { 'block.code': 'Code block #{n}', 'block.text': 'Text block #{n}' },
69
+ }
70
+
61
71
  /**
62
72
  * Standalone translator used only when no DSH locale service is present
63
73
  * (defensive fallback outside the standard web composition). English is the
@@ -82,21 +92,21 @@ export function detectBrowserLocale() {
82
92
  }
83
93
  }
84
94
 
85
- /** Build a block chip label from a translator: 复制代码块2 / Code block #2. */
95
+ /** Build a block chip label from a translator: 代码块 2 / Code #2. */
86
96
  export function blockLabel(t, type, n) {
87
97
  return t(type === 'code' ? 'block.code' : 'block.text', { n })
88
98
  }
89
99
 
90
100
  /**
91
- * Recognize a rendered block label in ANY shipped locale and recover its
92
- * `{ type, n }` identity. This lets a chip click, an ✕ delete, and the
93
- * locale-switch retitling find the right block even when the chip was
94
- * inserted under a different language than the one currently active.
95
- * Returns null for anything that is not a block label.
101
+ * Recognize a rendered block label in ANY shipped locale (or a pre-0.1.3
102
+ * legacy locale) and recover its `{ type, n }` identity. This lets a chip
103
+ * click, an ✕ delete, and the locale-switch retitling find the right block
104
+ * even when the chip was inserted under a different language than the one
105
+ * currently active. Returns null for anything that is not a block label.
96
106
  */
97
107
  export function parseBlockLabel(text) {
98
108
  if (!text) return null
99
- for (const dict of [dictionaries.zh, dictionaries.en]) {
109
+ for (const dict of [dictionaries.zh, dictionaries.en, legacyLabels.zh, legacyLabels.en]) {
100
110
  for (const key of ['block.code', 'block.text']) {
101
111
  const pattern = new RegExp(
102
112
  '^' +