|
| 1 | +class Plugin { |
| 2 | + constructor(workspace) { |
| 3 | + this.workspace = workspace; |
| 4 | + this.containerId = 'debug-plugin-container'; |
| 5 | + } |
| 6 | + |
| 7 | + async onload() { |
| 8 | + console.log('Debug & Internal Editor Plugin loaded'); |
| 9 | + this.createUI(); |
| 10 | + } |
| 11 | + |
| 12 | + createUI() { |
| 13 | + // UIコンテナの作成 |
| 14 | + const container = document.createElement('div'); |
| 15 | + container.id = this.containerId; |
| 16 | + container.className = 'fixed bottom-4 right-4 z-[200] flex flex-col gap-2'; |
| 17 | + |
| 18 | + // メインボタン |
| 19 | + const toggleBtn = document.createElement('button'); |
| 20 | + toggleBtn.innerHTML = '🛠️ Debug'; |
| 21 | + toggleBtn.className = 'bg-slate-800 text-white px-4 py-2 rounded-full shadow-lg font-bold hover:bg-slate-700 transition-all'; |
| 22 | + toggleBtn.onclick = () => this.togglePanel(); |
| 23 | + |
| 24 | + // パネル |
| 25 | + const panel = document.createElement('div'); |
| 26 | + panel.id = 'debug-panel'; |
| 27 | + panel.className = 'hidden w-[500px] h-[600px] bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl shadow-2xl flex flex-col overflow-hidden'; |
| 28 | + panel.innerHTML = ` |
| 29 | + <div class="flex items-center justify-between px-4 py-3 border-b border-slate-100 dark:border-slate-800 bg-slate-50 dark:bg-slate-950"> |
| 30 | + <span class="font-bold text-sm">Debug & Internal Editor</span> |
| 31 | + <button id="debug-panel-close" class="text-slate-400 hover:text-slate-600">✕</button> |
| 32 | + </div> |
| 33 | + <div class="flex border-b border-slate-100 dark:border-slate-800"> |
| 34 | + <button id="tab-editor" class="flex-1 py-2 text-xs font-bold border-b-2 border-indigo-500 text-indigo-500">Editor</button> |
| 35 | + <button id="tab-logs" class="flex-1 py-2 text-xs font-bold text-slate-400 hover:text-slate-600">System Logs</button> |
| 36 | + <button id="tab-glossary" class="flex-1 py-2 text-xs font-bold text-slate-400 hover:text-slate-600">Glossary</button> |
| 37 | + </div> |
| 38 | + <div id="debug-content" class="flex-1 overflow-hidden flex flex-col p-4"> |
| 39 | + <!-- Content will be injected here --> |
| 40 | + </div> |
| 41 | + `; |
| 42 | + |
| 43 | + container.appendChild(panel); |
| 44 | + container.appendChild(toggleBtn); |
| 45 | + document.body.appendChild(container); |
| 46 | + |
| 47 | + panel.querySelector('#debug-panel-close').onclick = () => this.togglePanel(); |
| 48 | + panel.querySelector('#tab-editor').onclick = () => this.showEditor(); |
| 49 | + panel.querySelector('#tab-logs').onclick = () => this.showLogs(); |
| 50 | + panel.querySelector('#tab-glossary').onclick = () => this.showGlossary(); |
| 51 | + |
| 52 | + this.showEditor(); |
| 53 | + } |
| 54 | + |
| 55 | + togglePanel() { |
| 56 | + const panel = document.getElementById('debug-panel'); |
| 57 | + panel.classList.toggle('hidden'); |
| 58 | + } |
| 59 | + |
| 60 | + updateTabs(activeId) { |
| 61 | + const tabs = ['tab-editor', 'tab-logs', 'tab-glossary']; |
| 62 | + tabs.forEach(id => { |
| 63 | + const el = document.getElementById(id); |
| 64 | + if (id === activeId) { |
| 65 | + el.classList.add('border-b-2', 'border-indigo-500', 'text-indigo-500'); |
| 66 | + el.classList.remove('text-slate-400'); |
| 67 | + } else { |
| 68 | + el.classList.remove('border-b-2', 'border-indigo-500', 'text-indigo-500'); |
| 69 | + el.classList.add('text-slate-400'); |
| 70 | + } |
| 71 | + }); |
| 72 | + } |
| 73 | + |
| 74 | + showEditor() { |
| 75 | + this.updateTabs('tab-editor'); |
| 76 | + const content = document.getElementById('debug-content'); |
| 77 | + content.innerHTML = ` |
| 78 | + <p class="text-[11px] text-slate-500 mb-2">プラグインの内部コードをリアルタイムで変更できます(再読み込みで反映)</p> |
| 79 | + <textarea id="internal-editor" class="flex-1 w-full p-3 font-mono text-xs bg-slate-950 text-emerald-400 rounded-lg outline-none border border-slate-800 resize-none"></textarea> |
| 80 | + <div class="mt-3 flex gap-2"> |
| 81 | + <button id="save-internal" class="flex-1 bg-indigo-600 text-white py-2 rounded-lg text-xs font-bold hover:bg-indigo-700">Apply Changes</button> |
| 82 | + </div> |
| 83 | + `; |
| 84 | + |
| 85 | + const editor = document.getElementById('internal-editor'); |
| 86 | + // 現在のプラグインマネージャーから自身の情報を取得 |
| 87 | + const pm = this.workspace.pluginManager; |
| 88 | + if (pm) { |
| 89 | + const myMeta = pm.installedPlugins['debug-editor-plugin']; |
| 90 | + if (myMeta && myMeta.script) { |
| 91 | + editor.value = myMeta.script; |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + document.getElementById('save-internal').onclick = () => { |
| 96 | + if (pm) { |
| 97 | + const myMeta = pm.installedPlugins['debug-editor-plugin']; |
| 98 | + if (myMeta) { |
| 99 | + myMeta.script = editor.value; |
| 100 | + pm.saveInstalledPlugins(); |
| 101 | + alert('プラグインコードを更新しました。再起動後に反映されます。'); |
| 102 | + } |
| 103 | + } |
| 104 | + }; |
| 105 | + } |
| 106 | + |
| 107 | + showLogs() { |
| 108 | + this.updateTabs('tab-logs'); |
| 109 | + const content = document.getElementById('debug-content'); |
| 110 | + content.innerHTML = ` |
| 111 | + <div class="flex flex-col h-full"> |
| 112 | + <div class="flex justify-between items-center mb-2"> |
| 113 | + <span class="text-[11px] font-bold text-slate-500">System Error Codes & Status</span> |
| 114 | + <button id="clear-logs" class="text-[10px] text-red-500 hover:underline">Clear</button> |
| 115 | + </div> |
| 116 | + <div id="log-list" class="flex-1 bg-slate-50 dark:bg-slate-950 rounded-lg p-3 font-mono text-[10px] overflow-y-auto space-y-1"> |
| 117 | + <div class="text-blue-500">[INFO] Workspace initialized.</div> |
| 118 | + <div class="text-blue-500">[INFO] Plugin Manager ready.</div> |
| 119 | + <div class="text-amber-500">[WARN] Slow network detected for Blockly CDN.</div> |
| 120 | + <div class="text-slate-400">[DEBUG] Serializing workspace...</div> |
| 121 | + <div class="text-emerald-500">[SUCCESS] Auto-save completed.</div> |
| 122 | + </div> |
| 123 | + </div> |
| 124 | + `; |
| 125 | + } |
| 126 | + |
| 127 | + showGlossary() { |
| 128 | + this.updateTabs('tab-glossary'); |
| 129 | + const content = document.getElementById('debug-content'); |
| 130 | + content.innerHTML = ` |
| 131 | + <div class="space-y-4 overflow-y-auto h-full pr-2"> |
| 132 | + <div> |
| 133 | + <h4 class="text-xs font-bold text-indigo-500 mb-1">UUID (Universally Unique Identifier)</h4> |
| 134 | + <p class="text-[11px] text-slate-600 dark:text-slate-400">プラグインを一意に識別するための128ビットの識別子。CDMでは開発者名とプラグイン名を元に生成されます。</p> |
| 135 | + </div> |
| 136 | + <div> |
| 137 | + <h4 class="text-xs font-bold text-indigo-500 mb-1">Serialization</h4> |
| 138 | + <p class="text-[11px] text-slate-600 dark:text-slate-400">ワークスペースの状態(ブロックの配置など)を保存可能なデータ形式(JSON等)に変換すること。</p> |
| 139 | + </div> |
| 140 | + <div> |
| 141 | + <h4 class="text-xs font-bold text-indigo-500 mb-1">LZString</h4> |
| 142 | + <p class="text-[11px] text-slate-600 dark:text-slate-400">共有URLを短くするために使用される圧縮アルゴリズム。データをURLセーフな文字列に変換します。</p> |
| 143 | + </div> |
| 144 | + <div> |
| 145 | + <h4 class="text-xs font-bold text-indigo-500 mb-1">Flyout</h4> |
| 146 | + <p class="text-[11px] text-slate-600 dark:text-slate-400">Blocklyでツールボックスのカテゴリをクリックした時に横から出てくるブロック一覧パネルのこと。</p> |
| 147 | + </div> |
| 148 | + <div> |
| 149 | + <h4 class="text-xs font-bold text-indigo-500 mb-1">Shadow Block</h4> |
| 150 | + <p class="text-[11px] text-slate-600 dark:text-slate-400">削除できないプレースホルダー的なブロック。ユーザーが入力を上書きするためのデフォルト値として機能します。</p> |
| 151 | + </div> |
| 152 | + </div> |
| 153 | + `; |
| 154 | + } |
| 155 | + |
| 156 | + async onunload() { |
| 157 | + const container = document.getElementById(this.containerId); |
| 158 | + if (container) container.remove(); |
| 159 | + console.log('Debug & Internal Editor Plugin unloaded'); |
| 160 | + } |
| 161 | +} |
0 commit comments