dsh-muv-table 0.1.0 → 0.2.1

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/lib/client.js +114 -2
  3. package/package.json +7 -24
package/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ ## v0.2.0 (2026-08-27)
4
+
5
+ ### ✨ 新功能
6
+ - **宏测试浮窗**:点击面板 header 的「📐 宏」按钮弹出
7
+ - 输入宏语法 → 展开测试 → 实时看结果
8
+ - 展开结果支持「📋 复制」和「⬆ 填入」(回填到输入框继续编辑)
9
+ - 🎲 快捷骰子栏:d4/d6/d8/d10/d12/d20/2d6/3d6/1d100 一键掷骰
10
+ - 📌 Pick 缓存列表:展示所有缓存 key→值,单个重抽或全部清除
11
+ - 📖 语法帮助折叠区
12
+
13
+ ### 🔧 改进
14
+ - Header 按钮精简:去掉重复的「🍺 酒馆」按钮(与 🔄 刷新功能重复),替换为「📐 宏」
15
+ - 依赖 muv-engine 升级到 `^0.2.0`
16
+
17
+ ---
18
+
19
+ ## v0.1.0 (2026-08-26)
20
+
21
+ - 初始版本:树形变量表格编辑器、酒馆侧边栏入口、从酒馆加载角色卡、MUV 块生成
package/lib/client.js CHANGED
@@ -28,11 +28,122 @@ window.__ModuleLoader__.load({
28
28
  bg: 'var(--dsw-alias-bg-base)', bg1: 'var(--dsw-alias-bg-layer-1)', bg2: 'var(--dsw-alias-bg-layer-2)', bg3: 'var(--dsw-alias-bg-layer-3)',
29
29
  border: 'var(--dsw-alias-border-l2)', borderL: 'var(--dsw-alias-border-l1)',
30
30
  text: 'var(--dsw-alias-label-primary)', sub: 'var(--dsw-alias-label-secondary)', dim: 'var(--dsw-alias-label-tertiary)',
31
- accent: 'var(--dsw-alias-label-accent)', gold: '#c5a065', danger: 'var(--dsw-alias-label-danger)',
31
+ accent: 'var(--dsw-alias-label-accent)', gold: 'var(--dsw-alias-label-accent,#c5a065)', danger: 'var(--dsw-alias-label-danger)',
32
32
  hover: 'var(--dsw-specific-sidebar-nav-item-hover)',
33
33
  font: 'var(--dsw-font-family)'
34
34
  }
35
35
 
36
+ // ============ MacroPanel ============
37
+ function MacroPanel({ onClose }) {
38
+ const [input, setInput] = React.useState('')
39
+ const [result, setResult] = React.useState('')
40
+ const [picks, setPicks] = React.useState([])
41
+ const [diceResult, setDiceResult] = React.useState('')
42
+
43
+ const refreshPicks = () => {
44
+ if (typeof window._tavernListPicks === 'function') {
45
+ setPicks(window._tavernListPicks())
46
+ }
47
+ }
48
+ React.useEffect(() => { refreshPicks() }, [])
49
+
50
+ const handleExpand = () => {
51
+ if (typeof window._tavernExpandMacros === 'function') {
52
+ setResult(window._tavernExpandMacros(input))
53
+ } else {
54
+ setResult('⚠ muv-engine 插件未加载')
55
+ }
56
+ refreshPicks()
57
+ }
58
+ const handleReroll = (key) => {
59
+ if (typeof window._tavernRerollPick === 'function') {
60
+ window._tavernRerollPick(key)
61
+ refreshPicks()
62
+ }
63
+ }
64
+ const handleClearAll = () => {
65
+ picks.forEach(p => { if (typeof window._tavernRerollPick === 'function') window._tavernRerollPick(p.key) })
66
+ refreshPicks()
67
+ }
68
+ const quickDice = (expr) => {
69
+ if (typeof window._tavernExpandMacros === 'function') {
70
+ setDiceResult(window._tavernExpandMacros('{[roll::'+expr+']}'))
71
+ }
72
+ }
73
+
74
+ const DICE = ['d4','d6','d8','d10','d12','d20','2d6','3d6','1d100']
75
+
76
+ return jsx.jsxs('div', { style:{position:'fixed',inset:0,zIndex:70,background:'rgba(0,0,0,0.5)',display:'flex',alignItems:'center',justifyContent:'center'}, onClick:onClose, children: [
77
+ jsx.jsxs('div', { onClick:e=>e.stopPropagation(), style:{width:'min(90vw,520px)',background:C.bg,display:'flex',flexDirection:'column',color:C.text,fontFamily:C.font,fontSize:13,borderRadius:12,border:'1px solid '+C.border,boxShadow:'0 20px 60px rgba(0,0,0,0.5)',overflow:'hidden'}, children: [
78
+ // Header
79
+ jsx.jsxs('div', { style:{display:'flex',alignItems:'center',gap:10,padding:'10px 16px',borderBottom:'1px solid '+C.border,flexShrink:0,background:C.bg1}, children: [
80
+ jsx.jsx('span', { style:{fontWeight:700,fontSize:15,flex:1}, children: '📐 宏测试' }),
81
+ jsx.jsx('button', { onClick:onClose, style:{padding:'5px 12px',borderRadius:6,border:'1px solid '+C.border,background:C.bg3,color:C.text,cursor:'pointer',fontSize:12,fontFamily:'inherit'}, children: '✕' })
82
+ ] }),
83
+ // Body
84
+ jsx.jsxs('div', { style:{padding:16,display:'flex',flexDirection:'column',gap:14,overflow:'auto'}, children: [
85
+ // Input
86
+ jsx.jsxs('div', { children: [
87
+ jsx.jsx('div', { style:{fontSize:11,color:C.dim,marginBottom:6}, children: '输入宏语法(支持 random / pick / roll)' }),
88
+ jsx.jsx('textarea', { value:input, onChange:e=>setInput(e.target.value), placeholder:'{[random::选项A::选项B::选项C]}\n{[pick::宝箱::灵石x50::破旧剑谱::神秘丹药]}\n{[roll::2d6+3]}', rows:4, style:{width:'100%',padding:10,borderRadius:8,border:'1px solid '+C.border,background:C.bg3,color:C.text,fontSize:13,fontFamily:'monospace',resize:'vertical',outline:'none',boxSizing:'border-box'} }),
89
+ jsx.jsx('button', { onClick:handleExpand, style:{marginTop:8,padding:'8px 20px',borderRadius:8,border:'none',background:'linear-gradient(135deg,#c5a065,#d4a76a)',color:'#1a1a1a',cursor:'pointer',fontSize:13,fontWeight:700,fontFamily:'inherit',width:'100%'}, children: '⚡ 展开测试' })
90
+ ] }),
91
+ // Result
92
+ result && jsx.jsxs('div', { children: [
93
+ jsx.jsxs('div', { style:{display:'flex',alignItems:'center',gap:8,marginBottom:4}, children: [
94
+ jsx.jsx('div', { style:{fontSize:11,color:C.dim,flex:1}, children: '展开结果' }),
95
+ jsx.jsx('button', { onClick:()=>navigator.clipboard.writeText(result), style:{padding:'2px 8px',borderRadius:4,border:'1px solid '+C.border,background:C.bg3,color:C.sub,cursor:'pointer',fontSize:10,fontFamily:'inherit'}, children: '📋 复制' }),
96
+ jsx.jsx('button', { onClick:()=>setInput(result), style:{padding:'2px 8px',borderRadius:4,border:'1px solid '+C.border,background:C.bg3,color:C.sub,cursor:'pointer',fontSize:10,fontFamily:'inherit'}, children: '⬆ 填入' })
97
+ ] }),
98
+ jsx.jsx('div', { style:{padding:10,borderRadius:8,border:'1px solid '+C.accent,background:'rgba(74,191,171,0.06)',color:C.text,fontSize:13,fontFamily:'monospace',whiteSpace:'pre-wrap',wordBreak:'break-all',minHeight:20}, children: result })
99
+ ] }),
100
+ // Dice quick
101
+ jsx.jsxs('div', { children: [
102
+ jsx.jsx('div', { style:{fontSize:11,color:C.dim,marginBottom:6}, children: '🎲 快捷骰子' }),
103
+ jsx.jsx('div', { style:{display:'flex',flexWrap:'wrap',gap:6}, children: DICE.map(d =>
104
+ jsx.jsx('button', { onClick:()=>quickDice(d), style:{padding:'4px 10px',borderRadius:6,border:'1px solid '+C.border,background:C.bg3,color:C.text,cursor:'pointer',fontSize:12,fontFamily:'monospace'}, children: d }, d)
105
+ ) }),
106
+ diceResult && jsx.jsx('div', { style:{marginTop:8,padding:'6px 12px',borderRadius:6,background:'rgba(197,160,101,0.1)',color:C.gold,fontSize:13,fontWeight:600}, children: '结果: '+diceResult })
107
+ ] }),
108
+ // Pick cache
109
+ jsx.jsxs('div', { children: [
110
+ jsx.jsxs('div', { style:{display:'flex',alignItems:'center',gap:8,marginBottom:6}, children: [
111
+ jsx.jsx('div', { style:{fontSize:11,color:C.dim,flex:1}, children: '📌 Pick 缓存 ('+picks.length+')' }),
112
+ picks.length>0 && jsx.jsx('button', { onClick:handleClearAll, style:{padding:'2px 8px',borderRadius:4,border:'1px solid '+C.danger,background:'transparent',color:C.danger,cursor:'pointer',fontSize:10,fontFamily:'inherit'}, children: '清除全部' })
113
+ ] }),
114
+ picks.length===0 && jsx.jsx('div', { style:{fontSize:11,color:C.dim,fontStyle:'italic'}, children: '暂无缓存(使用 {[pick::key::...]} 后自动出现)' }),
115
+ picks.map(p => jsx.jsxs('div', { key:p.key, style:{display:'flex',alignItems:'center',gap:8,padding:'4px 8px',borderRadius:6,background:C.bg3,marginBottom:4}, children: [
116
+ jsx.jsx('span', { style:{fontSize:11,color:C.gold,fontWeight:600,fontFamily:'monospace',flex:1}, children: p.key }),
117
+ jsx.jsx('span', { style:{fontSize:12,color:C.text}, children: '→ '+p.value }),
118
+ jsx.jsx('button', { onClick:()=>handleReroll(p.key), style:{padding:'2px 8px',borderRadius:4,border:'1px solid '+C.border,background:C.bg1,color:C.sub,cursor:'pointer',fontSize:10,fontFamily:'inherit'}, children: '重抽' })
119
+ ] }))
120
+ ] }),
121
+ // Syntax help
122
+ jsx.jsxs('details', { style:{fontSize:11}, children: [
123
+ jsx.jsx('summary', { style:{color:C.dim,cursor:'pointer',marginBottom:4}, children: '📖 语法帮助' }),
124
+ jsx.jsx('div', { style:{color:C.sub,lineHeight:1.8,padding:'4px 0'}, children: [
125
+ jsx.jsx('div', { children: '{[random::A::B::C]} → 每次随机选一个' }),
126
+ jsx.jsx('div', { children: '{[pick::key::A::B::C]} → 固定结果,缓存为 key' }),
127
+ jsx.jsx('div', { children: '{[roll::2d6]} → 掷 2 个 6 面骰' }),
128
+ jsx.jsx('div', { children: '{[roll::1d20+3]} → d20 + 3 调整值' }),
129
+ jsx.jsx('div', { style:{marginTop:4,color:C.dim}, children: '在聊天输入框里直接写宏,按 Enter 自动展开后发送给 AI。' })
130
+ ] })
131
+ ] })
132
+ ] })
133
+ ] })
134
+ ] })
135
+ }
136
+
137
+ let macroVc = null, macroVr = null
138
+ function showMacroPanel() {
139
+ if (macroVc) { macroVc.style.display = ''; return }
140
+ macroVc = document.createElement('div')
141
+ macroVc.setAttribute('data-dsh-macro-panel', '')
142
+ document.body.appendChild(macroVc)
143
+ macroVr = ReactDOM.createRoot(macroVc)
144
+ macroVr.render(jsx.jsx(MacroPanel, { onClose: () => { if (macroVc) macroVc.style.display = 'none' } }))
145
+ }
146
+
36
147
  // ============ MuvTableView ============
37
148
  function MuvTableView({ onClose }) {
38
149
  const initial = savedState && savedState.cardName
@@ -177,7 +288,7 @@ window.__ModuleLoader__.load({
177
288
  jsx.jsx('span', { style:{fontWeight:700,fontSize:15,flex:1}, children: state.cardName?'📊 '+state.cardName:'📊 MUV 变量表格' }),
178
289
  state.status==='loaded' && jsx.jsx('input', { type:'text', placeholder:'🔍 搜索变量...', value:state.search, onChange:e=>setState(s=>({...s,search:e.target.value})), style:{width:160,padding:'4px 10px',borderRadius:6,border:'1px solid '+C.border,background:C.bg3,color:C.text,fontSize:12,fontFamily:'inherit',outline:'none'} }),
179
290
  editCount>0 && jsx.jsx('span', { style:{fontSize:11,color:C.sub,background:'rgba(197,160,101,0.12)',padding:'2px 8px',borderRadius:10}, children: editCount+' 修改' }),
180
- state.status==='loaded' && jsx.jsx('button', { onClick:loadFromTavern, style:{padding:'5px 10px',borderRadius:6,border:'1px solid '+C.gold,background:'rgba(197,160,101,0.1)',color:C.gold,cursor:'pointer',fontSize:11,fontFamily:'inherit'}, children: '🍺 酒馆' }),
291
+ state.status==='loaded' && jsx.jsx('button', { onClick:()=>showMacroPanel(), style:{padding:'5px 10px',borderRadius:6,border:'1px solid '+C.accent,background:'rgba(74,191,171,0.1)',color:C.accent,cursor:'pointer',fontSize:11,fontFamily:'inherit'}, children: '📐 宏' }),
181
292
  state.status==='loaded' && jsx.jsx('button', { onClick:loadFromTavern, style:{padding:'5px 8px',borderRadius:6,border:'1px solid '+C.border,background:C.bg3,color:C.text,cursor:'pointer',fontSize:13,fontFamily:'inherit'}, children: '🔄' }),
182
293
  state.status==='loaded' && jsx.jsx('button', { onClick:toggleAll, style:{padding:'5px 10px',borderRadius:6,border:'1px solid '+C.border,background:C.bg3,color:C.text,cursor:'pointer',fontSize:11,fontFamily:'inherit'}, children: collapsed.size>0?'📖 展开全部':'📕 折叠全部' }),
183
294
  state.status==='loaded' && jsx.jsx('button', { onClick:handleGenerate, style:{padding:'7px 18px',borderRadius:8,border:'none',background:'linear-gradient(135deg,#c5a065,#d4a76a)',color:'#1a1a1a',cursor:'pointer',fontSize:13,fontWeight:700,fontFamily:'inherit',boxShadow:'0 2px 8px rgba(197,160,101,0.25)'}, children: '⚡ 生成 MUV 块' }),
@@ -301,6 +412,7 @@ window.__ModuleLoader__.load({
301
412
  document.removeEventListener('tavern-preset-changed', onPresetChanged)
302
413
  document.removeEventListener('tavern-session-changed', onSessionChanged)
303
414
  if (d) d()
415
+ if (macroVc) { macroVc.remove(); macroVc = null; macroVr = null }
304
416
  }
305
417
  }
306
418
  return module.exports
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-muv-table",
3
- "version": "0.1.0",
4
- "description": "MUV Variable Table Editor - tavern companion plugin for DSH: structured table editing for UpdateVariable blocks",
3
+ "version": "0.2.1",
4
+ "description": "MUV 变量表格编辑器 —— 树形变量面板、宏测试浮窗(random/pick/roll)、骰子快捷栏、pick 缓存管理",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -9,30 +9,13 @@
9
9
  "./client": "./lib/client.js",
10
10
  "./package.json": "./package.json"
11
11
  },
12
- "files": [
13
- "lib",
14
- "cordis.patch.yml"
15
- ],
16
- "keywords": [
17
- "dsh",
18
- "dsh-plugin",
19
- "deepseek-harness",
20
- "muv",
21
- "magvarupdate",
22
- "tavern",
23
- "variable-table"
24
- ],
12
+ "files": ["lib", "cordis.patch.yml", "CHANGELOG.md"],
13
+ "keywords": ["dsh", "dsh-plugin", "deepseek-harness", "muv", "magvarupdate", "tavern", "variable-table"],
25
14
  "license": "PolyForm-Noncommercial-Copyleft-1.0.0",
26
15
  "dsh": {
27
- "bundle": {
28
- "patch": "./cordis.patch.yml"
29
- },
30
- "client": {
31
- "platform": "web"
32
- }
16
+ "bundle": { "patch": "./cordis.patch.yml" },
17
+ "client": { "platform": "web" }
33
18
  },
34
19
  "repository": {"type": "git", "url": "git+https://github.com/chen731215-dev/dsh-muv-table.git"},
35
- "engines": {
36
- "node": ">=20"
37
- }
20
+ "engines": { "node": ">=20" }
38
21
  }