dev-tools / dev-tools.js
soiz1's picture
Update dev-tools.js
cd1febc verified
raw
history blame
5.36 kB
// dev-tools.js
document.addEventListener('DOMContentLoaded', () => {
// スタイル定義
const style = document.createElement('style');
style.textContent = `
:root {
--devtools-blue: #1a1c2c;
--neon-blue: #00f3ff;
--dark-layer: rgba(0, 0, 0, 0.9);
}
.devtools-btn {
position: fixed;
bottom: 20px;
right: 20px;
background: var(--devtools-blue);
color: var(--neon-blue);
border: 2px solid var(--neon-blue);
padding: 10px 20px;
cursor: pointer;
border-radius: 5px;
font-family: 'Courier New', monospace;
z-index: 10000;
transition: all 0.3s;
}
.devtools-btn:hover {
box-shadow: 0 0 15px var(--neon-blue);
}
.devtools-panel {
position: fixed;
bottom: 0;
right: 0;
width: 100%;
height: 60vh;
background: var(--dark-layer);
border-top: 3px solid var(--neon-blue);
color: white;
font-family: 'Courier New', monospace;
display: none;
z-index: 9999;
}
.tabs {
display: flex;
background: var(--devtools-blue);
border-bottom: 1px solid var(--neon-blue);
}
.tab {
padding: 10px 20px;
cursor: pointer;
border-right: 1px solid var(--neon-blue);
}
.tab.active {
background: var(--neon-blue);
color: var(--devtools-blue);
}
.panel-content {
padding: 15px;
overflow-y: auto;
height: calc(100% - 50px);
}
.dom-node {
margin-left: 15px;
cursor: pointer;
}
.dom-node::before {
content: '▶';
margin-right: 5px;
transition: transform 0.2s;
}
.dom-node.expanded::before {
transform: rotate(90deg);
}
.console-input {
width: 100%;
background: transparent;
border: 1px solid var(--neon-blue);
color: white;
padding: 5px;
margin-top: 10px;
}
.console-log {
white-space: pre-wrap;
color: var(--neon-blue);
}
`;
document.head.appendChild(style);
// 開発者ツール起動ボタン
const openBtn = document.createElement('button');
openBtn.className = 'devtools-btn';
openBtn.textContent = '🛠 Open DevTools';
document.body.appendChild(openBtn);
// 開発者ツールパネル
const panel = document.createElement('div');
panel.className = 'devtools-panel';
// タブインターフェイス
const tabs = ['Console', 'Elements', 'Styles'].map(name => {
const tab = document.createElement('div');
tab.className = 'tab';
tab.textContent = name;
return tab;
});
const tabContent = document.createElement('div');
tabContent.className = 'panel-content';
// コンソールタブ
const consoleInput = document.createElement('input');
consoleInput.className = 'console-input';
consoleInput.placeholder = 'Enter JavaScript...';
const consoleLog = document.createElement('pre');
consoleLog.className = 'console-log';
// ログキャプチャ
const originalConsoleLog = console.log;
console.log = (...args) => {
originalConsoleLog(...args);
consoleLog.textContent += args.join(' ') + '\n';
};
// DOMインスペクタ
function createDOMTree(node, depth = 0) {
const element = document.createElement('div');
element.className = 'dom-node';
element.textContent = node.nodeName.toLowerCase();
if (node.childNodes.length > 0) {
node.childNodes.forEach(child => {
if (child.nodeType === Node.ELEMENT_NODE) {
element.appendChild(createDOMTree(child, depth + 1));
}
});
}
element.addEventListener('click', (e) => {
e.stopPropagation();
element.classList.toggle('expanded');
});
return element;
}
// タブ切り替え
tabs.forEach((tab, index) => {
tab.addEventListener('click', () => {
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
tabContent.innerHTML = '';
switch(index) {
case 0:
tabContent.appendChild(consoleLog);
tabContent.appendChild(consoleInput);
break;
case 1:
tabContent.appendChild(createDOMTree(document.documentElement));
break;
}
});
});
// パネル構成
panel.appendChild(tabs.reduce((container, tab) => {
container.appendChild(tab);
return container;
}, document.createElement('div')));
panel.appendChild(tabContent);
// イベントハンドラ
openBtn.addEventListener('click', () => {
panel.style.display = 'block';
tabs[0].click();
});
consoleInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
try {
eval(e.target.value);
} catch (err) {
console.log('Error:', err);
}
e.target.value = '';
}
});
document.body.appendChild(panel);
});