| class CustomCommandPanel extends HTMLElement { |
| constructor() { |
| super(); |
| this.isOpen = false; |
| } |
| |
| connectedCallback() { |
| this.attachShadow({ mode: 'open' }); |
| this.render(); |
| this.setupEventListeners(); |
| } |
| |
| render() { |
| this.shadowRoot.innerHTML = ` |
| <style> |
| :host { |
| display: block; |
| position: relative; |
| } |
| |
| .panel-toggle { |
| position: fixed; |
| right: 0; |
| top: 50%; |
| transform: translateY(-50%); |
| background: #0ea5e9; |
| color: white; |
| padding: 1rem 0.5rem; |
| border-radius: 0.5rem 0 0 0.5rem; |
| writing-mode: vertical-rl; |
| cursor: pointer; |
| z-index: 40; |
| transition: all 0.3s ease; |
| box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1); |
| font-weight: 600; |
| font-size: 0.875rem; |
| } |
| |
| .panel-toggle:hover { |
| background: #0284c7; |
| padding-right: 0.75rem; |
| } |
| |
| .command-panel { |
| position: fixed; |
| right: 0; |
| top: 0; |
| height: 100vh; |
| width: 400px; |
| background: white; |
| border-left: 1px solid #e5e7eb; |
| box-shadow: -4px 0 16px rgba(0, 0, 0, 0.1); |
| transform: translateX(100%); |
| transition: transform 0.3s ease-in-out; |
| z-index: 50; |
| display: flex; |
| flex-direction: column; |
| } |
| |
| .panel-open { |
| transform: translateX(0); |
| } |
| |
| .panel-header { |
| padding: 1rem 1.5rem; |
| border-bottom: 1px solid #e5e7eb; |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| } |
| |
| .panel-title { |
| font-size: 1.25rem; |
| font-weight: 600; |
| color: #1f2937; |
| } |
| |
| .close-button { |
| background: none; |
| border: none; |
| font-size: 1.5rem; |
| cursor: pointer; |
| color: #6b7280; |
| padding: 0.25rem; |
| border-radius: 0.25rem; |
| } |
| |
| .close-button:hover { |
| background: #f3f4f6; |
| } |
| |
| .search-container { |
| padding: 1rem 1.5rem; |
| border-bottom: 1px solid #e5e7eb; |
| } |
| |
| .search-input { |
| width: 100%; |
| padding: 0.75rem 1rem; |
| border: 1px solid #d1d5db; |
| border-radius: 0.5rem; |
| font-size: 0.875rem; |
| focus:outline-none; |
| focus:ring-2; |
| focus:ring-primary-500; |
| focus:border-primary-500; |
| } |
| |
| .search-input:focus { |
| outline: none; |
| border-color: #0ea5e9; |
| box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1); |
| } |
| |
| .content-area { |
| flex: 1; |
| overflow-y: auto; |
| padding: 1rem 1.5rem; |
| } |
| |
| .section { |
| margin-bottom: 1.5rem; |
| } |
| |
| .section-title { |
| font-size: 0.875rem; |
| font-weight: 600; |
| color: #374151; |
| margin-bottom: 0.75rem; |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| } |
| |
| .command-list { |
| list-style: none; |
| } |
| |
| .command-item { |
| padding: 0.75rem 1rem; |
| border-radius: 0.5rem; |
| cursor: pointer; |
| margin-bottom: 0.25rem; |
| display: flex; |
| align-items: center; |
| transition: all 0.2s ease; |
| } |
| |
| .command-item:hover { |
| background: #f9fafb; |
| } |
| |
| .command-icon { |
| width: 20px; |
| height: 20px; |
| margin-right: 0.75rem; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| } |
| |
| .command-text { |
| flex: 1; |
| } |
| |
| .command-name { |
| font-weight: 500; |
| color: #1f2937; |
| margin-bottom: 0.125rem; |
| } |
| |
| .command-desc { |
| font-size: 0.75rem; |
| color: #6b7280; |
| } |
| |
| .badge { |
| background: #eff6ff; |
| color: #1d4ed8; |
| padding: 0.125rem 0.5rem; |
| border-radius: 9999px; |
| font-size: 0.75rem; |
| font-weight: 500; |
| } |
| |
| .context-suggestions { |
| background: #f0f9ff; |
| border-radius: 0.5rem; |
| padding: 1rem; |
| margin-top: 1rem; |
| } |
| |
| .suggestion-title { |
| font-size: 0.875rem; |
| font-weight: 600; |
| color: #0369a1; |
| margin-bottom: 0.5rem; |
| } |
| |
| .suggestion-list { |
| list-style: none; |
| } |
| |
| .suggestion-item { |
| padding: 0.5rem; |
| border-radius: 0.25rem; |
| cursor: pointer; |
| font-size: 0.875rem; |
| color: #0369a1; |
| transition: background 0.2s ease; |
| } |
| |
| .suggestion-item:hover { |
| background: #e0f2fe; |
| } |
| </style> |
| <div class="panel-toggle" id="toggle-button"> |
| CMD |
| </div> |
| <div class="command-panel" id="command-panel"> |
| <div class="panel-header"> |
| <div class="panel-title">Command Center</div> |
| <button class="close-button" id="close-button">Γ</button> |
| </div> |
| <div class="search-container"> |
| <input type="text" class="search-input" placeholder="Search commands... Ctrl+K" id="search-input"> |
| </div> |
| <div class="content-area"> |
| <div class="section"> |
| <div class="section-title"> |
| <span>β± Recent Commands</span> |
| </div> |
| <ul class="command-list"> |
| <li class="command-item"> |
| <div class="command-icon">π</div> |
| <div class="command-text"> |
| <div class="command-name">/task create "API integration" @john</div> |
| </div> |
| </li> |
| <li class="command-item"> |
| <div class="command-icon">βοΈ</div> |
| <div class="command-text"> |
| <div class="command-name">/bulk assign sprint:Q1-3 to:@alice</div> |
| </div> |
| </li> |
| <li class="command-item"> |
| <div class="command-icon">ποΈ</div> |
| <div class="command-text"> |
| <div class="command-name">/schedule pto @bob from:3/1 to:3/5</div> |
| </div> |
| </li> |
| </ul> |
| </div> |
| |
| <div class="section"> |
| <div class="section-title"> |
| <span>π Command Templates</span> |
| </div> |
| <ul class="command-list"> |
| <li class="command-item"> |
| <div class="command-icon">π</div> |
| <div class="command-text"> |
| <div class="command-name">Create Task</div> |
| <div class="command-desc">Create a new task with specified details</div> |
| </div> |
| </li> |
| <li class="command-item"> |
| <div class="command-icon">βοΈ</div> |
| <div class="command-text"> |
| <div class="command-name">Move Task</div> |
| <div class="command-desc">Move task to different date/assignee</div> |
| </div> |
| </li> |
| <li class="command-item"> |
| <div class="command-icon">π</div> |
| <div class="command-text"> |
| <div class="command-name">Update Status</div> |
| <div class="command-desc">Update task properties</div> |
| </div> |
| </li> |
| <li class="command-item"> |
| <div class="command-icon">ποΈ</div> |
| <div class="command-text"> |
| <div class="command-name">Delete Task</div> |
| <div class="command-desc">Delete specific task</div> |
| </div> |
| </li> |
| <li class="command-item"> |
| <div class="command-icon">ποΈ</div> |
| <div class="command-text"> |
| <div class="command-name">Scheduling (6 commands)</div> |
| </div> |
| </li> |
| <li class="command-item"> |
| <div class="command-icon">π</div> |
| <div class="command-text"> |
| <div class="command-name">Multi-Task Operations (8 commands)</div> |
| </div> |
| </li> |
| </ul> |
| </div> |
| |
| <div class="context-suggestions"> |
| <div class="suggestion-title">π‘ Context Suggestions</div> |
| <div class="suggestion-desc">Based on your selection:</div> |
| <ul class="suggestion-list"> |
| <li class="suggestion-item">β’ Assign 3 selected tasks to...</li> |
| <li class="suggestion-item">β’ Move selection to next sprint</li> |
| <li class="suggestion-item">β’ Mark selected as complete</li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| `; |
| } |
| |
| setupEventListeners() { |
| const toggleButton = this.shadowRoot.getElementById('toggle-button'); |
| const closeButton = this.shadowRoot.getElementById('close-button'); |
| const commandPanel = this.shadowRoot.getElementById('command-panel'); |
| const searchInput = this.shadowRoot.getElementById('search-input'); |
| |
| toggleButton.addEventListener('click', () => { |
| this.togglePanel(); |
| }); |
| |
| closeButton.addEventListener('click', () => { |
| this.closePanel(); |
| }); |
| |
| |
| document.addEventListener('click', (event) => { |
| if (this.isOpen && !commandPanel.contains(event.target) && !toggleButton.contains(event.target)) { |
| this.closePanel(); |
| } |
| }); |
| |
| |
| document.addEventListener('keydown', (event) => { |
| |
| if ((event.ctrlKey || event.metaKey) && event.key === 'k') { |
| event.preventDefault(); |
| this.togglePanel(); |
| } |
| |
| |
| if (event.key === 'Escape' && this.isOpen) { |
| this.closePanel(); |
| } |
| }); |
| |
| |
| searchInput.addEventListener('focus', () => { |
| |
| }); |
| } |
| |
| togglePanel() { |
| this.isOpen = !this.isOpen; |
| const panel = this.shadowRoot.getElementById('command-panel'); |
| const toggleButton = this.shadowRoot.getElementById('toggle-button'); |
| |
| if (this.isOpen) { |
| panel.classList.add('panel-open'); |
| toggleButton.textContent = 'Γ'; |
| } else { |
| panel.classList.remove('panel-open'); |
| toggleButton.textContent = 'CMD'; |
| } |
| } |
| |
| openPanel(template = null) { |
| this.isOpen = true; |
| const panel = this.shadowRoot.getElementById('command-panel'); |
| const toggleButton = this.shadowRoot.getElementById('toggle-button'); |
| |
| panel.classList.add('panel-open'); |
| toggleButton.textContent = 'Γ'; |
| |
| |
| if (template) { |
| this.loadTemplate(template); |
| } |
| } |
| |
| closePanel() { |
| this.isOpen = false; |
| const panel = this.shadowRoot.getElementById('command-panel'); |
| const toggleButton = this.shadowRoot.getElementById('toggle-button'); |
| |
| panel.classList.remove('panel-open'); |
| toggleButton.textContent = 'CMD'; |
| } |
| |
| loadTemplate(templateName) { |
| |
| console.log('Loading template:', templateName); |
| } |
| } |
|
|
| customElements.define('custom-command-panel', CustomCommandPanel); |