@vibedev-si/dsh-media-viewer 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.
Files changed (3) hide show
  1. package/README.md +3 -3
  2. package/client.js +9 -331
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -16,9 +16,9 @@
16
16
 
17
17
  画廊在右侧栏的 **+ 菜单**里叫「媒体画廊」;每个播放器工具栏里的「画廊」按钮会直接打开它所在的文件夹。
18
18
 
19
- ## 本版新增(0.1.2)
19
+ ## 本版变更(0.1.3)
20
20
 
21
- 新增「组件」入口:在预览工具栏里可直接打开 **VibeDev 插件中心**,了解或补齐影视工作台与 VibeDev 账号插件(打不开插件中心时会给出可复制的包名);已安装或应用内置的组件不会重复推荐。
21
+ 撤回了 0.1.2 加进预览工具栏和画廊底部的「组件 / 插件中心」入口,它影响了侧栏观感,等重新设计后再考虑;预览、画廊与安全说明不受影响。
22
22
 
23
23
  ## 安装
24
24
 
@@ -76,7 +76,7 @@ client 是无需构建的纯 JS(`client.js`),host 是 `index.js`,没有
76
76
  - **Audio** — mp3 / wav / m4a / flac…, live spectrum, playback speed, loop.
77
77
  - **HTML** — scripts allowed by default; relative CSS / JS / images / video / `fetch()` all load; preview ⇄ source, phone / tablet / desktop widths, script toggle. Runs in an opaque-origin sandboxed iframe, so a previewed page cannot reach the GUI.
78
78
  - **Media gallery** — thumbnail grid for a folder with type filters, search, sort, optional recursion, and a lightbox with ← / → navigation.
79
- - **Related components (0.1.2)** — a 「组件」 entry in the preview toolbar opens the **VibeDev plugin centre** from the sidebar to learn about or add the film workbench and the VibeDev account plugin (and falls back to a copyable package name); components already installed or shipped by the app are never recommended again.
79
+ - **Withdrawn in 0.1.3** — the 「组件」 / plugin-centre entry 0.1.2 added to the preview toolbar and the gallery footer is gone, because it changed how the sidebar looked; it will be reconsidered after a redesign, and previewing, the gallery and the security notes are unaffected.
80
80
 
81
81
  Why it exists: the built-in `/sidebar/file` and `/sidebar/html` routes cap files at 20 MB, read them fully into memory, have no Range support, and their fence rejects the `cross-site` sub-resource requests a sandboxed iframe makes. This plugin ships its own `/mp/*` routes instead. Install it by package name from your DSH plugin manager, or `dsh plugin --profile <name> add @vibedev-si/dsh-media-viewer`, then reload the page.
82
82
 
package/client.js CHANGED
@@ -158,12 +158,6 @@ window.__ModuleLoader__.load({
158
158
  h("rect", { key: "d", x: 9, y: 9, width: 5, height: 5, rx: 1, stroke: "currentColor", strokeWidth: 1.5 }),
159
159
  ]);
160
160
  }
161
- function IconTools(size) {
162
- return svg(size, [
163
- h("rect", { key: "a", x: 2, y: 2, width: 12, height: 12, rx: 3, stroke: "currentColor", strokeWidth: 1.5 }),
164
- pathEl("M8 5.4v5.2M5.4 8h5.2", { key: "b" }),
165
- ]);
166
- }
167
161
  function kindIcon(kind, size) {
168
162
  return kind === "video" ? IconVideo(size) : kind === "audio" ? IconAudio(size) : kind === "html" ? IconHtml(size) : IconImage(size);
169
163
  }
@@ -186,7 +180,7 @@ window.__ModuleLoader__.load({
186
180
  } catch (e) { console.error("[dsh-media-viewer] open gallery failed", e); }
187
181
  }
188
182
 
