claude-code-marketplace 0.4.0 → 0.4.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.
- package/package.json +1 -1
- package/public/app.js +67 -15
- package/public/index.html +2 -1
- package/public/style.css +15 -0
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -48,6 +48,8 @@ ICONS.readme = SVG(
|
|
|
48
48
|
ICONS.settings = ICONS.gear;
|
|
49
49
|
ICONS.openEditor =
|
|
50
50
|
'<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M17.583 2.207a1.1 1.1 0 0 1 1.541.033l2.636 2.636a1.1 1.1 0 0 1 .033 1.541L10.68 17.53a1.1 1.1 0 0 1-.345.247l-4.56 1.903a.55.55 0 0 1-.725-.725l1.903-4.56a1.1 1.1 0 0 1 .247-.345zm.902 1.87-8.794 8.793-.946 2.268 2.268-.946 8.794-8.793z"/></svg>';
|
|
51
|
+
ICONS.copyPath =
|
|
52
|
+
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
|
|
51
53
|
const COMP_HAS_DIR = new Set(['skills', 'commands', 'agents']);
|
|
52
54
|
const COMP_LABELS = {
|
|
53
55
|
skills: 'Skills',
|
|
@@ -72,6 +74,7 @@ function updateArrow(p) {
|
|
|
72
74
|
// --- Init ---
|
|
73
75
|
document.addEventListener('DOMContentLoaded', () => {
|
|
74
76
|
document.getElementById('contentOpenEditor').innerHTML = ICONS.openEditor;
|
|
77
|
+
document.getElementById('contentCopyPath').innerHTML = ICONS.copyPath;
|
|
75
78
|
restoreAppState();
|
|
76
79
|
loadProject();
|
|
77
80
|
loadData();
|
|
@@ -447,7 +450,7 @@ async function showDetail(pluginId) {
|
|
|
447
450
|
<div class="detail-header">
|
|
448
451
|
<h3>${headerIcon} ${esc(plugin.name)} ${plugin.version ? `<span class="version">v${esc(plugin.version)}</span>` : ''}</h3>
|
|
449
452
|
<div class="detail-header-actions">
|
|
450
|
-
${plugin._pluginDir ? `<button class="modal-action-btn" title="Open in VS Code" onclick="openFolderInEditor({pluginId:'${esc(plugin.fullId)}'})">${ICONS.openEditor}</button>` : ''}
|
|
453
|
+
${plugin._pluginDir ? `<button class="modal-action-btn" title="${esc(plugin._pluginDir)}" onclick="copyPluginPath('${escJs(plugin._pluginDir)}', event)">${ICONS.copyPath}</button><button class="modal-action-btn" title="Open in VS Code" onclick="openFolderInEditor({pluginId:'${esc(plugin.fullId)}',event})">${ICONS.openEditor}</button>` : ''}
|
|
451
454
|
<button class="detail-close" onclick="closeDetail()">\u2715</button>
|
|
452
455
|
</div>
|
|
453
456
|
</div>
|
|
@@ -576,6 +579,7 @@ const EXT_TO_LANG = {
|
|
|
576
579
|
const PREFERRED_FILE = 'SKILL.MD';
|
|
577
580
|
let _contentCodeEl = null;
|
|
578
581
|
let _contentPluginId = null;
|
|
582
|
+
let _contentPluginDir = null;
|
|
579
583
|
|
|
580
584
|
function highlightSource(text, fileName) {
|
|
581
585
|
const ext = (fileName || '').split('.').pop().toLowerCase();
|
|
@@ -603,31 +607,72 @@ function getContentCodeEl() {
|
|
|
603
607
|
return _contentCodeEl;
|
|
604
608
|
}
|
|
605
609
|
|
|
606
|
-
async function
|
|
607
|
-
if (!_contentPluginId) return;
|
|
608
|
-
const relativePath = document.getElementById('contentViewerPath').textContent || '';
|
|
610
|
+
async function postAndFlash(endpoint, data, btn) {
|
|
609
611
|
try {
|
|
610
|
-
await fetch(
|
|
612
|
+
await fetch(endpoint, {
|
|
611
613
|
method: 'POST',
|
|
612
614
|
headers: { 'Content-Type': 'application/json' },
|
|
613
|
-
body: JSON.stringify(
|
|
615
|
+
body: JSON.stringify(data),
|
|
614
616
|
});
|
|
617
|
+
if (btn) flashButton(btn);
|
|
615
618
|
} catch {}
|
|
616
619
|
}
|
|
617
620
|
|
|
618
|
-
async function
|
|
619
|
-
if (!
|
|
621
|
+
async function openInEditor(event) {
|
|
622
|
+
if (!_contentPluginId) return;
|
|
623
|
+
const relativePath = document.getElementById('contentViewerPath').textContent || '';
|
|
624
|
+
await postAndFlash('/api/open-in-editor', { pluginId: _contentPluginId, relativePath }, event?.currentTarget);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const CHECKMARK_SVG =
|
|
628
|
+
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>';
|
|
629
|
+
|
|
630
|
+
function flashButton(btn) {
|
|
631
|
+
if (btn._flashTimeout) clearTimeout(btn._flashTimeout);
|
|
632
|
+
if (!btn._flashOrig) btn._flashOrig = btn.innerHTML;
|
|
633
|
+
btn.innerHTML = CHECKMARK_SVG;
|
|
634
|
+
btn.classList.add('copy-success');
|
|
635
|
+
btn._flashTimeout = setTimeout(() => {
|
|
636
|
+
btn.innerHTML = btn._flashOrig;
|
|
637
|
+
btn.classList.remove('copy-success');
|
|
638
|
+
btn._flashOrig = null;
|
|
639
|
+
btn._flashTimeout = null;
|
|
640
|
+
}, 1000);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
async function copyToClipboard(text, btn) {
|
|
620
644
|
try {
|
|
621
|
-
await
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
645
|
+
await navigator.clipboard.writeText(text);
|
|
646
|
+
} catch {
|
|
647
|
+
const ta = document.createElement('textarea');
|
|
648
|
+
ta.value = text;
|
|
649
|
+
document.body.appendChild(ta);
|
|
650
|
+
ta.select();
|
|
651
|
+
document.execCommand('copy');
|
|
652
|
+
document.body.removeChild(ta);
|
|
653
|
+
}
|
|
654
|
+
if (btn) flashButton(btn);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
async function copyContentPath(event) {
|
|
658
|
+
if (!_contentPluginDir) return;
|
|
659
|
+
const relativePath = document.getElementById('contentViewerPath').textContent || '';
|
|
660
|
+
const full = relativePath ? `${_contentPluginDir}/${relativePath}` : _contentPluginDir;
|
|
661
|
+
await copyToClipboard(full, event?.currentTarget);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
async function copyPluginPath(pluginDir, event) {
|
|
665
|
+
if (pluginDir) await copyToClipboard(pluginDir, event?.currentTarget);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
async function openFolderInEditor({ pluginId, marketplaceName, event } = {}) {
|
|
669
|
+
if (!pluginId && !marketplaceName) return;
|
|
670
|
+
await postAndFlash('/api/open-folder-in-editor', { pluginId, marketplaceName }, event?.currentTarget);
|
|
627
671
|
}
|
|
628
672
|
|
|
629
673
|
async function openReadmeModal(title, fetchUrl) {
|
|
630
674
|
_contentPluginId = null;
|
|
675
|
+
_contentPluginDir = null;
|
|
631
676
|
document.getElementById('contentModalTitle').textContent = `${title} \u2014 README`;
|
|
632
677
|
const tree = document.getElementById('contentTree');
|
|
633
678
|
const codeEl = getContentCodeEl();
|
|
@@ -648,6 +693,8 @@ async function openReadmeModal(title, fetchUrl) {
|
|
|
648
693
|
|
|
649
694
|
async function openContentModal(pluginId, initialPath, componentType) {
|
|
650
695
|
_contentPluginId = pluginId;
|
|
696
|
+
const comps = await fetchComponents(pluginId);
|
|
697
|
+
_contentPluginDir = comps?._pluginDir || null;
|
|
651
698
|
const plugin = findPlugin(pluginId);
|
|
652
699
|
const label = COMP_LABELS[componentType] || componentType;
|
|
653
700
|
document.getElementById('contentModalTitle').textContent = `${plugin?.name || pluginId} \u2014 ${label}`;
|
|
@@ -767,7 +814,7 @@ function showMarketplaceDetail(name) {
|
|
|
767
814
|
<div class="detail-header">
|
|
768
815
|
<h3>${ICONS.marketplace} ${esc(m.name)} ${m.version ? `<span class="version">v${esc(m.version)}</span>` : ''}</h3>
|
|
769
816
|
<div class="detail-header-actions">
|
|
770
|
-
${m.installLocation ? `<button class="modal-action-btn" title="Open in VS Code" onclick="openFolderInEditor({marketplaceName:'${esc(m.name)}'})">${ICONS.openEditor}</button>` : ''}
|
|
817
|
+
${m.installLocation ? `<button class="modal-action-btn" title="${esc(m.installLocation)}" onclick="copyPluginPath('${escJs(m.installLocation)}', event)">${ICONS.copyPath}</button><button class="modal-action-btn" title="Open in VS Code" onclick="openFolderInEditor({marketplaceName:'${esc(m.name)}',event})">${ICONS.openEditor}</button>` : ''}
|
|
771
818
|
<button class="detail-close" onclick="closeDetail()">\u2715</button>
|
|
772
819
|
</div>
|
|
773
820
|
</div>
|
|
@@ -1004,6 +1051,11 @@ function esc(str) {
|
|
|
1004
1051
|
.replace(/'/g, ''');
|
|
1005
1052
|
}
|
|
1006
1053
|
|
|
1054
|
+
function escJs(str) {
|
|
1055
|
+
if (!str) return '';
|
|
1056
|
+
return str.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1007
1059
|
function shortenPath(p) {
|
|
1008
1060
|
if (!p) return '';
|
|
1009
1061
|
const home = '~';
|
package/public/index.html
CHANGED
|
@@ -158,7 +158,8 @@
|
|
|
158
158
|
<div class="modal-header">
|
|
159
159
|
<h3 id="contentModalTitle">File Preview</h3>
|
|
160
160
|
<div class="modal-header-actions">
|
|
161
|
-
<button class="modal-action-btn" id="
|
|
161
|
+
<button class="modal-action-btn" id="contentCopyPath" title="Copy path" onclick="copyContentPath(event)"></button>
|
|
162
|
+
<button class="modal-action-btn" id="contentOpenEditor" title="Open in VS Code" onclick="openInEditor(event)"></button>
|
|
162
163
|
<button class="modal-close" onclick="closeModal('contentModal')">✕</button>
|
|
163
164
|
</div>
|
|
164
165
|
</div>
|
package/public/style.css
CHANGED
|
@@ -1042,6 +1042,21 @@ body.light .scope-toggle.local {
|
|
|
1042
1042
|
color: var(--accent);
|
|
1043
1043
|
background: var(--hover);
|
|
1044
1044
|
}
|
|
1045
|
+
.modal-action-btn.copy-success {
|
|
1046
|
+
color: var(--success, #22c55e);
|
|
1047
|
+
animation: copy-flash 0.3s ease;
|
|
1048
|
+
}
|
|
1049
|
+
@keyframes copy-flash {
|
|
1050
|
+
0% {
|
|
1051
|
+
transform: scale(1);
|
|
1052
|
+
}
|
|
1053
|
+
50% {
|
|
1054
|
+
transform: scale(1.3);
|
|
1055
|
+
}
|
|
1056
|
+
100% {
|
|
1057
|
+
transform: scale(1);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1045
1060
|
.modal-close {
|
|
1046
1061
|
background: none;
|
|
1047
1062
|
border: none;
|