diff --git a/sidepanel/sidepanel.css b/sidepanel/sidepanel.css index cc4022d..1cb4cce 100644 --- a/sidepanel/sidepanel.css +++ b/sidepanel/sidepanel.css @@ -1,26 +1,82 @@ -/* sidepanel/sidepanel.css */ +/* ============================================================ + MultiPage Automation — Side Panel Theme + Design: Dark OLED / Developer Tool + Font: Inter (UI) + JetBrains Mono (code/data) + Colors: Blue primary (#2563EB), Green success (#22C55E), + Orange warning (#F97316), Red error (#EF4444) + ============================================================ */ + +:root { + --bg-base: #0a0a0b; + --bg-surface: #141416; + --bg-elevated: #1c1c20; + --bg-hover: #252529; + --bg-active: #2a2a30; + + --border: #2a2a30; + --border-subtle: #1e1e22; + + --text-primary: #e8e8ed; + --text-secondary: #8b8b96; + --text-muted: #5c5c66; + + --blue: #2563eb; + --blue-glow: rgba(37, 99, 235, 0.15); + --green: #22c55e; + --green-glow: rgba(34, 197, 94, 0.12); + --orange: #f97316; + --orange-glow: rgba(249, 115, 22, 0.12); + --red: #ef4444; + --red-glow: rgba(239, 68, 68, 0.12); + --cyan: #06b6d4; + --purple: #a78bfa; + + --radius-sm: 6px; + --radius-md: 8px; + --radius-lg: 10px; + + --transition: 150ms ease; +} + * { margin: 0; padding: 0; box-sizing: border-box; } body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; font-size: 13px; - color: #333; - background: #f8f9fa; + color: var(--text-primary); + background: var(--bg-base); padding: 12px; width: 100%; min-height: 100vh; + -webkit-font-smoothing: antialiased; } +/* ============================================================ + Header + ============================================================ */ + header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; + padding-bottom: 12px; + border-bottom: 1px solid var(--border-subtle); } -header h1 { - font-size: 15px; - font-weight: 600; +.header-title { + display: flex; + align-items: center; + gap: 8px; + color: var(--text-primary); +} + +.header-title svg { color: var(--blue); } + +.header-title h1 { + font-size: 14px; + font-weight: 700; + letter-spacing: -0.02em; } .header-btns { @@ -28,195 +84,382 @@ header h1 { gap: 6px; } -#btn-reset { - padding: 4px 10px; - font-size: 12px; - background: #dc3545; - color: #fff; - border: none; - border-radius: 4px; - cursor: pointer; -} -#btn-reset:hover { background: #c82333; } +/* ============================================================ + Buttons + ============================================================ */ -.btn-auto { - padding: 4px 10px; - font-size: 12px; - background: #28a745; - color: #fff; - border: none; - border-radius: 4px; - cursor: pointer; - font-weight: 600; -} -.btn-auto:hover { background: #218838; } -.btn-auto:disabled { background: #6c757d; cursor: not-allowed; } - -.auto-continue-bar { - margin-top: 8px; - padding: 8px; - background: #fff3cd; - border: 1px solid #ffc107; - border-radius: 4px; - display: flex; +.btn { + display: inline-flex; align-items: center; - gap: 8px; -} - -.auto-hint { - font-size: 11px; - color: #856404; - flex: 1; -} - -.btn-continue { - padding: 4px 12px; + gap: 5px; + padding: 6px 12px; + font-family: inherit; font-size: 12px; - background: #007bff; - color: #fff; - border: none; - border-radius: 4px; - cursor: pointer; font-weight: 600; + border: none; + border-radius: var(--radius-sm); + cursor: pointer; + transition: all var(--transition); white-space: nowrap; } -.btn-continue:hover { background: #0069d9; } -/* Data Section */ -#data-section { - background: #fff; - border: 1px solid #dee2e6; - border-radius: 6px; - padding: 10px; - margin-bottom: 12px; +.btn-primary { + background: var(--blue); + color: #fff; +} +.btn-primary:hover { background: #3b82f6; box-shadow: 0 0 12px var(--blue-glow); } + +.btn-success { + background: var(--green); + color: #fff; +} +.btn-success:hover { background: #16a34a; box-shadow: 0 0 12px var(--green-glow); } +.btn-success:disabled { background: var(--bg-elevated); color: var(--text-muted); cursor: not-allowed; box-shadow: none; } + +.btn-ghost { + background: transparent; + color: var(--text-secondary); + padding: 6px 8px; +} +.btn-ghost:hover { background: var(--bg-hover); color: var(--text-primary); } + +.btn-sm { padding: 4px 10px; font-size: 11px; } +.btn-xs { padding: 2px 8px; font-size: 10px; } + +/* ============================================================ + Data Card + ============================================================ */ + +#data-section { margin-bottom: 12px; } + +.data-card { + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius-md); + padding: 10px 12px; + display: flex; + flex-direction: column; + gap: 8px; } .data-row { display: flex; align-items: center; - margin-bottom: 6px; + gap: 8px; } -.data-row:last-child { margin-bottom: 0; } -.data-row label { - width: 80px; +.data-label { + width: 56px; + font-size: 11px; font-weight: 600; - font-size: 12px; - color: #666; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.04em; flex-shrink: 0; } .data-value { - font-size: 12px; - color: #999; - word-break: break-all; + font-size: 11px; + color: var(--text-secondary); + min-width: 0; } -.data-value.has-value { - color: #333; +.data-value.has-value { color: var(--text-primary); } + +.mono { + font-family: 'JetBrains Mono', 'Consolas', monospace; + font-size: 10.5px; } -#input-email { +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.data-input { flex: 1; - padding: 4px 8px; - border: 1px solid #ced4da; - border-radius: 4px; - font-size: 12px; + padding: 5px 8px; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + color: var(--text-primary); + font-family: 'JetBrains Mono', monospace; + font-size: 11px; + outline: none; + transition: border-color var(--transition); + min-width: 0; +} +.data-input::placeholder { color: var(--text-muted); } +.data-input:focus { border-color: var(--blue); box-shadow: 0 0 0 2px var(--blue-glow); } + +/* Status Bar */ +.status-bar { + display: flex; + align-items: center; + gap: 8px; + margin-top: 8px; + padding: 6px 10px; + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + font-size: 11px; + color: var(--text-secondary); } -/* Steps Section */ -#steps-section { - margin-bottom: 12px; +.status-dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--text-muted); + flex-shrink: 0; +} + +.status-bar.running .status-dot { + background: var(--orange); + animation: pulse 1.5s ease-in-out infinite; +} + +.status-bar.completed .status-dot { background: var(--green); } +.status-bar.failed .status-dot { background: var(--red); } + +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.3; } +} + +/* Auto Continue Bar */ +.auto-continue-bar { + margin-top: 8px; + padding: 8px 10px; + background: var(--orange-glow); + border: 1px solid rgba(249, 115, 22, 0.25); + border-radius: var(--radius-sm); + display: flex; + align-items: center; + gap: 8px; +} + +.auto-continue-bar svg { color: var(--orange); flex-shrink: 0; } + +.auto-hint { + font-size: 11px; + color: var(--orange); + flex: 1; +} + +/* ============================================================ + Steps Section + ============================================================ */ + +#steps-section { margin-bottom: 12px; } + +.steps-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; +} + +.section-label { + font-size: 11px; + font-weight: 600; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.06em; +} + +.steps-progress { + font-family: 'JetBrains Mono', monospace; + font-size: 11px; + color: var(--text-muted); +} + +.steps-list { + display: flex; + flex-direction: column; + gap: 3px; } .step-row { display: flex; align-items: center; gap: 8px; - margin-bottom: 4px; + padding: 2px 0; + transition: opacity var(--transition); +} + +/* Step Number Indicator */ +.step-indicator { + width: 22px; + height: 22px; + border-radius: 50%; + background: var(--bg-elevated); + border: 1.5px solid var(--border); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + transition: all var(--transition); } .step-num { - width: 20px; - text-align: center; + font-size: 10px; font-weight: 600; - font-size: 12px; - color: #666; + color: var(--text-muted); } +/* Step states via indicator */ +.step-row.running .step-indicator { + border-color: var(--orange); + background: var(--orange-glow); + animation: pulse 1.5s ease-in-out infinite; +} +.step-row.running .step-num { color: var(--orange); } + +.step-row.completed .step-indicator { + border-color: var(--green); + background: var(--green-glow); +} +.step-row.completed .step-num { color: var(--green); } + +.step-row.failed .step-indicator { + border-color: var(--red); + background: var(--red-glow); +} +.step-row.failed .step-num { color: var(--red); } + +/* Step Button */ .step-btn { flex: 1; padding: 6px 10px; + font-family: inherit; font-size: 12px; - background: #007bff; - color: #fff; - border: none; - border-radius: 4px; + font-weight: 500; + color: var(--text-primary); + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius-sm); cursor: pointer; text-align: left; + transition: all var(--transition); } -.step-btn:hover:not(:disabled) { background: #0069d9; } + +.step-btn:hover:not(:disabled) { + background: var(--bg-hover); + border-color: var(--blue); +} + .step-btn:disabled { - background: #ccc; + color: var(--text-muted); + background: var(--bg-base); + border-color: var(--border-subtle); cursor: not-allowed; + opacity: 0.5; } +.step-row.running .step-btn { + border-color: var(--orange); + color: var(--orange); +} + +.step-row.completed .step-btn { + border-color: var(--border-subtle); + color: var(--text-secondary); +} + +.step-row.failed .step-btn { + border-color: var(--red); + color: var(--red); +} + +/* Step Status Icon (right side) */ .step-status { - width: 24px; + width: 20px; text-align: center; - font-size: 14px; + font-size: 12px; + flex-shrink: 0; } -/* Log Section */ -#log-section h2 { - font-size: 13px; - font-weight: 600; +/* ============================================================ + Log Section + ============================================================ */ + +.log-header { + display: flex; + justify-content: space-between; + align-items: center; margin-bottom: 6px; } #log-area { - background: #1e1e1e; - color: #d4d4d4; - font-family: 'Consolas', 'Courier New', monospace; - font-size: 11px; - line-height: 1.5; - padding: 8px; - border-radius: 6px; - height: 250px; + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius-md); + padding: 8px 10px; + height: 220px; overflow-y: auto; - white-space: pre-wrap; - word-break: break-all; + font-family: 'JetBrains Mono', 'Consolas', monospace; + font-size: 10.5px; + line-height: 1.65; + color: var(--text-secondary); } -.log-info { color: #d4d4d4; } -.log-ok { color: #4ec9b0; font-weight: bold; } -.log-warn { color: #dcdcaa; } -.log-error { color: #f44747; font-weight: bold; } +#log-area::-webkit-scrollbar { width: 4px; } +#log-area::-webkit-scrollbar-track { background: transparent; } +#log-area::-webkit-scrollbar-thumb { background: var(--bg-hover); border-radius: 4px; } +#log-area::-webkit-scrollbar-thumb:hover { background: var(--text-muted); } + +/* Log line styles */ +.log-line { padding: 1px 0; } +.log-line + .log-line { border-top: 1px solid var(--border-subtle); } + +.log-time { color: var(--text-muted); } + +.log-level { font-weight: 600; } +.log-level-info { color: var(--blue); } +.log-level-ok { color: var(--green); } +.log-level-warn { color: var(--orange); } +.log-level-error { color: var(--red); } .log-step-tag { display: inline-block; - background: #3a3d41; - color: #569cd6; - border-radius: 3px; padding: 0 4px; - margin-right: 4px; - font-weight: bold; - font-size: 10px; + border-radius: 3px; + font-weight: 600; + font-size: 9.5px; + margin-right: 2px; } -.log-step-tag.step-1 { color: #4fc1ff; } -.log-step-tag.step-2 { color: #c586c0; } -.log-step-tag.step-3 { color: #dcdcaa; } -.log-step-tag.step-4 { color: #ce9178; } -.log-step-tag.step-5 { color: #b5cea8; } -.log-step-tag.step-6 { color: #4fc1ff; } -.log-step-tag.step-7 { color: #ce9178; } -.log-step-tag.step-8 { color: #c586c0; } -.log-step-tag.step-9 { color: #b5cea8; } +.log-step-tag.step-1 { color: var(--cyan); background: rgba(6, 182, 212, 0.1); } +.log-step-tag.step-2 { color: var(--purple); background: rgba(167, 139, 250, 0.1); } +.log-step-tag.step-3 { color: #facc15; background: rgba(250, 204, 21, 0.1); } +.log-step-tag.step-4 { color: var(--orange); background: var(--orange-glow); } +.log-step-tag.step-5 { color: var(--green); background: var(--green-glow); } +.log-step-tag.step-6 { color: var(--cyan); background: rgba(6, 182, 212, 0.1); } +.log-step-tag.step-7 { color: var(--orange); background: var(--orange-glow); } +.log-step-tag.step-8 { color: var(--purple); background: rgba(167, 139, 250, 0.1); } +.log-step-tag.step-9 { color: var(--green); background: var(--green-glow); } -.log-time { color: #6a9955; } -.log-level { font-weight: bold; } -.log-level-info { color: #569cd6; } -.log-level-ok { color: #4ec9b0; } -.log-level-warn { color: #dcdcaa; } -.log-level-error { color: #f44747; } +.log-msg { color: var(--text-secondary); } +.log-line.log-ok .log-msg { color: var(--green); } +.log-line.log-error .log-msg { color: var(--red); } +.log-line.log-warn .log-msg { color: var(--orange); } + +/* ============================================================ + Animations + ============================================================ */ + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(4px); } + to { opacity: 1; transform: translateY(0); } +} + +.log-line { animation: fadeIn 150ms ease-out; } + +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + transition-duration: 0.01ms !important; + } +} diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html index 5915d59..dd67350 100644 --- a/sidepanel/sidepanel.html +++ b/sidepanel/sidepanel.html @@ -4,90 +4,117 @@ Multi-Page Automation + + +
-

Multi-Page Automation

+
+ + + +

MultiPage

+
- - + +
-
- - Not obtained +
+
+ OAuth + Waiting... +
+
+ Email + +
+
+ Callback + Waiting... +
-
- - -
-
- - Not captured -
-
- - Waiting +
+
+ Ready
-
- 1 - - +
+ + 0 / 9
-
- 2 - - -
-
- 3 - - -
-
- 4 - - -
-
- 5 - - -
-
- 6 - - -
-
- 7 - - -
-
- 8 - - -
-
- 9 - - +
+
+
1
+ + +
+
+
2
+ + +
+
+
3
+ + +
+
+
4
+ + +
+
+
5
+ + +
+
+
6
+ + +
+
+
7
+ + +
+
+
8
+ + +
+
+
9
+ + +
-

Log

+
+ + +
diff --git a/sidepanel/sidepanel.js b/sidepanel/sidepanel.js index 36947f0..d449ca0 100644 --- a/sidepanel/sidepanel.js +++ b/sidepanel/sidepanel.js @@ -1,18 +1,24 @@ // sidepanel/sidepanel.js — Side Panel logic const STATUS_ICONS = { - pending: '\u2B1A', // ⬚ - running: '\u23F3', // ⏳ - completed: '\u2705', // ✅ - failed: '\u274C', // ❌ + pending: '', + running: '', + completed: '\u2713', // ✓ + failed: '\u2717', // ✗ }; const logArea = document.getElementById('log-area'); const displayOauthUrl = document.getElementById('display-oauth-url'); const displayLocalhostUrl = document.getElementById('display-localhost-url'); const displayStatus = document.getElementById('display-status'); +const statusBar = document.getElementById('status-bar'); const inputEmail = document.getElementById('input-email'); const btnReset = document.getElementById('btn-reset'); +const stepsProgress = document.getElementById('steps-progress'); +const btnAutoRun = document.getElementById('btn-auto-run'); +const btnAutoContinue = document.getElementById('btn-auto-continue'); +const autoContinueBar = document.getElementById('auto-continue-bar'); +const btnClearLog = document.getElementById('btn-clear-log'); // ============================================================ // State Restore on load @@ -22,7 +28,6 @@ async function restoreState() { try { const state = await chrome.runtime.sendMessage({ type: 'GET_STATE', source: 'sidepanel' }); - // Restore data fields if (state.oauthUrl) { displayOauthUrl.textContent = state.oauthUrl; displayOauthUrl.classList.add('has-value'); @@ -35,14 +40,12 @@ async function restoreState() { inputEmail.value = state.email; } - // Restore step statuses if (state.stepStatuses) { for (const [step, status] of Object.entries(state.stepStatuses)) { updateStepUI(Number(step), status); } } - // Restore logs if (state.logs) { for (const entry of state.logs) { appendLog(entry); @@ -50,6 +53,7 @@ async function restoreState() { } updateStatusDisplay(state); + updateProgressCounter(); } catch (err) { console.error('Failed to restore state:', err); } @@ -61,23 +65,36 @@ async function restoreState() { function updateStepUI(step, status) { const statusEl = document.querySelector(`.step-status[data-step="${step}"]`); - if (statusEl) statusEl.textContent = STATUS_ICONS[status] || '\u2B1A'; + const row = document.querySelector(`.step-row[data-step="${step}"]`); + const indicator = document.querySelector(`.step-indicator[data-step="${step}"]`); + + if (statusEl) statusEl.textContent = STATUS_ICONS[status] || ''; + if (row) { + row.className = `step-row ${status}`; + } - // Interlock logic updateButtonStates(); + updateProgressCounter(); +} + +function updateProgressCounter() { + let completed = 0; + document.querySelectorAll('.step-row').forEach(row => { + if (row.classList.contains('completed')) completed++; + }); + stepsProgress.textContent = `${completed} / 9`; } function updateButtonStates() { - // Get all current statuses from DOM const statuses = {}; - document.querySelectorAll('.step-status').forEach(el => { - const step = Number(el.dataset.step); - const icon = el.textContent; - const status = Object.entries(STATUS_ICONS).find(([, v]) => v === icon)?.[0] || 'pending'; - statuses[step] = status; + document.querySelectorAll('.step-row').forEach(row => { + const step = Number(row.dataset.step); + if (row.classList.contains('completed')) statuses[step] = 'completed'; + else if (row.classList.contains('running')) statuses[step] = 'running'; + else if (row.classList.contains('failed')) statuses[step] = 'failed'; + else statuses[step] = 'pending'; }); - // Find if any step is running const anyRunning = Object.values(statuses).some(s => s === 'running'); for (let step = 1; step <= 9; step++) { @@ -85,13 +102,10 @@ function updateButtonStates() { if (!btn) continue; if (anyRunning) { - // When any step is running, disable all buttons btn.disabled = true; } else if (step === 1) { - // Step 1 is always available (unless running) btn.disabled = false; } else { - // Steps 2-9: enabled if previous step completed (or current step failed for retry) const prevStatus = statuses[step - 1]; const currentStatus = statuses[step]; btn.disabled = !(prevStatus === 'completed' || currentStatus === 'failed' || currentStatus === 'completed'); @@ -101,45 +115,53 @@ function updateButtonStates() { function updateStatusDisplay(state) { if (!state || !state.stepStatuses) return; + + statusBar.className = 'status-bar'; + const running = Object.entries(state.stepStatuses).find(([, s]) => s === 'running'); if (running) { displayStatus.textContent = `Step ${running[0]} running...`; - displayStatus.classList.add('has-value'); + statusBar.classList.add('running'); + return; + } + + const failed = Object.entries(state.stepStatuses).find(([, s]) => s === 'failed'); + if (failed) { + displayStatus.textContent = `Step ${failed[0]} failed`; + statusBar.classList.add('failed'); + return; + } + + const lastCompleted = Object.entries(state.stepStatuses) + .filter(([, s]) => s === 'completed') + .map(([k]) => Number(k)) + .sort((a, b) => b - a)[0]; + + if (lastCompleted === 9) { + displayStatus.textContent = 'All steps completed!'; + statusBar.classList.add('completed'); + } else if (lastCompleted) { + displayStatus.textContent = `Step ${lastCompleted} done`; } else { - const lastCompleted = Object.entries(state.stepStatuses) - .filter(([, s]) => s === 'completed') - .map(([k]) => Number(k)) - .sort((a, b) => b - a)[0]; - if (lastCompleted === 9) { - displayStatus.textContent = 'All steps completed!'; - displayStatus.classList.add('has-value'); - } else if (lastCompleted) { - displayStatus.textContent = `Step ${lastCompleted} done. Ready for step ${lastCompleted + 1}.`; - displayStatus.classList.add('has-value'); - } else { - displayStatus.textContent = 'Waiting'; - displayStatus.classList.remove('has-value'); - } + displayStatus.textContent = 'Ready'; } } function appendLog(entry) { const time = new Date(entry.timestamp).toLocaleTimeString('en-US', { hour12: false }); - const levelLabel = entry.level.toUpperCase().padEnd(5); + const levelLabel = entry.level.toUpperCase(); const line = document.createElement('div'); - line.className = `log-${entry.level}`; + line.className = `log-line log-${entry.level}`; - // Extract step number from message (e.g., "Step 4: ..." or "[vps-panel] Step 1: ...") const stepMatch = entry.message.match(/Step (\d)/); const stepNum = stepMatch ? stepMatch[1] : null; - // Build rich HTML let html = `${time} `; - html += `[${levelLabel}] `; + html += `${levelLabel} `; if (stepNum) { html += `S${stepNum}`; } - html += `${escapeHtml(entry.message)}`; + html += `${escapeHtml(entry.message)}`; line.innerHTML = html; logArea.appendChild(line); @@ -159,37 +181,23 @@ function escapeHtml(text) { document.querySelectorAll('.step-btn').forEach(btn => { btn.addEventListener('click', async () => { const step = Number(btn.dataset.step); - - // Save email if step 3 and email input has value if (step === 3) { const email = inputEmail.value.trim(); if (!email) { appendLog({ message: 'Please paste email address first', level: 'error', timestamp: Date.now() }); return; } - await chrome.runtime.sendMessage({ - type: 'EXECUTE_STEP', - source: 'sidepanel', - payload: { step, email }, - }); + await chrome.runtime.sendMessage({ type: 'EXECUTE_STEP', source: 'sidepanel', payload: { step, email } }); } else { - await chrome.runtime.sendMessage({ - type: 'EXECUTE_STEP', - source: 'sidepanel', - payload: { step }, - }); + await chrome.runtime.sendMessage({ type: 'EXECUTE_STEP', source: 'sidepanel', payload: { step } }); } }); }); -// Auto Run button -const btnAutoRun = document.getElementById('btn-auto-run'); -const btnAutoContinue = document.getElementById('btn-auto-continue'); -const autoContinueBar = document.getElementById('auto-continue-bar'); - +// Auto Run btnAutoRun.addEventListener('click', async () => { btnAutoRun.disabled = true; - btnAutoRun.textContent = 'Running...'; + btnAutoRun.innerHTML = ' Running...'; await chrome.runtime.sendMessage({ type: 'AUTO_RUN', source: 'sidepanel' }); }); @@ -200,44 +208,41 @@ btnAutoContinue.addEventListener('click', async () => { return; } autoContinueBar.style.display = 'none'; - btnAutoRun.textContent = 'Running...'; - await chrome.runtime.sendMessage({ - type: 'RESUME_AUTO_RUN', - source: 'sidepanel', - payload: { email }, - }); + await chrome.runtime.sendMessage({ type: 'RESUME_AUTO_RUN', source: 'sidepanel', payload: { email } }); }); -// Reset button +// Reset btnReset.addEventListener('click', async () => { if (confirm('Reset all steps and data?')) { await chrome.runtime.sendMessage({ type: 'RESET', source: 'sidepanel' }); - // Clear UI - displayOauthUrl.textContent = 'Not obtained'; + displayOauthUrl.textContent = 'Waiting...'; displayOauthUrl.classList.remove('has-value'); - displayLocalhostUrl.textContent = 'Not captured'; + displayLocalhostUrl.textContent = 'Waiting...'; displayLocalhostUrl.classList.remove('has-value'); inputEmail.value = ''; - displayStatus.textContent = 'Waiting'; - displayStatus.classList.remove('has-value'); + displayStatus.textContent = 'Ready'; + statusBar.className = 'status-bar'; logArea.innerHTML = ''; - document.querySelectorAll('.step-status').forEach(el => el.textContent = '\u2B1A'); + document.querySelectorAll('.step-row').forEach(row => row.className = 'step-row'); + document.querySelectorAll('.step-status').forEach(el => el.textContent = ''); btnAutoRun.disabled = false; - btnAutoRun.textContent = 'Auto Run'; + btnAutoRun.innerHTML = ' Auto'; autoContinueBar.style.display = 'none'; updateButtonStates(); + updateProgressCounter(); } }); -// Save email when user types/pastes +// Clear log +btnClearLog.addEventListener('click', () => { + logArea.innerHTML = ''; +}); + +// Save email on change inputEmail.addEventListener('change', async () => { const email = inputEmail.value.trim(); if (email) { - await chrome.runtime.sendMessage({ - type: 'SAVE_EMAIL', - source: 'sidepanel', - payload: { email }, - }); + await chrome.runtime.sendMessage({ type: 'SAVE_EMAIL', source: 'sidepanel', payload: { email } }); } }); @@ -254,8 +259,19 @@ chrome.runtime.onMessage.addListener((message) => { case 'STEP_STATUS_CHANGED': { const { step, status } = message.payload; updateStepUI(step, status); - // Update status display chrome.runtime.sendMessage({ type: 'GET_STATE', source: 'sidepanel' }).then(updateStatusDisplay); + if (status === 'completed') { + chrome.runtime.sendMessage({ type: 'GET_STATE', source: 'sidepanel' }).then(state => { + if (state.oauthUrl) { + displayOauthUrl.textContent = state.oauthUrl; + displayOauthUrl.classList.add('has-value'); + } + if (state.localhostUrl) { + displayLocalhostUrl.textContent = state.localhostUrl; + displayLocalhostUrl.classList.add('has-value'); + } + }); + } break; } @@ -276,16 +292,16 @@ chrome.runtime.onMessage.addListener((message) => { switch (phase) { case 'waiting_email': autoContinueBar.style.display = 'flex'; - btnAutoRun.textContent = 'Waiting...'; + btnAutoRun.innerHTML = ' Paused'; break; case 'complete': btnAutoRun.disabled = false; - btnAutoRun.textContent = 'Auto Run'; + btnAutoRun.innerHTML = ' Auto'; autoContinueBar.style.display = 'none'; break; case 'stopped': btnAutoRun.disabled = false; - btnAutoRun.textContent = 'Auto Run'; + btnAutoRun.innerHTML = ' Auto'; autoContinueBar.style.display = 'none'; break; }