claude-code-marketplace 0.4.0 → 0.4.2
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 +75 -15
- package/public/index.html +2 -1
- package/public/style.css +18 -3
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();
|
|
@@ -117,6 +120,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
117
120
|
document.body.classList.add('light');
|
|
118
121
|
}
|
|
119
122
|
syncHljsTheme();
|
|
123
|
+
updateThemeColor(savedTheme !== 'dark');
|
|
120
124
|
|
|
121
125
|
document.addEventListener('keydown', handleKeydown);
|
|
122
126
|
});
|
|
@@ -129,6 +133,12 @@ function syncHljsTheme() {
|
|
|
129
133
|
if (lightSheet) lightSheet.disabled = !light;
|
|
130
134
|
}
|
|
131
135
|
|
|
136
|
+
function updateThemeColor(isLight) {
|
|
137
|
+
document.querySelectorAll('meta[name="theme-color"]').forEach((m) => {
|
|
138
|
+
m.setAttribute('content', isLight ? '#e8e6e3' : '#101114');
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
132
142
|
function toggleTheme() {
|
|
133
143
|
const isLight = document.body.classList.contains('light');
|
|
134
144
|
document.body.classList.remove('light', 'dark-forced');
|
|
@@ -140,6 +150,7 @@ function toggleTheme() {
|
|
|
140
150
|
localStorage.setItem('theme', 'light');
|
|
141
151
|
}
|
|
142
152
|
syncHljsTheme();
|
|
153
|
+
updateThemeColor(!isLight);
|
|
143
154
|
}
|
|
144
155
|
|
|
145
156
|
async function loadProject() {
|
|
@@ -447,7 +458,7 @@ async function showDetail(pluginId) {
|
|
|
447
458
|
<div class="detail-header">
|
|
448
459
|
<h3>${headerIcon} ${esc(plugin.name)} ${plugin.version ? `<span class="version">v${esc(plugin.version)}</span>` : ''}</h3>
|
|
449
460
|
<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>` : ''}
|
|
461
|
+
${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
462
|
<button class="detail-close" onclick="closeDetail()">\u2715</button>
|
|
452
463
|
</div>
|
|
453
464
|
</div>
|
|
@@ -576,6 +587,7 @@ const EXT_TO_LANG = {
|
|
|
576
587
|
const PREFERRED_FILE = 'SKILL.MD';
|
|
577
588
|
let _contentCodeEl = null;
|
|
578
589
|
let _contentPluginId = null;
|
|
590
|
+
let _contentPluginDir = null;
|
|
579
591
|
|
|
580
592
|
function highlightSource(text, fileName) {
|
|
581
593
|
const ext = (fileName || '').split('.').pop().toLowerCase();
|
|
@@ -603,31 +615,72 @@ function getContentCodeEl() {
|
|
|
603
615
|
return _contentCodeEl;
|
|
604
616
|
}
|
|
605
617
|
|
|
606
|
-
async function
|
|
607
|
-
if (!_contentPluginId) return;
|
|
608
|
-
const relativePath = document.getElementById('contentViewerPath').textContent || '';
|
|
618
|
+
async function postAndFlash(endpoint, data, btn) {
|
|
609
619
|
try {
|
|
610
|
-
await fetch(
|
|
620
|
+
await fetch(endpoint, {
|
|
611
621
|
method: 'POST',
|
|
612
622
|
headers: { 'Content-Type': 'application/json' },
|
|
613
|
-
body: JSON.stringify(
|
|
623
|
+
body: JSON.stringify(data),
|
|
614
624
|
});
|
|
625
|
+
if (btn) flashButton(btn);
|
|
615
626
|
} catch {}
|
|
616
627
|
}
|
|
617
628
|
|
|
618
|
-
async function
|
|
619
|
-
if (!
|
|
629
|
+
async function openInEditor(event) {
|
|
630
|
+
if (!_contentPluginId) return;
|
|
631
|
+
const relativePath = document.getElementById('contentViewerPath').textContent || '';
|
|
632
|
+
await postAndFlash('/api/open-in-editor', { pluginId: _contentPluginId, relativePath }, event?.currentTarget);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const CHECKMARK_SVG =
|
|
636
|
+
'<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>';
|
|
637
|
+
|
|
638
|
+
function flashButton(btn) {
|
|
639
|
+
if (btn._flashTimeout) clearTimeout(btn._flashTimeout);
|
|
640
|
+
if (!btn._flashOrig) btn._flashOrig = btn.innerHTML;
|
|
641
|
+
btn.innerHTML = CHECKMARK_SVG;
|
|
642
|
+
btn.classList.add('copy-success');
|
|
643
|
+
btn._flashTimeout = setTimeout(() => {
|
|
644
|
+
btn.innerHTML = btn._flashOrig;
|
|
645
|
+
btn.classList.remove('copy-success');
|
|
646
|
+
btn._flashOrig = null;
|
|
647
|
+
btn._flashTimeout = null;
|
|
648
|
+
}, 1000);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
async function copyToClipboard(text, btn) {
|
|
620
652
|
try {
|
|
621
|
-
await
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
653
|
+
await navigator.clipboard.writeText(text);
|
|
654
|
+
} catch {
|
|
655
|
+
const ta = document.createElement('textarea');
|
|
656
|
+
ta.value = text;
|
|
657
|
+
document.body.appendChild(ta);
|
|
658
|
+
ta.select();
|
|
659
|
+
document.execCommand('copy');
|
|
660
|
+
document.body.removeChild(ta);
|
|
661
|
+
}
|
|
662
|
+
if (btn) flashButton(btn);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
async function copyContentPath(event) {
|
|
666
|
+
if (!_contentPluginDir) return;
|
|
667
|
+
const relativePath = document.getElementById('contentViewerPath').textContent || '';
|
|
668
|
+
const full = relativePath ? `${_contentPluginDir}/${relativePath}` : _contentPluginDir;
|
|
669
|
+
await copyToClipboard(full, event?.currentTarget);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
async function copyPluginPath(pluginDir, event) {
|
|
673
|
+
if (pluginDir) await copyToClipboard(pluginDir, event?.currentTarget);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
async function openFolderInEditor({ pluginId, marketplaceName, event } = {}) {
|
|
677
|
+
if (!pluginId && !marketplaceName) return;
|
|
678
|
+
await postAndFlash('/api/open-folder-in-editor', { pluginId, marketplaceName }, event?.currentTarget);
|
|
627
679
|
}
|
|
628
680
|
|
|
629
681
|
async function openReadmeModal(title, fetchUrl) {
|
|
630
682
|
_contentPluginId = null;
|
|
683
|
+
_contentPluginDir = null;
|
|
631
684
|
document.getElementById('contentModalTitle').textContent = `${title} \u2014 README`;
|
|
632
685
|
const tree = document.getElementById('contentTree');
|
|
633
686
|
const codeEl = getContentCodeEl();
|
|
@@ -648,6 +701,8 @@ async function openReadmeModal(title, fetchUrl) {
|
|
|
648
701
|
|
|
649
702
|
async function openContentModal(pluginId, initialPath, componentType) {
|
|
650
703
|
_contentPluginId = pluginId;
|
|
704
|
+
const comps = await fetchComponents(pluginId);
|
|
705
|
+
_contentPluginDir = comps?._pluginDir || null;
|
|
651
706
|
const plugin = findPlugin(pluginId);
|
|
652
707
|
const label = COMP_LABELS[componentType] || componentType;
|
|
653
708
|
document.getElementById('contentModalTitle').textContent = `${plugin?.name || pluginId} \u2014 ${label}`;
|
|
@@ -767,7 +822,7 @@ function showMarketplaceDetail(name) {
|
|
|
767
822
|
<div class="detail-header">
|
|
768
823
|
<h3>${ICONS.marketplace} ${esc(m.name)} ${m.version ? `<span class="version">v${esc(m.version)}</span>` : ''}</h3>
|
|
769
824
|
<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>` : ''}
|
|
825
|
+
${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
826
|
<button class="detail-close" onclick="closeDetail()">\u2715</button>
|
|
772
827
|
</div>
|
|
773
828
|
</div>
|
|
@@ -1004,6 +1059,11 @@ function esc(str) {
|
|
|
1004
1059
|
.replace(/'/g, ''');
|
|
1005
1060
|
}
|
|
1006
1061
|
|
|
1062
|
+
function escJs(str) {
|
|
1063
|
+
if (!str) return '';
|
|
1064
|
+
return str.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1007
1067
|
function shortenPath(p) {
|
|
1008
1068
|
if (!p) return '';
|
|
1009
1069
|
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
|
@@ -42,9 +42,9 @@ body.light {
|
|
|
42
42
|
--bg-hover: #d2d0cc;
|
|
43
43
|
--border: #a09b94;
|
|
44
44
|
--text-primary: #0a0a0a;
|
|
45
|
-
--text-secondary: #
|
|
46
|
-
--text-tertiary: #
|
|
47
|
-
--text-muted: #
|
|
45
|
+
--text-secondary: #333333;
|
|
46
|
+
--text-tertiary: #555555;
|
|
47
|
+
--text-muted: #777777;
|
|
48
48
|
--accent-text: #b85a20;
|
|
49
49
|
--accent-dim: rgba(232, 111, 51, 0.18);
|
|
50
50
|
--accent-glow: rgba(232, 111, 51, 0.5);
|
|
@@ -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;
|