UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

235 lines 8.15 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ContextMenu = void 0; const blessed_1 = __importDefault(require("blessed")); class ContextMenu { constructor(screen, eventBus) { this.isVisible = false; this.selectedIndex = 0; this.menuItems = []; this.screen = screen; this.eventBus = eventBus; } show(config) { if (this.isVisible) { this.hide(); } this.currentConfig = config; this.menuItems = config.items.filter(item => item.enabled !== false); this.selectedIndex = 0; if (this.menuItems.length === 0) { return; } this.createMenuBox(config); if (this.menuBox) { this.isVisible = true; this.eventBus.emit('contextmenu:shown', { x: config.x, y: config.y, context: config.context, componentId: config.componentId, itemCount: this.menuItems.length, timestamp: new Date(), }); } } hide() { if (!this.isVisible || !this.menuBox) return; try { this.screen.remove(this.menuBox); this.menuBox = null; this.isVisible = false; this.selectedIndex = 0; this.menuItems = []; this.screen.render(); this.eventBus.emit('contextmenu:hidden', { timestamp: new Date(), }); } catch (error) { console.error('Failed to hide context menu:', error); this.menuBox = null; this.isVisible = false; } } navigateUp() { if (!this.isVisible || this.menuItems.length === 0) return; this.selectedIndex = this.selectedIndex === 0 ? this.menuItems.length - 1 : this.selectedIndex - 1; this.updateMenuDisplay(); } navigateDown() { if (!this.isVisible || this.menuItems.length === 0) return; this.selectedIndex = (this.selectedIndex + 1) % this.menuItems.length; this.updateMenuDisplay(); } selectItem() { if (!this.isVisible || this.menuItems.length === 0) return; const selectedItem = this.menuItems[this.selectedIndex]; if (selectedItem) { this.executeAction(selectedItem); this.hide(); } } isContextMenuVisible() { return this.isVisible; } getSelectedIndex() { return this.selectedIndex; } createMenuBox(config) { try { const content = this.generateMenuContent(); const { adjustedX, adjustedY } = this.calculatePosition(config.x, config.y); const menuWidth = this.calculateMenuWidth(); const menuHeight = this.menuItems.length + 2; this.menuBox = blessed_1.default.box({ left: adjustedX, top: adjustedY, width: menuWidth, height: menuHeight, content, tags: true, border: { type: 'line', }, style: { fg: config.style?.fg || 'white', bg: config.style?.bg || 'black', border: { fg: config.style?.border?.fg || 'gray', bg: config.style?.border?.bg || 'black', }, }, keys: true, mouse: true, }); this.setupMenuEvents(); this.screen.append(this.menuBox); this.menuBox.focus(); this.screen.render(); } catch (error) { console.error('Failed to create context menu:', error); this.isVisible = false; this.menuBox = null; } } setupMenuEvents() { if (!this.menuBox) return; this.menuBox.key(['up', 'k'], () => { this.navigateUp(); }); this.menuBox.key(['down', 'j'], () => { this.navigateDown(); }); this.menuBox.key(['enter', 'space'], () => { this.selectItem(); }); this.menuBox.key(['escape', 'q'], () => { this.hide(); }); this.menuBox.on('click', (data) => { if (data && typeof data.y === 'number') { const clickedIndex = data.y - 1; if (clickedIndex >= 0 && clickedIndex < this.menuItems.length) { this.selectedIndex = clickedIndex; this.selectItem(); } } }); if (this.currentConfig?.autoHide !== false) { this.screen.on('click', () => { setTimeout(() => { if (this.isVisible) { this.hide(); } }, 50); }); } } generateMenuContent() { const lines = []; this.menuItems.forEach((item, index) => { const isSelected = index === this.selectedIndex; const icon = item.icon ? `${item.icon} ` : ''; const shortcut = item.shortcut ? ` {gray-fg}${item.shortcut}{/gray-fg}` : ''; let line = `${icon}${item.label}${shortcut}`; if (isSelected) { const selectedFg = this.currentConfig?.style?.selectedFg || 'black'; const selectedBg = this.currentConfig?.style?.selectedBg || 'white'; line = `{${selectedBg}-bg}{${selectedFg}-fg}${line}{/${selectedFg}-fg}{/${selectedBg}-bg}`; } lines.push(line); if (item.separator && index < this.menuItems.length - 1) { lines.push('{gray-fg}─'.repeat(this.calculateMenuWidth() - 4) + '{/gray-fg}'); } }); return lines.join('\n'); } updateMenuDisplay() { if (!this.menuBox) return; try { const content = this.generateMenuContent(); this.menuBox.setContent(content); this.screen.render(); } catch (error) { console.error('Failed to update menu display:', error); } } calculateMenuWidth() { let maxWidth = 20; this.menuItems.forEach(item => { const iconLength = item.icon ? item.icon.length + 1 : 0; const shortcutLength = item.shortcut ? item.shortcut.length + 1 : 0; const itemWidth = iconLength + item.label.length + shortcutLength + 4; maxWidth = Math.max(maxWidth, itemWidth); }); return Math.min(maxWidth, 60); } calculatePosition(x, y) { const screenWidth = this.screen.width || 80; const screenHeight = this.screen.height || 24; const menuWidth = this.calculateMenuWidth(); const menuHeight = this.menuItems.length + 2; let adjustedX = x; let adjustedY = y; if (adjustedX + menuWidth > screenWidth) { adjustedX = Math.max(0, x - menuWidth); } if (adjustedY + menuHeight > screenHeight) { adjustedY = Math.max(0, y - menuHeight); } return { adjustedX, adjustedY }; } executeAction(item) { this.eventBus.emit('contextmenu:action', { action: item.action, label: item.label, context: this.currentConfig?.context, componentId: this.currentConfig?.componentId, timestamp: new Date(), }); this.eventBus.emit(`action:${item.action}`, { context: this.currentConfig?.context, componentId: this.currentConfig?.componentId, source: 'contextmenu', }); } destroy() { this.hide(); } } exports.ContextMenu = ContextMenu; //# sourceMappingURL=context-menu.js.map