189
- function CommonActions(props, abs, url, toolsOpen, onTools) {
183
+ function CommonActions(props, abs, url) {
190
184
  var out = [
191
185
  h("a", { key: "new", href: url, target: "_blank", rel: "noopener", style: btn(), title: "在新窗口打开" }, "新窗口"),
192
186
  h("a", { key: "dl", href: fileUrl(props.scope, abs, "download=1"), download: baseName(abs), style: btn(), title: "下载原文件" }, "下载"),
@@ -194,9 +188,6 @@ window.__ModuleLoader__.load({
194
188
  if (!props.hideGallery) {
195
189
  out.push(h(Btn, { key: "gal", title: "浏览所在文件夹的全部媒体", onClick: function () { openGallery(props, abs); } }, [IconGrid(12), "画廊"]));
196
190
  }
197
- if (typeof onTools === "function") {
198
- out.push(h(Btn, { key: "tools", active: toolsOpen === true, title: "相关组件与插件中心", onClick: onTools }, [IconTools(12), "组件"]));
199
- }
200
191
  return out;
201
192
  }
202
193
 
@@ -209,305 +200,9 @@ window.__ModuleLoader__.load({
209
200
  }
210
201
 
211
202
  function Shell(p) {
212
- var kids = p.children ? (Array.isArray(p.children) ? p.children.slice() : [p.children]) : [];
213
- if (p.tools) kids.push(p.tools);
214
203
  return h("div", {
215
204
  style: { display: "flex", flexDirection: "column", gap: "8px", padding: "10px", minWidth: 0, minHeight: 0, height: "100%", boxSizing: "border-box" },
216
- }, kids);
217
- }
218
-
219
- // ── companion components (the plugin centre is the way to the rest) ─────
220
- //
221
- // What the Host actually has comes from its plugin inventory — a bundle the profile
222
- // installed, or one the application ships itself. Every service below is read
223
- // optionally and strictly, so a Host without a plugin manager, a panel layout, or the
224
- // plugin navigation contract keeps this viewer working and simply shows the manual
225
- // spec. Nothing here installs anything: the centre and the Plugins page own every
226
- // install, approval and progress step, and nothing is read before a surface is opened.
227
-
228
- /** The VibeDev components by package name; the centre is the way to all of them. */
229
- var SUITE = { account: "@vibedev-si/dsh-vibedev", center: "@vibedev-si/dsh-ecosystem", film: "dsh-film" };
230
- /** The main panel the VibeDev plugin centre registers its page under. */
231
- var CENTER_PANEL = "vibedev-center";
232
- /** The package a person can add on the Plugins page when nothing can open the centre. */
233
- var CENTER_SPEC = SUITE.center;
234
- /**
235
- * The components this viewer's own work leans on, in the order the card lists them.
236
- * A bundle already installed or shipped by the app is never named (see `bundlePresent`),
237
- * and the viewer never recommends itself.
238
- */
239
- var COMPANIONS = [
240
- { package: SUITE.account, line: "VibeDev 账号:用余额生成图片、视频和音频,模型请求走 VibeDev 网关。" },
241
- { package: SUITE.film, line: "影视工作台:剧本、分镜画布和导演台,把这个文件夹里的媒体排成片子。" },
242
- ];
243
- /** The card's own copy, in the one language this bundle's UI uses. */
244
- var SUITE_COPY = {
245
- missingTitle: "相关组件",
246
- missingIntro: "这些组件和右侧栏预览配合使用,装好后出现在它们各自的页面里。",
247
- toolsTitle: "插件中心",
248
- toolsIntro: "插件中心里可以浏览其余组件。",
249
- keep: "这里只做提示:不会自动安装,也不会改动已装的东西;安装与授权都在插件中心里完成。",
250
- open: "打开插件中心",
251
- manual: "打不开插件中心时,可在「插件」页按包名安装:",
252
- copy: "复制包名",
253
- copied: "已复制",
254
- tools: "组件",
255
- };
256
-
257
- /** A value read as a record, without trusting its declared type. */
258
- function asRecord(v) { return typeof v === "object" && v !== null ? v : undefined; }
259
-
260
- /** One property of a service, read without letting a hostile getter throw into the viewer. */
261
- function safeGet(target, name) {
262
- var record = asRecord(target);
263
- if (record === undefined) return undefined;
264
- try { return record[name]; } catch (e) { return undefined; }
265
- }
266
-
267
- /** One optional service, read strictly: absent (never throwing) on a Host that does not have it. */
268
- function serviceOf(ctx, name) {
269
- if (!ctx || typeof ctx.get !== "function") return undefined;
270
- try { return ctx.get(name); } catch (e) { return undefined; }
271
- }
272
-
273
- /** The optional services the card uses, from the strict store first and the property proxy second. */
274
- function suiteServices(ctx) {
275
- var remote = asRecord(serviceOf(ctx, "remote") || safeGet(ctx, "remote"));
276
- return {
277
- manager: asRecord(serviceOf(ctx, "remote.pluginManager") || safeGet(remote, "pluginManager")),
278
- slots: asRecord(serviceOf(ctx, "slots") || safeGet(ctx, "slots")),
279
- layout: asRecord(serviceOf(ctx, "layout") || safeGet(ctx, "layout")),
280
- navigation: asRecord(serviceOf(ctx, "pluginNavigation") || safeGet(ctx, "pluginNavigation")),
281
- remote: remote,
282
- };
283
- }
284
-
285
- /** Whether the Host already has a bundle: the profile installed it, or the application provides it itself. */
286
- function bundlePresent(bundle) {
287
- return bundle.installed === true || (bundle.removable === false && !bundle.source);
288
- }
289
-
290
- /**
291
- * The present package names of one inventory answer, or undefined when the answer is not a
292
- * readable list. An answer this cannot read is never read as "nothing is present": a refusal
293
- * envelope, another shape, or a missing value means the caller knows nothing, not that every
294
- * component is missing.
295
- */
296
- function presentFrom(answer) {
297
- var record = asRecord(answer);
298
- if (record === undefined || record.ok === false) return undefined;
299
- if (!Array.isArray(record.value)) return undefined;
300
- var names = [];
301
- for (var i = 0; i < record.value.length; i++) {
302
- var bundle = asRecord(record.value[i]);
303
- if (!bundle || !bundlePresent(bundle)) continue;
304
- if (typeof bundle.name === "string" && bundle.name !== "" && names.indexOf(bundle.name) < 0) names.push(bundle.name);
305
- }
306
- return names;
307
- }
308
-
309
- /**
310
- * Read the Host's plugin inventory once. A manager that cannot answer — absent, throwing,
311
- * rejecting, or answering an envelope that is not a readable list — is not an inventory of
312
- * nothing: `ok: false` makes the card offer the centre and claim no component is missing.
313
- */
314
- function readPresence(ctx) {
315
- var manager = suiteServices(ctx).manager;
316
- var list = safeGet(manager, "listBundles");
317
- if (typeof list !== "function") return Promise.resolve({ ok: false, present: [] });
318
- try {
319
- return Promise.resolve(list.call(manager)).then(
320
- function (answer) {
321
- var present = presentFrom(answer);
322
- return present === undefined ? { ok: false, present: [] } : { ok: true, present: present };
323
- },
324
- function () { return { ok: false, present: [] }; });
325
- } catch (e) {
326
- return Promise.resolve({ ok: false, present: [] });
327
- }
328
- }
329
-
330
- /** Hear about installs, removals and activations; a Host without the event bus returns a no-op. */
331
- function observePresence(ctx, listener) {
332
- var remote = suiteServices(ctx).remote;
333
- var on = safeGet(remote, "$on");
334
- if (typeof on !== "function") return function () {};
335
- try {
336
- var off = on.call(remote, "plugin-manager/changed", listener);
337
- return typeof off === "function" ? function () { off(); } : function () {};
338
- } catch (e) {
339
- return function () {};
340
- }
341
- }
342
-
343
- /**
344
- * The centre's main panel, where this Host registered one. A slots entry keeps its
345
- * identity in `options` (`options.key` is the panel id the layout selects); older
346
- * shapes kept `key`/`id` at the top level, which is still read as a fallback.
347
- */
348
- function centerPanel(ctx) {
349
- var slots = suiteServices(ctx).slots;
350
- var entries = safeGet(slots, "entries");
351
- if (typeof entries !== "function") return undefined;
352
- var listed;
353
- try { listed = entries.call(slots, "main"); } catch (e) { return undefined; }
354
- if (!Array.isArray(listed)) return undefined;
355
- for (var i = 0; i < listed.length; i++) {
356
- var record = asRecord(listed[i]);
357
- var options = asRecord(safeGet(record, "options"));
358
- var key = options ? (safeGet(options, "key") !== undefined ? safeGet(options, "key") : safeGet(options, "id"))
359
- : (record ? (safeGet(record, "key") !== undefined ? safeGet(record, "key") : safeGet(record, "id")) : undefined);
360
- if (key === CENTER_PANEL) return CENTER_PANEL;
361
- }
362
- return undefined;
363
- }
364
-
365
- /**
366
- * Send the person to the centre, or to the Host's own way of installing it. A panel that
367
- * is gone, a layout that refuses, and a missing navigation contract each fall through to
368
- * the next, and the last answer is the spec a person can paste into the Plugins page.
369
- */
370
- function openCenter(ctx) {
371
- var services = suiteServices(ctx);
372
- var panel = centerPanel(ctx);
373
- var selectPanel = safeGet(services.layout, "selectPanel");
374
- if (panel !== undefined && typeof selectPanel === "function") {
375
- try { selectPanel.call(services.layout, panel); return { kind: "center" }; } catch (e) { /* the panel is gone */ }
376
- }
377
- var navigation = services.navigation;
378
- var openBundle = safeGet(navigation, "openBundle");
379
- if (typeof openBundle === "function") {
380
- try { openBundle.call(navigation, SUITE.center); return { kind: "plugins" }; } catch (e) { /* no Plugins panel here */ }
381
- }
382
- var openInstall = safeGet(navigation, "openInstall");
383
- if (typeof openInstall === "function") {
384
- try { openInstall.call(navigation, { spec: CENTER_SPEC }); return { kind: "plugins" }; } catch (e) { /* nothing could open */ }
385
- }
386
- return { kind: "manual", spec: CENTER_SPEC };
387
- }
388
-
389
- /** Which of `wanted` this Host does not have yet, in the order the surface lists them. */
390
- function missingFrom(present, wanted) {
391
- return wanted.filter(function (want) { return present.indexOf(want.package) < 0; });
392
- }
393
-
394
- /** What the card says: the absent components, or the one way to the rest. An unreadable inventory claims nothing. */
395
- function suiteHint(read, wanted) {
396
- if (!read.ok) return { kind: "tools", missing: [] };
397
- var missing = missingFrom(read.present, wanted);
398
- if (missing.length === 0) return { kind: "tools", missing: [] };
399
- return {
400
- kind: "missing",
401
- missing: missing.map(function (want) { return { package: want.package, line: want.line }; }),
402
- };
403
- }
404
-
405
- /** Write text through the browser's clipboard, where the page has one. */
406
- function writeClipboard(text) {
407
- var clipboard = typeof navigator !== "undefined" && navigator ? safeGet(navigator, "clipboard") : undefined;
408
- var write = safeGet(clipboard, "writeText");
409
- if (typeof write !== "function") return Promise.resolve(false);
410
- try {
411
- return Promise.resolve(write.call(clipboard, text)).then(function () { return true; }, function () { return false; });
412
- } catch (e) {
413
- return Promise.resolve(false);
414
- }
415
- }
416
-
417
- /** One read of what this Host has, shared by every card this bundle renders. */
418
- function createSuiteStore(ctx, wanted) {
419
- var snapshot = { read: false, found: { ok: false, present: [] }, hint: { kind: "tools", missing: [] } };
420
- var listeners = [];
421
- function publish(next) {
422
- snapshot = next;
423
- var copy = listeners.slice();
424
- for (var i = 0; i < copy.length; i++) copy[i]();
425
- }
426
- function read() {
427
- return readPresence(ctx).then(function (found) {
428
- publish({ read: true, found: found, hint: suiteHint(found, wanted) });
429
- });
430
- }
431
- return {
432
- subscribe: function (listener) {
433
- listeners.push(listener);
434
- return function () {
435
- var at = listeners.indexOf(listener);
436
- if (at >= 0) listeners.splice(at, 1);
437
- };
438
- },
439
- getSnapshot: function () { return snapshot; },
440
- open: function () { return openCenter(ctx); },
441
- copy: writeClipboard,
442
- /** Start the first read and every later refresh; the returned disposer releases both. */
443
- start: function () {
444
- void read();
445
- return observePresence(ctx, function () { void read(); });
446
- },
447
- };
448
- }
449
-
450
- /**
451
- * The companion components this Host lacks, and the one quiet way into the plugin centre.
452
- * It renders nothing until its own read settled, installs nothing, and opens nothing by
453
- * itself: every line here is a statement about the Host, and the button is the only action.
454
- */
455
- function SuiteCard(props) {
456
- var store = useMemo(function () {
457
- return props.store || createSuiteStore(props.ctx, COMPANIONS);
458
- }, [props.ctx, props.store]);
459
- var st = useState(store.getSnapshot()), snap = st[0], setSnap = st[1];
460
- var mn = useState(null), manual = mn[0], setManual = mn[1];
461
- var cp = useState(false), copied = cp[0], setCopied = cp[1];
462
-
463
- useEffect(function () {
464
- // Subscribe before the first read: a change published during it must still reach this card.
465
- var off = store.subscribe(function () { setSnap(store.getSnapshot()); });
466
- var stop = store.start();
467
- return function () { off(); stop(); };
468
- }, [store]);
469
-
470
- if (!snap.read) return null;
471
- var missing = snap.hint.kind === "missing";
472
- var kids = [
473
- h("div", { key: "t", style: { fontSize: "12px", fontWeight: 600 } }, missing ? SUITE_COPY.missingTitle : SUITE_COPY.toolsTitle),
474
- h("div", { key: "i", style: { fontSize: "11px", color: C.muted, lineHeight: 1.6 } }, missing ? SUITE_COPY.missingIntro : SUITE_COPY.toolsIntro),
475
- ];
476
- for (var i = 0; i < snap.hint.missing.length; i++) {
477
- var line = snap.hint.missing[i];
478
- kids.push(h("div", { key: "m:" + line.package, style: { fontSize: "12px", lineHeight: 1.6 } }, line.line));
479
- }
480
- kids.push(h("div", { key: "k", style: { fontSize: "11px", color: C.muted, lineHeight: 1.6 } }, SUITE_COPY.keep));
481
- kids.push(h("div", { key: "a", style: { display: "flex", flexWrap: "wrap", gap: "6px", paddingTop: "2px" } }, [
482
- h(Btn, {
483
- key: "open", active: missing, title: "打开插件中心",
484
- onClick: function () {
485
- var target = store.open();
486
- setCopied(false);
487
- setManual(target.kind === "manual" ? { spec: target.spec } : null);
488
- },
489
- }, SUITE_COPY.open),
490
- ]));
491
- if (manual) {
492
- kids.push(h("div", { key: "mn", style: { fontSize: "11px", color: C.muted, lineHeight: 1.6 } }, SUITE_COPY.manual));
493
- kids.push(h("code", {
494
- key: "spec",
495
- style: { fontSize: "12px", padding: "2px 6px", borderRadius: "6px", background: C.softer, border: "1px solid " + C.line, userSelect: "text", alignSelf: "flex-start" },
496
- }, manual.spec));
497
- kids.push(h("div", { key: "cp", style: { display: "flex", flexWrap: "wrap", gap: "6px" } }, [
498
- h(Btn, {
499
- key: "copy", title: "复制包名",
500
- onClick: function () { void store.copy(manual.spec).then(function (written) { setCopied(written); }); },
501
- }, copied ? SUITE_COPY.copied : SUITE_COPY.copy),
502
- ]));
503
- }
504
- return h("div", {
505
- "data-mp-companions": "1",
506
- style: {
507
- display: "flex", flexDirection: "column", gap: "5px", flex: "none", boxSizing: "border-box",
508
- padding: "9px 10px", borderRadius: "8px", border: "1px dashed " + C.line, background: C.softer, color: C.fg,
509
- },
510
- }, kids);
205
+ }, p.children);
511
206
  }
512
207
 
513
208
  // ── video ───────────────────────────────────────────────────────────────
@@ -521,14 +216,13 @@ window.__ModuleLoader__.load({
521
216
  var er = useState(null), err = er[0], setErr = er[1];
522
217
  var du = useState(null), dur = du[0], setDur = du[1];
523
218
  var dims = useState(null), dim = dims[0], setDim = dims[1];
524
- var tl = useState(false), tools = tl[0], setTools = tl[1];
525
219
 
526
220
  useEffect(function () { setErr(null); setDur(null); setDim(null); }, [url]);
527
221
  useEffect(function () { if (vref.current) vref.current.playbackRate = rate; }, [rate, url]);
528
222
 
529
223
  var info = [dur != null ? fmtDur(dur) : null, dim ? dim : null, extOf(abs).toUpperCase()].filter(Boolean).join(" · ");
530
224
 
531
- return h(Shell, { key: "root", tools: tools ? h(SuiteCard, { ctx: props.ctx }) : null }, [
225
+ return h(Shell, null, [
532
226
  h("div", { key: "stage", style: { flex: "1 1 auto", minHeight: 0, display: "flex", background: "#000", borderRadius: "8px", overflow: "hidden" } },
533
227
  err
534
228
  ? h("div", { style: { margin: "auto", padding: "20px", textAlign: "center", color: "#ddd", fontSize: "13px", lineHeight: 1.7 } }, [
@@ -551,7 +245,7 @@ window.__ModuleLoader__.load({
551
245
  h(Bar, { key: "bar", title: baseName(abs) + (info ? " · " + info : ""), path: abs }, [
552
246
  h(RatePicker, { key: "rate", rate: rate, set: setRate }),
553
247
  h(Btn, { key: "loop", active: loop, title: "循环播放", onClick: function () { setLoop(!loop); } }, "循环"),
554
- CommonActions(props, abs, url, tools, function () { setTools(!tools); }),
248
+ CommonActions(props, abs, url),
555
249
  ]),
556
250
  ]);
557
251
  }
@@ -567,7 +261,6 @@ window.__ModuleLoader__.load({
567
261
  var lp = useState(false), loop = lp[0], setLoop = lp[1];
568
262
  var er = useState(null), err = er[0], setErr = er[1];
569
263
  var du = useState(null), dur = du[0], setDur = du[1];
570
- var tl = useState(false), tools = tl[0], setTools = tl[1];
571
264
 
572
265
  useEffect(function () { setErr(null); setDur(null); }, [url]);
573
266
  useEffect(function () { if (aref.current) aref.current.playbackRate = rate; }, [rate, url]);
@@ -618,7 +311,7 @@ window.__ModuleLoader__.load({
618
311
  };
619
312
  }, [url]);
620
313
 
621
- return h(Shell, { key: "root", tools: tools ? h(SuiteCard, { ctx: props.ctx }) : null }, [
314
+ return h(Shell, null, [
622
315
  h("div", {
623
316
  key: "stage",
624
317
  style: {
@@ -640,7 +333,7 @@ window.__ModuleLoader__.load({
640
333
  h(Bar, { key: "bar", title: baseName(abs) + " · " + [dur != null ? fmtDur(dur) : null, extOf(abs).toUpperCase()].filter(Boolean).join(" · "), path: abs }, [
641
334
  h(RatePicker, { key: "rate", rate: rate, set: setRate }),
642
335
  h(Btn, { key: "loop", active: loop, title: "循环播放", onClick: function () { setLoop(!loop); } }, "循环"),
643
- CommonActions(props, abs, url, tools, function () { setTools(!tools); }),
336
+ CommonActions(props, abs, url),
644
337
  ]),
645
338
  ]);
646
339
  }
@@ -662,7 +355,6 @@ window.__ModuleLoader__.load({
662
355
  var vp = useState("fit"), view = vp[0], setView = vp[1];
663
356
  var rk = useState(0), reloadKey = rk[0], setReloadKey = rk[1];
664
357
  var sr = useState({ state: "idle", text: "" }), source = sr[0], setSource = sr[1];
665
- var tl = useState(false), tools = tl[0], setTools = tl[1];
666
358
 
667
359
  var frameRef = useRef(null);
668
360
 
@@ -712,7 +404,7 @@ window.__ModuleLoader__.load({
712
404
  }));
713
405
  }
714
406
 
715
- return h(Shell, { key: "root", tools: tools ? h(SuiteCard, { ctx: props.ctx }) : null }, [
407
+ return h(Shell, null, [
716
408
  stage,
717
409
  h(Bar, { key: "bar", title: baseName(abs), path: abs }, [
718
410
  h(Btn, { key: "m1", active: mode === "render", title: "渲染预览", onClick: function () { setMode("render"); } }, "预览"),
@@ -722,7 +414,7 @@ window.__ModuleLoader__.load({
722
414
  }) : null,
723
415
  h(Btn, { key: "js", active: scripts, title: scripts ? "脚本已允许,点击关闭(页面将重新加载)" : "脚本已禁用,点击允许", onClick: function () { setScripts(!scripts); } }, scripts ? "脚本 开" : "脚本 关"),
724
416
  h(Btn, { key: "rl", title: "重新加载", onClick: function () { setReloadKey(reloadKey + 1); } }, "刷新"),
725
- CommonActions(props, abs, url, tools, function () { setTools(!tools); }),
417
+ CommonActions(props, abs, url),
726
418
  ]),
727
419
  ]);
728
420
  }
@@ -942,8 +634,6 @@ window.__ModuleLoader__.load({
942
634
  return h("div", { style: { position: "relative", height: "100%", display: "flex", flexDirection: "column", overflow: "hidden", minWidth: 0 } }, [
943
635
  header,
944
636
  body,
945
- // The card sits at the foot of the gallery: a statement about the Host, never a launch ad.
946
- h("div", { key: "tools", style: { flex: "none", padding: "0 10px 10px" } }, h(SuiteCard, { ctx: props.ctx })),
947
637
  sel >= 0 && items[sel]
948
638
  ? h(Lightbox, {
949
639
  key: "lb", ctx: props.ctx, store: props.store, scope: scope, item: items[sel], index: sel, total: items.length,
@@ -991,19 +681,7 @@ window.__ModuleLoader__.load({
991
681
  });
992
682
  }
993
683
 
994
- // The loader reads `inject` and `apply`; `__suite` is the companion-components core, kept
995
- // exported so test/suite.test.mjs can drive it and the card through a fake loader and React.
996
- module.exports = {
997
- inject: inject,
998
- apply: apply,
999
- __suite: {
1000
- SUITE: SUITE, CENTER_PANEL: CENTER_PANEL, CENTER_SPEC: CENTER_SPEC, COMPANIONS: COMPANIONS,
1001
- suiteServices: suiteServices, bundlePresent: bundlePresent, presentFrom: presentFrom,
1002
- readPresence: readPresence, observePresence: observePresence, centerPanel: centerPanel,
1003
- openCenter: openCenter, missingFrom: missingFrom, suiteHint: suiteHint,
1004
- createSuiteStore: createSuiteStore, SuiteCard: SuiteCard,
1005
- },
1006
- };
684
+ module.exports = { inject: inject, apply: apply };
1007
685
  return module.exports;
1008
686
  },
1009
687
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibedev-si/dsh-media-viewer",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "右侧栏媒体预览:直接预览视频、音频和 HTML(大文件可拖进度条,HTML 默认允许脚本),并提供文件夹媒体画廊,需配合 dsh-better-sidebar · Inline video, audio and HTML preview plus a folder media gallery in the dsh-better-sidebar right column — range-streamed large files, sandboxed HTML with working relative assets",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -53,7 +53,7 @@
53
53
  "registry": "https://registry.npmjs.org/"
54
54
  },
55
55
  "scripts": {
56
- "test": "node test/route.test.mjs && node test/tokens.test.mjs && node test/suite.test.mjs"
56
+ "test": "node test/route.test.mjs && node test/tokens.test.mjs"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "dsh-better-sidebar": ">=0.24.0"