diff --git a/server.js b/server.js index 394f1c3..4067004 100644 --- a/server.js +++ b/server.js @@ -183,10 +183,17 @@ app.get(['/widget.js', BASE + '/widget.js'], (req, res) => { .fb-picker-btn { background:#1a2a1a; border:1px solid #2a4a2a; color:#6fcf6f; font-size:.78rem; padding:.4rem .7rem; border-radius:6px; cursor:pointer; white-space:nowrap; flex-shrink:0; } .fb-picker-btn:hover { background:#223322; } - .fb-picker-hint { color:#444; font-size:.75rem; } - .fb-snippet-preview { background:#0a0a0a; border:1px solid #2a2a2a; border-radius:6px; - padding:.5rem .7rem; font-size:.72rem; color:#7c9ef5; font-family:monospace; - white-space:pre-wrap; word-break:break-all; max-height:80px; overflow-y:auto; } + /* Picked-elements chip list */ + #_fb-picked-list { display:flex; flex-wrap:wrap; gap:.4rem; } + #_fb-picked-list:empty { display:none; } + .fb-picked-chip { display:inline-flex; align-items:center; gap:.35rem; background:#0d1f0d; + border:1px solid #2a4a2a; border-radius:6px; padding:.28rem .55rem; font-size:.75rem; + color:#6fcf6f; font-family:monospace; } + .fb-chip-num { color:#4a9f4a; font-weight:700; } + .fb-chip-label { color:#aaa; max-width:140px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; } + .fb-chip-remove { background:none; border:none; color:#555; cursor:pointer; font-size:.7rem; + padding:0; line-height:1; } + .fb-chip-remove:hover { color:#f57c7c; } /* Picker overlay */ #_fb-picker-shield { display:none; position:fixed; inset:0; z-index:199999; cursor:crosshair; } #_fb-picker-shield.active { display:block; } @@ -240,11 +247,8 @@ app.get(['/widget.js', BASE + '/widget.js'], (req, res) => {
- Click to reference a page element -
- +
@@ -302,7 +306,8 @@ app.get(['/widget.js', BASE + '/widget.js'], (req, res) => { // ── Picker mode ─────────────────────────────────────────────────────────── var pickerActive = false; var pickerHighlighted = null; - var capturedSnippet = ''; + var nextPickNum = 1; + var pickedElements = {}; // { [num]: { selector, snippet } } function getSelector(el) { if (!el || el === document.body) return 'body'; @@ -332,7 +337,30 @@ app.get(['/widget.js', BASE + '/widget.js'], (req, res) => { toast.classList.add('active'); } - function deactivatePicker(snippet) { + function insertAtCursor(ta, text) { + var start = ta.selectionStart != null ? ta.selectionStart : ta.value.length; + var end = ta.selectionEnd != null ? ta.selectionEnd : ta.value.length; + ta.value = ta.value.slice(0, start) + text + ta.value.slice(end); + ta.selectionStart = ta.selectionEnd = start + text.length; + } + + function addPickedChip(num, selector, snippet) { + var list = document.getElementById('_fb-picked-list'); + var chip = document.createElement('span'); + chip.className = 'fb-picked-chip'; + chip.dataset.num = num; + chip.innerHTML = + '[' + num + ']' + + '' + esc(selector) + '' + + ''; + chip.querySelector('.fb-chip-remove').addEventListener('click', function() { + delete pickedElements[num]; + chip.remove(); + }); + list.appendChild(chip); + } + + function deactivatePicker(snippet, selector) { pickerActive = false; shield.classList.remove('active'); toast.classList.remove('active'); @@ -342,14 +370,14 @@ app.get(['/widget.js', BASE + '/widget.js'], (req, res) => { } overlay.classList.add('open'); if (snippet) { - capturedSnippet = snippet; - document.getElementById('_fb-snippet').textContent = snippet; - document.getElementById('_fb-snippet-wrap').style.display = ''; - document.getElementById('_fb-pick-hint').textContent = 'βœ“ Element captured β€” you can pick again'; - // Append to description + var num = nextPickNum++; + pickedElements[num] = { selector: selector, snippet: snippet }; + addPickedChip(num, selector, snippet); + // Insert reference token at cursor in the textarea var desc = document.getElementById('_fb-desc'); - var tag = '\\n\\n**Picked element:**\\n\`\`\`html\\n' + snippet + '\\n\`\`\`'; - if (!desc.value.includes(tag)) desc.value += tag; + var token = '[element ' + num + ']'; + insertAtCursor(desc, token); + desc.focus(); } } @@ -383,15 +411,15 @@ app.get(['/widget.js', BASE + '/widget.js'], (req, res) => { shield.style.display = ''; if (el && !el.closest('#_fb-picker-toast')) { el.classList.remove('_fb-hover-highlight'); - deactivatePicker(getSnippet(el)); + deactivatePicker(getSnippet(el), getSelector(el)); } else { - deactivatePicker(null); + deactivatePicker(null, null); } }); // Esc cancels picker document.addEventListener('keydown', function(e) { - if (e.key === 'Escape' && pickerActive) deactivatePicker(null); + if (e.key === 'Escape' && pickerActive) deactivatePicker(null, null); }); // ── Submit ──────────────────────────────────────────────────────────────── @@ -403,9 +431,16 @@ app.get(['/widget.js', BASE + '/widget.js'], (req, res) => { var btn = document.getElementById('_fb-submit'); if (!title) { status.style.color='#f57c7c'; status.textContent='Title is required.'; return; } btn.disabled = true; status.style.color='#888'; status.textContent='Submitting…'; + // Append element snippets as a reference block + var snippetBlock = ''; + Object.keys(pickedElements).forEach(function(num) { + var pe = pickedElements[num]; + snippetBlock += '\\n\\n**[element ' + num + ']** `' + pe.selector + '`\\n\`\`\`html\\n' + pe.snippet + '\\n\`\`\`'; + }); + var fullBody = body + snippetBlock; fetch(SELF + '/api/feedback', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ title, body, repo: cfg.repo, source_url: window.location.href, assignee: assignee || undefined }) + body: JSON.stringify({ title, body: fullBody, repo: cfg.repo, source_url: window.location.href, assignee: assignee || undefined }) }).then(function(r) { return r.json(); }).then(function(d) { if (d.ok) { status.style.color='#6fcf6f'; @@ -413,9 +448,9 @@ app.get(['/widget.js', BASE + '/widget.js'], (req, res) => { document.getElementById('_fb-title').value = ''; document.getElementById('_fb-desc').value = ''; document.getElementById('_fb-assignee').value = ''; - document.getElementById('_fb-snippet-wrap').style.display = 'none'; - document.getElementById('_fb-pick-hint').textContent = 'Click to reference a page element'; - capturedSnippet = ''; + document.getElementById('_fb-picked-list').innerHTML = ''; + nextPickNum = 1; + pickedElements = {}; btn.disabled = false; setTimeout(function() { status.textContent=''; }, 3000); } else {