claude-code-marketplace 0.5.8 → 0.5.10
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 +62 -7
- package/public/index.html +6 -5
- package/public/style.css +53 -29
- package/server.js +9 -4
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -7,6 +7,7 @@ let componentCache = {};
|
|
|
7
7
|
const detailHistory = [];
|
|
8
8
|
let focusedRowId = null;
|
|
9
9
|
let _focusedRowEl = null;
|
|
10
|
+
let treeContainer;
|
|
10
11
|
|
|
11
12
|
function matchKey(e, ...keys) {
|
|
12
13
|
if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) return false;
|
|
@@ -91,11 +92,13 @@ function updateArrow(p) {
|
|
|
91
92
|
|
|
92
93
|
// --- Init ---
|
|
93
94
|
document.addEventListener('DOMContentLoaded', () => {
|
|
95
|
+
treeContainer = document.getElementById('treeContainer');
|
|
94
96
|
document.getElementById('contentOpenEditor').innerHTML = ICONS.openEditor;
|
|
95
97
|
document.getElementById('contentCopyPath').innerHTML = ICONS.copyPath;
|
|
96
98
|
restoreAppState();
|
|
97
99
|
loadProject();
|
|
98
100
|
loadData();
|
|
101
|
+
initSidebarResize();
|
|
99
102
|
|
|
100
103
|
let searchTimer;
|
|
101
104
|
document.getElementById('searchInput').addEventListener('input', (e) => {
|
|
@@ -1168,13 +1171,13 @@ function shortenPath(p) {
|
|
|
1168
1171
|
.replace(/^\/home\/[^/]+/i, home);
|
|
1169
1172
|
}
|
|
1170
1173
|
|
|
1171
|
-
let toastTimeout;
|
|
1172
1174
|
function toast(msg, type = 'info') {
|
|
1173
|
-
const
|
|
1175
|
+
const container = document.getElementById('toast');
|
|
1176
|
+
const el = document.createElement('div');
|
|
1177
|
+
el.className = `toast toast-${type}`;
|
|
1174
1178
|
el.textContent = msg;
|
|
1175
|
-
el
|
|
1176
|
-
|
|
1177
|
-
toastTimeout = setTimeout(() => el.classList.remove('show'), 3000);
|
|
1179
|
+
container.appendChild(el);
|
|
1180
|
+
setTimeout(() => el.remove(), 3000);
|
|
1178
1181
|
}
|
|
1179
1182
|
|
|
1180
1183
|
function closeModal(id) {
|
|
@@ -1218,7 +1221,19 @@ async function submitAddMarketplace() {
|
|
|
1218
1221
|
// --- Keyboard Navigation ---
|
|
1219
1222
|
|
|
1220
1223
|
function getVisibleRows() {
|
|
1221
|
-
return [...
|
|
1224
|
+
return [...treeContainer.querySelectorAll('.tree-row')].filter((r) => r.offsetParent !== null);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
function scrollRowIntoView(row) {
|
|
1228
|
+
const rowTop = row.getBoundingClientRect().top - treeContainer.getBoundingClientRect().top + treeContainer.scrollTop;
|
|
1229
|
+
const rowBottom = rowTop + row.offsetHeight;
|
|
1230
|
+
const cTop = treeContainer.scrollTop;
|
|
1231
|
+
const cBottom = cTop + treeContainer.clientHeight;
|
|
1232
|
+
if (rowTop < cTop) {
|
|
1233
|
+
treeContainer.scrollTop = rowTop;
|
|
1234
|
+
} else if (rowBottom > cBottom) {
|
|
1235
|
+
treeContainer.scrollTop = rowBottom - treeContainer.clientHeight;
|
|
1236
|
+
}
|
|
1222
1237
|
}
|
|
1223
1238
|
|
|
1224
1239
|
function setFocusedRow(index, rows) {
|
|
@@ -1232,7 +1247,7 @@ function setFocusedRow(index, rows) {
|
|
|
1232
1247
|
index = Math.max(0, Math.min(index, rows.length - 1));
|
|
1233
1248
|
const row = rows[index];
|
|
1234
1249
|
row.classList.add('focused');
|
|
1235
|
-
row
|
|
1250
|
+
scrollRowIntoView(row);
|
|
1236
1251
|
focusedRowId = row.dataset.rowId;
|
|
1237
1252
|
_focusedRowEl = row;
|
|
1238
1253
|
}
|
|
@@ -1388,6 +1403,46 @@ if ('serviceWorker' in navigator) {
|
|
|
1388
1403
|
navigator.serviceWorker.register('/sw.js');
|
|
1389
1404
|
}
|
|
1390
1405
|
|
|
1406
|
+
function initSidebarResize() {
|
|
1407
|
+
const handle = document.getElementById('resizeHandle');
|
|
1408
|
+
const treePanel = document.getElementById('treePanel');
|
|
1409
|
+
const STORAGE_KEY = 'marketplace-sidebar-width';
|
|
1410
|
+
|
|
1411
|
+
const saved = parseInt(localStorage.getItem(STORAGE_KEY), 10);
|
|
1412
|
+
if (saved) document.documentElement.style.setProperty('--sidebar-w', `${saved}px`);
|
|
1413
|
+
|
|
1414
|
+
let dragging = false;
|
|
1415
|
+
let startX, startW, maxW, currentW;
|
|
1416
|
+
|
|
1417
|
+
handle.addEventListener('mousedown', (e) => {
|
|
1418
|
+
dragging = true;
|
|
1419
|
+
startX = e.clientX;
|
|
1420
|
+
startW = treePanel.getBoundingClientRect().width;
|
|
1421
|
+
currentW = startW;
|
|
1422
|
+
const detailMinW = parseInt(getComputedStyle(document.getElementById('detailPanel')).minWidth, 10);
|
|
1423
|
+
maxW = treePanel.parentElement.clientWidth - detailMinW - handle.offsetWidth;
|
|
1424
|
+
handle.classList.add('is-dragging');
|
|
1425
|
+
document.body.style.cursor = 'col-resize';
|
|
1426
|
+
document.body.style.userSelect = 'none';
|
|
1427
|
+
e.preventDefault();
|
|
1428
|
+
});
|
|
1429
|
+
|
|
1430
|
+
document.addEventListener('mousemove', (e) => {
|
|
1431
|
+
if (!dragging) return;
|
|
1432
|
+
currentW = Math.max(200, Math.min(maxW, startW + e.clientX - startX));
|
|
1433
|
+
document.documentElement.style.setProperty('--sidebar-w', `${currentW}px`);
|
|
1434
|
+
});
|
|
1435
|
+
|
|
1436
|
+
document.addEventListener('mouseup', () => {
|
|
1437
|
+
if (!dragging) return;
|
|
1438
|
+
dragging = false;
|
|
1439
|
+
handle.classList.remove('is-dragging');
|
|
1440
|
+
document.body.style.cursor = '';
|
|
1441
|
+
document.body.style.userSelect = '';
|
|
1442
|
+
localStorage.setItem(STORAGE_KEY, currentW);
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1391
1446
|
// #region HUB_INTEGRATION
|
|
1392
1447
|
(async function initHub() {
|
|
1393
1448
|
const cfg = await fetch('/hub-config')
|
package/public/index.html
CHANGED
|
@@ -46,24 +46,25 @@
|
|
|
46
46
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/></svg>
|
|
47
47
|
Refresh
|
|
48
48
|
</button>
|
|
49
|
+
<button class="topbar-btn" id="themeBtn" title="Toggle theme">
|
|
50
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
|
|
51
|
+
</button>
|
|
49
52
|
<button class="topbar-btn" id="helpBtn" title="Keyboard shortcuts (?)">
|
|
50
53
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><circle cx="12" cy="17" r="0.5" fill="currentColor"/></svg>
|
|
51
54
|
<kbd style="font-size:10px">?</kbd>
|
|
52
55
|
</button>
|
|
53
|
-
<button class="topbar-btn" id="themeBtn" title="Toggle theme">
|
|
54
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
|
|
55
|
-
</button>
|
|
56
56
|
<a class="topbar-btn" href="https://github.com/NikiforovAll/claude-code-marketplace" target="_blank" rel="noopener" title="GitHub">
|
|
57
57
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
|
|
58
58
|
</a>
|
|
59
59
|
</div>
|
|
60
60
|
|
|
61
61
|
<div class="main-layout">
|
|
62
|
-
<div class="tree-panel">
|
|
62
|
+
<div class="tree-panel" id="treePanel">
|
|
63
63
|
<div class="tree-container" id="treeContainer">
|
|
64
64
|
<div class="loading">Loading marketplaces...</div>
|
|
65
65
|
</div>
|
|
66
66
|
</div>
|
|
67
|
+
<div class="resize-handle" id="resizeHandle"></div>
|
|
67
68
|
<div class="detail-panel" id="detailPanel">
|
|
68
69
|
<div class="detail-empty">
|
|
69
70
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" opacity="0.3"><path d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"/></svg>
|
|
@@ -72,7 +73,7 @@
|
|
|
72
73
|
</div>
|
|
73
74
|
</div>
|
|
74
75
|
|
|
75
|
-
<div class="toast" id="toast"></div>
|
|
76
|
+
<div class="toast-container" id="toast"></div>
|
|
76
77
|
|
|
77
78
|
<!-- Add marketplace modal -->
|
|
78
79
|
<div class="modal-overlay" id="addMarketplaceModal">
|
package/public/style.css
CHANGED
|
@@ -279,11 +279,25 @@ body {
|
|
|
279
279
|
/* === TREE PANEL === */
|
|
280
280
|
|
|
281
281
|
.tree-panel {
|
|
282
|
-
flex:
|
|
282
|
+
flex: 0 0 var(--sidebar-w, 400px);
|
|
283
283
|
display: flex;
|
|
284
284
|
flex-direction: column;
|
|
285
285
|
overflow: hidden;
|
|
286
|
-
min-width:
|
|
286
|
+
min-width: 200px;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.resize-handle {
|
|
290
|
+
width: 4px;
|
|
291
|
+
flex-shrink: 0;
|
|
292
|
+
cursor: col-resize;
|
|
293
|
+
background: transparent;
|
|
294
|
+
transition: background 0.15s;
|
|
295
|
+
position: relative;
|
|
296
|
+
z-index: 1;
|
|
297
|
+
}
|
|
298
|
+
.resize-handle:hover,
|
|
299
|
+
.resize-handle.is-dragging {
|
|
300
|
+
background: var(--accent);
|
|
287
301
|
}
|
|
288
302
|
|
|
289
303
|
.tree-expand-toggle {
|
|
@@ -670,8 +684,8 @@ body.light .scope-toggle.local {
|
|
|
670
684
|
/* === DETAIL PANEL === */
|
|
671
685
|
|
|
672
686
|
.detail-panel {
|
|
673
|
-
|
|
674
|
-
|
|
687
|
+
flex: 1;
|
|
688
|
+
min-width: 300px;
|
|
675
689
|
background: var(--bg-surface);
|
|
676
690
|
border-left: 1px solid var(--border);
|
|
677
691
|
display: flex;
|
|
@@ -995,37 +1009,47 @@ body.light .scope-toggle.local {
|
|
|
995
1009
|
|
|
996
1010
|
/* === TOAST === */
|
|
997
1011
|
|
|
998
|
-
.toast {
|
|
1012
|
+
.toast-container {
|
|
999
1013
|
position: fixed;
|
|
1000
|
-
bottom:
|
|
1001
|
-
right:
|
|
1002
|
-
|
|
1014
|
+
bottom: 16px;
|
|
1015
|
+
right: 16px;
|
|
1016
|
+
z-index: 100;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
.toast {
|
|
1020
|
+
background: var(--bg-elevated);
|
|
1021
|
+
border: 1px solid var(--border);
|
|
1003
1022
|
border-radius: 6px;
|
|
1004
|
-
|
|
1005
|
-
font-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
z-index: 1000;
|
|
1009
|
-
opacity: 0;
|
|
1010
|
-
transform: translateY(10px);
|
|
1011
|
-
transition: all 300ms ease;
|
|
1012
|
-
max-width: 400px;
|
|
1023
|
+
padding: 8px 14px;
|
|
1024
|
+
font-size: 11px;
|
|
1025
|
+
color: var(--text-secondary);
|
|
1026
|
+
animation: slideIn 0.2s ease;
|
|
1013
1027
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1028
|
+
|
|
1029
|
+
.toast.toast-success {
|
|
1030
|
+
border-color: #2ea043;
|
|
1031
|
+
color: #2ea043;
|
|
1017
1032
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
color: #
|
|
1033
|
+
|
|
1034
|
+
.toast.toast-error {
|
|
1035
|
+
border-color: #f85149;
|
|
1036
|
+
color: #f85149;
|
|
1021
1037
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
color:
|
|
1038
|
+
|
|
1039
|
+
.toast.toast-info {
|
|
1040
|
+
border-color: var(--accent);
|
|
1041
|
+
color: var(--accent);
|
|
1025
1042
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1043
|
+
|
|
1044
|
+
@keyframes slideIn {
|
|
1045
|
+
from {
|
|
1046
|
+
opacity: 0;
|
|
1047
|
+
transform: translateY(10px);
|
|
1048
|
+
}
|
|
1049
|
+
to {
|
|
1050
|
+
opacity: 1;
|
|
1051
|
+
transform: translateY(0);
|
|
1052
|
+
}
|
|
1029
1053
|
}
|
|
1030
1054
|
|
|
1031
1055
|
/* === MODAL === */
|
package/server.js
CHANGED
|
@@ -258,7 +258,12 @@ function loadMarketplaces() {
|
|
|
258
258
|
const components = {};
|
|
259
259
|
for (const k of compKeys) {
|
|
260
260
|
if (fsComps && Array.isArray(fsComps[k]) && fsComps[k].length > 0) {
|
|
261
|
-
|
|
261
|
+
if (Array.isArray(pd[k]) && pd[k].length > 0) {
|
|
262
|
+
const allowed = new Set(pd[k].map(p => path.basename(typeof p === 'string' ? p : (p.name || String(p)))));
|
|
263
|
+
components[k] = fsComps[k].filter(name => allowed.has(name));
|
|
264
|
+
} else {
|
|
265
|
+
components[k] = fsComps[k];
|
|
266
|
+
}
|
|
262
267
|
} else if (Array.isArray(pd[k]) && pd[k].length > 0) {
|
|
263
268
|
components[k] = pd[k].map(p => typeof p === 'string' ? path.basename(p) : (p.name || String(p)));
|
|
264
269
|
} else if (pd[k]) {
|
|
@@ -617,9 +622,9 @@ app.get('/api/plugins/:pluginId/components', (req, res) => {
|
|
|
617
622
|
}
|
|
618
623
|
if (!plugin?._pluginDir) return res.status(404).json({ error: 'Plugin directory not found', pluginId });
|
|
619
624
|
|
|
620
|
-
const comps = plugin._fsComps || countComponents(plugin._pluginDir, plugin.metadata);
|
|
621
|
-
comps
|
|
622
|
-
res.json(
|
|
625
|
+
const comps = plugin.components || plugin._fsComps || countComponents(plugin._pluginDir, plugin.metadata);
|
|
626
|
+
const result = { ...comps, _pluginDir: plugin._pluginDir };
|
|
627
|
+
res.json(result);
|
|
623
628
|
});
|
|
624
629
|
|
|
625
630
|
app.get('/api/plugins/:pluginId/preview/*', (req, res) => {
|