@laststance/claude-plugin-dashboard 0.2.3 → 0.3.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/README.md +7 -1
- package/dist/app.d.ts +7 -1
- package/dist/app.js +544 -262
- package/dist/cli.js +60 -67
- package/dist/components/ComponentBadges.d.ts +0 -9
- package/dist/components/ComponentBadges.js +0 -33
- package/dist/components/ComponentDetail.d.ts +32 -0
- package/dist/components/ComponentDetail.js +106 -0
- package/dist/components/ComponentList.d.ts +87 -0
- package/dist/components/ComponentList.js +287 -0
- package/dist/components/HelpOverlay.js +1 -0
- package/dist/components/KeyHints.d.ts +1 -0
- package/dist/components/KeyHints.js +33 -29
- package/dist/components/MarketplaceActionMenu.d.ts +41 -0
- package/dist/components/MarketplaceActionMenu.js +68 -0
- package/dist/components/MarketplaceDetail.d.ts +10 -3
- package/dist/components/MarketplaceDetail.js +10 -4
- package/dist/components/PluginDetail.d.ts +19 -3
- package/dist/components/PluginDetail.js +56 -6
- package/dist/components/PluginList.js +19 -7
- package/dist/services/componentService.d.ts +10 -31
- package/dist/services/componentService.js +19 -174
- package/dist/services/components/hookService.d.ts +17 -0
- package/dist/services/components/hookService.js +45 -0
- package/dist/services/components/index.d.ts +41 -0
- package/dist/services/components/index.js +126 -0
- package/dist/services/components/markdownService.d.ts +39 -0
- package/dist/services/components/markdownService.js +147 -0
- package/dist/services/components/serverService.d.ts +28 -0
- package/dist/services/components/serverService.js +69 -0
- package/dist/services/components/skillService.d.ts +48 -0
- package/dist/services/components/skillService.js +164 -0
- package/dist/services/components/utils.d.ts +23 -0
- package/dist/services/components/utils.js +42 -0
- package/dist/services/marketplaceActionsService.d.ts +17 -0
- package/dist/services/marketplaceActionsService.js +18 -0
- package/dist/services/pluginActionsService.d.ts +31 -2
- package/dist/services/pluginActionsService.js +65 -6
- package/dist/services/pluginService.js +78 -2
- package/dist/store/index.d.ts +46 -0
- package/dist/store/index.js +47 -0
- package/dist/store/slices/marketplaceSlice.d.ts +344 -0
- package/dist/store/slices/marketplaceSlice.js +152 -0
- package/dist/store/slices/pluginSlice.d.ts +1544 -0
- package/dist/store/slices/pluginSlice.js +191 -0
- package/dist/store/slices/uiSlice.d.ts +147 -0
- package/dist/store/slices/uiSlice.js +126 -0
- package/dist/tabs/DiscoverTab.d.ts +8 -2
- package/dist/tabs/DiscoverTab.js +2 -2
- package/dist/tabs/EnabledTab.d.ts +8 -2
- package/dist/tabs/EnabledTab.js +3 -3
- package/dist/tabs/ErrorsTab.js +1 -1
- package/dist/tabs/InstalledTab.d.ts +8 -2
- package/dist/tabs/InstalledTab.js +3 -3
- package/dist/tabs/MarketplacesTab.d.ts +15 -2
- package/dist/tabs/MarketplacesTab.js +13 -4
- package/dist/types/index.d.ts +157 -5
- package/package.json +10 -3
package/dist/cli.js
CHANGED
|
@@ -14,12 +14,16 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
14
14
|
* claude-plugin-dashboard toggle <plugin-id> # Toggle plugin
|
|
15
15
|
* claude-plugin-dashboard help # Show help
|
|
16
16
|
*/
|
|
17
|
-
import {
|
|
17
|
+
import { withFullScreen } from 'fullscreen-ink';
|
|
18
|
+
import { match, P } from 'ts-pattern';
|
|
19
|
+
import { Provider } from 'react-redux';
|
|
18
20
|
import App from './app.js';
|
|
21
|
+
import { store } from './store/index.js';
|
|
19
22
|
import { loadAllPlugins, loadInstalledPlugins, loadMarketplaces, getPluginStatistics, getPluginById, } from './services/pluginService.js';
|
|
20
23
|
import { enablePlugin, disablePlugin, togglePlugin, } from './services/settingsService.js';
|
|
21
24
|
import { fileExists } from './services/fileService.js';
|
|
22
25
|
import { PATHS } from './utils/paths.js';
|
|
26
|
+
import packageJson from '../package.json' with { type: 'json' };
|
|
23
27
|
const args = process.argv.slice(2);
|
|
24
28
|
const command = args[0];
|
|
25
29
|
const subCommand = args[1];
|
|
@@ -243,66 +247,57 @@ function checkClaudeCodeInstalled() {
|
|
|
243
247
|
if (command) {
|
|
244
248
|
// Non-interactive mode
|
|
245
249
|
checkClaudeCodeInstalled();
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (!subCommand) {
|
|
266
|
-
console.error('Usage: claude-plugin-dashboard info <plugin-id>');
|
|
267
|
-
process.exit(1);
|
|
268
|
-
}
|
|
269
|
-
showPluginInfo(subCommand);
|
|
270
|
-
break;
|
|
271
|
-
case 'enable':
|
|
272
|
-
if (!subCommand) {
|
|
273
|
-
console.error('Usage: claude-plugin-dashboard enable <plugin-id>');
|
|
274
|
-
process.exit(1);
|
|
275
|
-
}
|
|
276
|
-
handleEnable(subCommand);
|
|
277
|
-
break;
|
|
278
|
-
case 'disable':
|
|
279
|
-
if (!subCommand) {
|
|
280
|
-
console.error('Usage: claude-plugin-dashboard disable <plugin-id>');
|
|
281
|
-
process.exit(1);
|
|
282
|
-
}
|
|
283
|
-
handleDisable(subCommand);
|
|
284
|
-
break;
|
|
285
|
-
case 'toggle':
|
|
286
|
-
if (!subCommand) {
|
|
287
|
-
console.error('Usage: claude-plugin-dashboard toggle <plugin-id>');
|
|
288
|
-
process.exit(1);
|
|
289
|
-
}
|
|
290
|
-
handleToggle(subCommand);
|
|
291
|
-
break;
|
|
292
|
-
case 'help':
|
|
293
|
-
case '-h':
|
|
294
|
-
case '--help':
|
|
295
|
-
showHelp();
|
|
296
|
-
break;
|
|
297
|
-
case '-v':
|
|
298
|
-
case '--version':
|
|
299
|
-
console.log('claude-plugin-dashboard v0.1.0');
|
|
300
|
-
break;
|
|
301
|
-
default:
|
|
302
|
-
console.error(`Unknown command: ${command}`);
|
|
303
|
-
console.log('Run "claude-plugin-dashboard help" for usage information.');
|
|
250
|
+
match(command)
|
|
251
|
+
.with('status', () => showStatus())
|
|
252
|
+
.with('list', () => {
|
|
253
|
+
if (subCommand === '--installed' || args.includes('--installed')) {
|
|
254
|
+
listPlugins({ installed: true });
|
|
255
|
+
}
|
|
256
|
+
else if (subCommand === '--marketplace' ||
|
|
257
|
+
args.includes('--marketplace')) {
|
|
258
|
+
const marketplaceIndex = args.indexOf('--marketplace');
|
|
259
|
+
const marketplace = args[marketplaceIndex + 1];
|
|
260
|
+
listPlugins({ marketplace });
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
listPlugins({});
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
.with('info', () => {
|
|
267
|
+
if (!subCommand) {
|
|
268
|
+
console.error('Usage: claude-plugin-dashboard info <plugin-id>');
|
|
304
269
|
process.exit(1);
|
|
305
|
-
|
|
270
|
+
}
|
|
271
|
+
showPluginInfo(subCommand);
|
|
272
|
+
})
|
|
273
|
+
.with('enable', () => {
|
|
274
|
+
if (!subCommand) {
|
|
275
|
+
console.error('Usage: claude-plugin-dashboard enable <plugin-id>');
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
handleEnable(subCommand);
|
|
279
|
+
})
|
|
280
|
+
.with('disable', () => {
|
|
281
|
+
if (!subCommand) {
|
|
282
|
+
console.error('Usage: claude-plugin-dashboard disable <plugin-id>');
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
handleDisable(subCommand);
|
|
286
|
+
})
|
|
287
|
+
.with('toggle', () => {
|
|
288
|
+
if (!subCommand) {
|
|
289
|
+
console.error('Usage: claude-plugin-dashboard toggle <plugin-id>');
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
handleToggle(subCommand);
|
|
293
|
+
})
|
|
294
|
+
.with(P.union('help', '-h', '--help'), () => showHelp())
|
|
295
|
+
.with(P.union('-v', '--version'), () => console.log(`claude-plugin-dashboard v${packageJson.version}`))
|
|
296
|
+
.otherwise((cmd) => {
|
|
297
|
+
console.error(`Unknown command: ${cmd}`);
|
|
298
|
+
console.log('Run "claude-plugin-dashboard help" for usage information.');
|
|
299
|
+
process.exit(1);
|
|
300
|
+
});
|
|
306
301
|
}
|
|
307
302
|
else {
|
|
308
303
|
// Interactive mode
|
|
@@ -312,11 +307,9 @@ else {
|
|
|
312
307
|
console.log('Use "claude-plugin-dashboard help" for non-interactive commands.');
|
|
313
308
|
process.exit(1);
|
|
314
309
|
}
|
|
315
|
-
|
|
316
|
-
//
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
process.stdout.write('\x1b[2J\x1b[H');
|
|
321
|
-
});
|
|
310
|
+
// Use fullscreen-ink for alternate screen buffer management
|
|
311
|
+
// This prevents rendering artifacts when switching tabs
|
|
312
|
+
const ink = withFullScreen(_jsx(Provider, { store: store, children: _jsx(App, {}) }));
|
|
313
|
+
ink.start();
|
|
314
|
+
ink.waitUntilExit();
|
|
322
315
|
}
|
|
@@ -21,12 +21,3 @@ export interface ComponentBadgesProps {
|
|
|
21
21
|
* // Renders: Skills:5 Slash:2
|
|
22
22
|
*/
|
|
23
23
|
export default function ComponentBadges({ components, }: ComponentBadgesProps): React.ReactNode;
|
|
24
|
-
/**
|
|
25
|
-
* Get a human-readable description of component types
|
|
26
|
-
* @param components - PluginComponents object
|
|
27
|
-
* @returns Formatted string describing components
|
|
28
|
-
* @example
|
|
29
|
-
* getComponentsDescription({ skills: 3, mcpServers: 1 })
|
|
30
|
-
* // => "3 skills, 1 MCP server"
|
|
31
|
-
*/
|
|
32
|
-
export declare function getComponentsDescription(components: PluginComponents | undefined): string;
|
|
@@ -48,36 +48,3 @@ export default function ComponentBadges({ components, }) {
|
|
|
48
48
|
function Badge({ label, count, color, }) {
|
|
49
49
|
return (_jsxs(Text, { children: [_jsx(Text, { color: color, bold: true, children: label }), count !== undefined && _jsxs(Text, { dimColor: true, children: [":", count] })] }));
|
|
50
50
|
}
|
|
51
|
-
/**
|
|
52
|
-
* Get a human-readable description of component types
|
|
53
|
-
* @param components - PluginComponents object
|
|
54
|
-
* @returns Formatted string describing components
|
|
55
|
-
* @example
|
|
56
|
-
* getComponentsDescription({ skills: 3, mcpServers: 1 })
|
|
57
|
-
* // => "3 skills, 1 MCP server"
|
|
58
|
-
*/
|
|
59
|
-
export function getComponentsDescription(components) {
|
|
60
|
-
if (!components) {
|
|
61
|
-
return '';
|
|
62
|
-
}
|
|
63
|
-
const parts = [];
|
|
64
|
-
if (components.skills) {
|
|
65
|
-
parts.push(`${components.skills} skill${components.skills > 1 ? 's' : ''}`);
|
|
66
|
-
}
|
|
67
|
-
if (components.commands) {
|
|
68
|
-
parts.push(`${components.commands} command${components.commands > 1 ? 's' : ''}`);
|
|
69
|
-
}
|
|
70
|
-
if (components.agents) {
|
|
71
|
-
parts.push(`${components.agents} agent${components.agents > 1 ? 's' : ''}`);
|
|
72
|
-
}
|
|
73
|
-
if (components.hooks) {
|
|
74
|
-
parts.push('hooks');
|
|
75
|
-
}
|
|
76
|
-
if (components.mcpServers) {
|
|
77
|
-
parts.push(`${components.mcpServers} MCP server${components.mcpServers > 1 ? 's' : ''}`);
|
|
78
|
-
}
|
|
79
|
-
if (components.lspServers) {
|
|
80
|
-
parts.push(`${components.lspServers} LSP server${components.lspServers > 1 ? 's' : ''}`);
|
|
81
|
-
}
|
|
82
|
-
return parts.join(', ');
|
|
83
|
-
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ComponentDetail component
|
|
3
|
+
* Displays detailed information about a selected component
|
|
4
|
+
* Shows name, type, description, allowed tools, and full content
|
|
5
|
+
*/
|
|
6
|
+
import type { ComponentDetailedInfo } from '../types/index.js';
|
|
7
|
+
/**
|
|
8
|
+
* Props for ComponentDetail
|
|
9
|
+
*/
|
|
10
|
+
export interface ComponentDetailProps {
|
|
11
|
+
/** Detailed component info to display */
|
|
12
|
+
component: ComponentDetailedInfo | null;
|
|
13
|
+
/** Maximum height for the detail panel */
|
|
14
|
+
maxHeight?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Displays detailed component information in a panel
|
|
18
|
+
* Used when user selects a component from the ComponentList
|
|
19
|
+
* Supports compact mode when maxHeight <= 4 (shows only name, type, description)
|
|
20
|
+
* @param props - ComponentDetailProps
|
|
21
|
+
* @returns React node
|
|
22
|
+
* @example
|
|
23
|
+
* <ComponentDetail
|
|
24
|
+
* component={{
|
|
25
|
+
* name: "sentry-code-review",
|
|
26
|
+
* type: "skill",
|
|
27
|
+
* description: "Analyze Sentry comments",
|
|
28
|
+
* allowedTools: ["Read", "Edit"]
|
|
29
|
+
* }}
|
|
30
|
+
* />
|
|
31
|
+
*/
|
|
32
|
+
export default function ComponentDetail({ component, maxHeight, }: ComponentDetailProps): React.ReactNode;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ComponentDetail component
|
|
4
|
+
* Displays detailed information about a selected component
|
|
5
|
+
* Shows name, type, description, allowed tools, and full content
|
|
6
|
+
*/
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import { Box, Text } from 'ink';
|
|
9
|
+
/**
|
|
10
|
+
* Type badge colors for visual distinction
|
|
11
|
+
*/
|
|
12
|
+
const TYPE_COLORS = {
|
|
13
|
+
skill: 'magenta',
|
|
14
|
+
command: 'cyan',
|
|
15
|
+
agent: 'blue',
|
|
16
|
+
hook: 'yellow',
|
|
17
|
+
mcp: 'green',
|
|
18
|
+
lsp: 'blueBright',
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Type labels for display
|
|
22
|
+
*/
|
|
23
|
+
const TYPE_LABELS = {
|
|
24
|
+
skill: 'Skill',
|
|
25
|
+
command: 'Slash Command',
|
|
26
|
+
agent: 'Agent',
|
|
27
|
+
hook: 'Hook',
|
|
28
|
+
mcp: 'MCP Server',
|
|
29
|
+
lsp: 'LSP Server',
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Compact mode threshold - show minimal info when height is small
|
|
33
|
+
*/
|
|
34
|
+
const COMPACT_MODE_THRESHOLD = 4;
|
|
35
|
+
/**
|
|
36
|
+
* Displays detailed component information in a panel
|
|
37
|
+
* Used when user selects a component from the ComponentList
|
|
38
|
+
* Supports compact mode when maxHeight <= 4 (shows only name, type, description)
|
|
39
|
+
* @param props - ComponentDetailProps
|
|
40
|
+
* @returns React node
|
|
41
|
+
* @example
|
|
42
|
+
* <ComponentDetail
|
|
43
|
+
* component={{
|
|
44
|
+
* name: "sentry-code-review",
|
|
45
|
+
* type: "skill",
|
|
46
|
+
* description: "Analyze Sentry comments",
|
|
47
|
+
* allowedTools: ["Read", "Edit"]
|
|
48
|
+
* }}
|
|
49
|
+
* />
|
|
50
|
+
*/
|
|
51
|
+
export default function ComponentDetail({ component, maxHeight = 10, }) {
|
|
52
|
+
// Safe content height calculation (at least 1 line)
|
|
53
|
+
const contentHeight = Math.max(1, maxHeight - 6);
|
|
54
|
+
const isCompact = maxHeight <= COMPACT_MODE_THRESHOLD;
|
|
55
|
+
if (!component) {
|
|
56
|
+
return (_jsx(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, height: maxHeight, children: _jsx(Text, { dimColor: true, children: "Select a component to view details" }) }));
|
|
57
|
+
}
|
|
58
|
+
const typeColor = TYPE_COLORS[component.type] || 'white';
|
|
59
|
+
const typeLabel = TYPE_LABELS[component.type] || component.type;
|
|
60
|
+
// Compact mode: minimal info only (name, type, description)
|
|
61
|
+
if (isCompact) {
|
|
62
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1, height: maxHeight, overflow: "hidden", children: [_jsxs(Box, { height: 1, children: [_jsxs(Text, { bold: true, color: "white", children: ["\uD83D\uDCE6 ", truncateString(component.name, 20)] }), _jsx(Text, { children: " " }), _jsxs(Text, { color: typeColor, bold: true, children: ["[", typeLabel, "]"] })] }), _jsx(Box, { height: 1, children: _jsx(Text, { wrap: "truncate", dimColor: true, children: component.description || 'No description' }) })] }));
|
|
63
|
+
}
|
|
64
|
+
// Full mode: show all details
|
|
65
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1, height: maxHeight, overflow: "hidden", children: [_jsxs(Box, { height: 1, children: [_jsxs(Text, { bold: true, color: "white", children: ["\uD83D\uDCE6 ", component.name] }), _jsx(Text, { children: " " }), _jsxs(Text, { color: typeColor, bold: true, children: ["[", typeLabel, "]"] })] }), component.description && (_jsx(Box, { height: 1, children: _jsx(Text, { wrap: "truncate", children: component.description }) })), component.allowedTools && component.allowedTools.length > 0 && (_jsxs(Box, { height: 1, children: [_jsxs(Text, { color: "yellow", bold: true, children: ["Tools:", ' '] }), _jsx(Text, { dimColor: true, wrap: "truncate", children: component.allowedTools.join(', ') })] })), component.filePath && (_jsx(Box, { height: 1, children: _jsxs(Text, { color: "gray", children: ["\uD83D\uDCC4 ", shortenPath(component.filePath)] }) })), component.fullDescription && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "\u2500\u2500 Content \u2500\u2500" }), _jsx(Box, { height: contentHeight, overflow: "hidden", children: _jsx(Text, { dimColor: true, wrap: "truncate", children: truncateContent(component.fullDescription, contentHeight) }) })] }))] }));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Truncate string to max length with ellipsis
|
|
69
|
+
* @param str - String to truncate
|
|
70
|
+
* @param maxLength - Maximum length
|
|
71
|
+
* @returns Truncated string
|
|
72
|
+
*/
|
|
73
|
+
function truncateString(str, maxLength) {
|
|
74
|
+
if (str.length <= maxLength) {
|
|
75
|
+
return str;
|
|
76
|
+
}
|
|
77
|
+
return str.slice(0, maxLength - 1) + '…';
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Shorten file path for display (cross-platform)
|
|
81
|
+
* Shows only the last few path components
|
|
82
|
+
* @param filePath - Full file path
|
|
83
|
+
* @returns Shortened path with forward slashes for consistent display
|
|
84
|
+
*/
|
|
85
|
+
function shortenPath(filePath) {
|
|
86
|
+
const normalized = path.normalize(filePath);
|
|
87
|
+
const parts = normalized.split(path.sep);
|
|
88
|
+
// Show last 4 components: .../skills/component-name/SKILL.md
|
|
89
|
+
if (parts.length > 4) {
|
|
90
|
+
return '.../' + parts.slice(-4).join('/');
|
|
91
|
+
}
|
|
92
|
+
return parts.join('/');
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Truncate multi-line content to fit within height
|
|
96
|
+
* @param content - Full content string
|
|
97
|
+
* @param maxLines - Maximum number of lines
|
|
98
|
+
* @returns Truncated content
|
|
99
|
+
*/
|
|
100
|
+
function truncateContent(content, maxLines) {
|
|
101
|
+
const lines = content.split('\n');
|
|
102
|
+
if (lines.length <= maxLines) {
|
|
103
|
+
return content;
|
|
104
|
+
}
|
|
105
|
+
return lines.slice(0, maxLines).join('\n') + '\n...';
|
|
106
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ComponentList component
|
|
3
|
+
* Displays detailed plugin components in a collapsible list format
|
|
4
|
+
* Shows component names when available, falls back to counts
|
|
5
|
+
*
|
|
6
|
+
* Data Source Architecture:
|
|
7
|
+
* - Installed plugins: Names + descriptions from file system scan
|
|
8
|
+
* - Not installed: Names only from marketplace JSON (if available)
|
|
9
|
+
* - Fallback: Count-only display from PluginComponents
|
|
10
|
+
*/
|
|
11
|
+
import type { ComponentInfo, PluginComponents, PluginComponentsDetailed } from '../types/index.js';
|
|
12
|
+
/**
|
|
13
|
+
* Flattened component item for selection tracking
|
|
14
|
+
* Combines type and info for easy navigation
|
|
15
|
+
*/
|
|
16
|
+
export interface FlatComponentItem {
|
|
17
|
+
/** Component info */
|
|
18
|
+
info: ComponentInfo;
|
|
19
|
+
/** Category label */
|
|
20
|
+
category: string;
|
|
21
|
+
/** Category color */
|
|
22
|
+
color: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Props for ComponentList
|
|
26
|
+
*/
|
|
27
|
+
export interface ComponentListProps {
|
|
28
|
+
/** Component counts (backward compat fallback) */
|
|
29
|
+
components?: PluginComponents;
|
|
30
|
+
/** Detailed component info with names */
|
|
31
|
+
componentsDetailed?: PluginComponentsDetailed;
|
|
32
|
+
/** Maximum visible items per category (default: 3) */
|
|
33
|
+
maxItems?: number;
|
|
34
|
+
/** Whether this list is focused for selection */
|
|
35
|
+
isFocused?: boolean;
|
|
36
|
+
/** Currently selected index in flattened list */
|
|
37
|
+
selectedIndex?: number;
|
|
38
|
+
/** Callback when selection changes */
|
|
39
|
+
onSelect?: (item: FlatComponentItem, index: number) => void;
|
|
40
|
+
/** Number of visible items in virtual scroll viewport (default: 5) */
|
|
41
|
+
visibleCount?: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Flatten all components from detailed info into a single array for selection
|
|
45
|
+
* @param componentsDetailed - Detailed component info
|
|
46
|
+
* @returns Array of FlatComponentItem for navigation
|
|
47
|
+
* @example
|
|
48
|
+
* flattenComponents({ skills: [{ name: 'xlsx', type: 'skill' }] })
|
|
49
|
+
* // => [{ info: { name: 'xlsx', type: 'skill' }, category: 'Skills', color: 'magenta' }]
|
|
50
|
+
*/
|
|
51
|
+
export declare function flattenComponents(componentsDetailed?: PluginComponentsDetailed): FlatComponentItem[];
|
|
52
|
+
/**
|
|
53
|
+
* Displays component details in a collapsible list
|
|
54
|
+
* Shows names when available, falls back to counts
|
|
55
|
+
* Supports selection mode when isFocused is true
|
|
56
|
+
* Uses virtual scrolling when focused to prevent layout overflow
|
|
57
|
+
* @param props - ComponentListProps
|
|
58
|
+
* @returns React node or null if no components
|
|
59
|
+
* @example
|
|
60
|
+
* <ComponentList
|
|
61
|
+
* componentsDetailed={{ skills: [{ name: 'xlsx', type: 'skill' }] }}
|
|
62
|
+
* maxItems={3}
|
|
63
|
+
* isFocused={true}
|
|
64
|
+
* selectedIndex={0}
|
|
65
|
+
* visibleCount={5}
|
|
66
|
+
* />
|
|
67
|
+
*/
|
|
68
|
+
export default function ComponentList({ components, componentsDetailed, maxItems, isFocused, selectedIndex, visibleCount, }: ComponentListProps): React.ReactNode;
|
|
69
|
+
/**
|
|
70
|
+
* Check if PluginComponentsDetailed has any data
|
|
71
|
+
* @param detailed - Detailed components object
|
|
72
|
+
* @returns true if any category has items
|
|
73
|
+
* @example
|
|
74
|
+
* hasAnyDetailedComponents({ skills: [{ name: 'xlsx', type: 'skill' }] }) // => true
|
|
75
|
+
* hasAnyDetailedComponents({}) // => false
|
|
76
|
+
*/
|
|
77
|
+
export declare function hasAnyDetailedComponents(detailed: PluginComponentsDetailed): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Check if PluginComponents has any count data
|
|
80
|
+
* @param components - Components counts object
|
|
81
|
+
* @returns true if any category has count > 0
|
|
82
|
+
* @example
|
|
83
|
+
* hasAnyCountComponents({ skills: 5 }) // => true
|
|
84
|
+
* hasAnyCountComponents({ hooks: true }) // => true
|
|
85
|
+
* hasAnyCountComponents({}) // => false
|
|
86
|
+
*/
|
|
87
|
+
export declare function hasAnyCountComponents(components: PluginComponents): boolean;
|