// Postman spoof — static-but-believable HTTP client UI. const RESPONSES = { GET: `{ "id": 1, "name": "Alice Freeman", "email": "alice@meridian.dev", "role": "developer", "active": true }`, POST: `{ "id": 42, "name": "New Resource", "created": "2025-03-14T10:30:00Z", "status": "created", "message": "Resource created successfully" }`, PUT: `{ "id": 42, "name": "Updated Resource", "updated": "2025-03-14T10:32:00Z", "status": "updated", "message": "Resource updated successfully" }`, DELETE: `{ "id": 42, "status": "deleted", "message": "Resource deleted successfully" }`, }; const METHODS = ['GET', 'POST', 'PUT', 'DELETE']; export default { id: 'postman', title: 'Postman', render(container, api) { let method = 'GET'; let sending = false; const root = document.createElement('div'); root.style.cssText = 'height:100%;display:flex;flex-direction:column;background:var(--bg-1);'; // Request bar: method select + URL input + Send button const reqBar = document.createElement('div'); reqBar.style.cssText = 'display:flex;align-items:center;gap:0;padding:8px 12px;border-bottom:1px solid var(--border);background:var(--bg-2);flex-shrink:0;'; const methodSelect = document.createElement('select'); methodSelect.style.cssText = 'padding:6px 10px;background:var(--bg-3);border:1px solid var(--border);border-right:none;border-radius:4px 0 0 4px;color:var(--accent);font-weight:600;font-size:13px;outline:none;cursor:pointer;min-width:70px;'; METHODS.forEach((m) => { const opt = document.createElement('option'); opt.value = m; opt.textContent = m; if (m === method) opt.selected = true; methodSelect.appendChild(opt); }); methodSelect.addEventListener('change', () => { method = methodSelect.value; }); const urlInput = document.createElement('input'); urlInput.type = 'text'; urlInput.value = 'https://api.meridian.dev/v1/users'; urlInput.style.cssText = 'flex:1;padding:6px 12px;background:var(--bg-3);border:1px solid var(--border);color:var(--text);font-size:13px;font-family:monospace;outline:none;'; urlInput.placeholder = 'Enter request URL'; const sendBtn = document.createElement('button'); sendBtn.style.cssText = 'padding:6px 20px;background:var(--accent);color:#0f1114;border:none;border-radius:0 4px 4px 0;font-size:13px;font-weight:600;cursor:pointer;'; sendBtn.textContent = 'Send'; sendBtn.addEventListener('click', () => { if (sending) return; sending = true; sendBtn.textContent = 'Sending...'; sendBtn.disabled = true; setTimeout(() => { sendBtn.textContent = 'Send'; sendBtn.disabled = false; sending = false; showResponse(); }, 200); }); reqBar.appendChild(methodSelect); reqBar.appendChild(urlInput); reqBar.appendChild(sendBtn); root.appendChild(reqBar); // Tabs const tabNames = ['Params', 'Headers', 'Body']; let activeTab = 'Params'; const tabBtns = []; const tabBar = document.createElement('div'); tabBar.style.cssText = 'display:flex;gap:0;border-bottom:1px solid var(--border);background:var(--bg-2);flex-shrink:0;'; tabNames.forEach((tab) => { const btn = document.createElement('button'); const isActive = activeTab === tab; btn.style.cssText = 'padding:8px 16px;background:transparent;border:none;border-right:1px solid var(--border);color:' + (isActive ? 'var(--text)' : 'var(--text-dim)') + ';font-size:12px;cursor:pointer;transition:color 150ms;'; btn.textContent = tab; btn.addEventListener('click', () => { activeTab = tab; tabArea.innerHTML = contentPanels[tab]; tabBtns.forEach((b) => { b.style.color = 'var(--text-dim)'; }); btn.style.color = 'var(--text)'; }); tabBtns.push(btn); tabBar.appendChild(btn); }); root.appendChild(tabBar); // Tab content panels const contentPanels = { Params: '
' + '
' + 'Authorization' + '' + '
' + '
' + 'Content-Type' + '' + '
' + '
' + 'X-Request-ID' + '' + '
' + '
', Headers: '
' + '
' + 'User-Agent' + 'MeridianClient/1.0' + '
' + '
' + 'Accept' + 'application/json' + '
' + '
' + 'Cache-Control' + 'no-cache' + '
' + '
', Body: '
' + '' + '
', }; // Build body content separately since it has real JSON const postmanBody = JSON.stringify({ name: 'Alice Freeman', email: 'alice@meridian.dev', role: 'developer' }, null, 2); const tabArea = document.createElement('div'); tabArea.style.cssText = 'flex:1;overflow-y:auto;background:var(--bg-2);'; tabArea.innerHTML = contentPanels[activeTab]; root.appendChild(tabArea); // Response label const respLabel = document.createElement('div'); respLabel.style.cssText = 'padding:8px 12px;font-size:11px;font-weight:600;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.05em;border-bottom:1px solid var(--border);background:var(--bg-2);flex-shrink:0;'; respLabel.textContent = 'Response'; // Response pre const respArea = document.createElement('pre'); respArea.style.cssText = 'flex:1;overflow:auto;padding:12px 16px;margin:0;font-size:12px;line-height:1.6;color:var(--text);font-family:monospace;background:var(--bg-1);'; respArea.textContent = 'Click Send to execute the request'; // Status line const statusLine = document.createElement('div'); statusLine.style.cssText = 'padding:4px 12px;font-size:11px;color:var(--text-dim);border-top:1px solid var(--border);background:var(--bg-2);flex-shrink:0;'; statusLine.textContent = 'Ready'; root.appendChild(respLabel); root.appendChild(respArea); root.appendChild(statusLine); container.appendChild(root); function showResponse() { const resp = RESPONSES[method] || RESPONSES.GET; const time = Math.floor(Math.random() * 60) + 40; const size = resp.length + 2; respArea.textContent = resp; statusLine.textContent = 'Status: 200 OK \u{B7} Time: ' + time + 'ms \u{B7} Size: ' + size + ' B'; } }, };