|
5 | 5 |
|
6 | 6 | (() => { |
7 | 7 | const KEY = 'htSummerDiscountsDismissed'; |
8 | | - const IMG = '/images/discount.jpeg'; |
| 8 | + const IMG = '/ima * HackTricks AI Chat Widget v1.17 – enhanced resizable sidebar |
| 9 | + * --------------------------------------------------- |
| 10 | + * ❶ Markdown rendering + sanitised (same as before) |
| 11 | + * ❷ ENHANCED: improved drag‑to‑resize panel with better UXdiscount.jpeg'; |
9 | 12 | const TXT = 'Click here for HT Summer Discounts, Last Days!'; |
10 | 13 | const URL = 'https://training.hacktricks.xyz'; |
11 | 14 |
|
12 | 15 | // Stop if user already dismissed |
13 | 16 | if (localStorage.getItem(KEY) === 'true') return; |
14 | 17 |
|
15 | 18 | // Quick helper |
16 | | - const $ = (tag, css = '') => Object.assign(document.createElement(tag), { style: css }); |
| 19 | + const $ = (tag, css = '') => Object.assign(document.cr p.innerHTML = ` |
| 20 | + <div id="ht-ai-header"> |
| 21 | + <strong>HackTricks AI Chat</strong> |
| 22 | + <span style="font-size:11px;opacity:0.6;margin-left:8px;">↔ Drag edge to resize</span> |
| 23 | + <div class="ht-actions"> |
| 24 | + <button id="ht-ai-reset" title="Reset">↺</button> |
| 25 | + <span id="ht-ai-close" title="Close">✖</span> |
| 26 | + </div> |
| 27 | + </div> |
| 28 | + <div id="ht-ai-chat"></div> |
| 29 | + <div id="ht-ai-input"> |
| 30 | + <textarea id="ht-ai-question" placeholder="Type your question…"></textarea> |
| 31 | + <button id="ht-ai-send">Send</button> |
| 32 | + </div>`;tag), { style: css }); |
17 | 33 |
|
18 | 34 | // --- Overlay (blur + dim) --- |
19 | 35 | const overlay = $('div', ` |
|
111 | 127 | const MAX_CONTEXT = 3000; // highlighted‑text char limit |
112 | 128 | const MAX_QUESTION = 500; // question char limit |
113 | 129 | const MIN_W = 250; // ← resize limits → |
114 | | - const MAX_W = 600; |
| 130 | + const MAX_W = 800; |
115 | 131 | const DEF_W = 350; // default width (if nothing saved) |
116 | 132 | const TOOLTIP_TEXT = |
117 | 133 | "💡 Highlight any text on the page,\nthen click to ask HackTricks AI about it"; |
|
345 | 361 | #ht-ai-panel{position:fixed;top:0;right:0;height:100%;max-width:90vw;background:#000;color:#fff;display:flex;flex-direction:column;transform:translateX(100%);transition:transform .3s ease;z-index:100000;font-family:system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue",Arial,sans-serif} |
346 | 362 | #ht-ai-panel.open{transform:translateX(0)} |
347 | 363 | @media(max-width:768px){#ht-ai-panel{display:none}} |
348 | | -#ht-ai-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid #333} |
349 | | -#ht-ai-header .ht-actions{display:flex;gap:8px;align-items:center} |
| 364 | +#ht-ai-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid #333;flex-wrap:wrap} |
| 365 | +#ht-ai-header strong{flex-shrink:0} |
| 366 | +#ht-ai-header .ht-actions{display:flex;gap:8px;align-items:center;margin-left:auto} |
350 | 367 | #ht-ai-close,#ht-ai-reset{cursor:pointer;font-size:18px;background:none;border:none;color:#fff;padding:0} |
351 | 368 | #ht-ai-close:hover,#ht-ai-reset:hover{opacity:.7} |
352 | 369 | #ht-ai-chat{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;font-size:14px} |
|
367 | 384 | ::selection{background:#ffeb3b;color:#000} |
368 | 385 | ::-moz-selection{background:#ffeb3b;color:#000} |
369 | 386 | /* NEW: resizer handle */ |
370 | | -#ht-ai-resizer{position:absolute;left:0;top:0;width:6px;height:100%;cursor:ew-resize;background:transparent} |
371 | | -#ht-ai-resizer:hover{background:rgba(255,255,255,.05)}`; |
| 387 | +#ht-ai-resizer{position:absolute;left:0;top:0;width:8px;height:100%;cursor:ew-resize;background:rgba(255,255,255,.08);border-right:1px solid rgba(255,255,255,.15);transition:background .2s ease} |
| 388 | +#ht-ai-resizer:hover{background:rgba(255,255,255,.15);border-right:1px solid rgba(255,255,255,.3)} |
| 389 | +#ht-ai-resizer:active{background:rgba(255,255,255,.25)} |
| 390 | +#ht-ai-resizer::before{content:'';position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:2px;height:20px;background:rgba(255,255,255,.4);border-radius:1px}`; |
372 | 391 | const s = document.createElement("style"); |
373 | 392 | s.id = "ht-ai-style"; |
374 | 393 | s.textContent = css; |
|
432 | 451 |
|
433 | 452 | const onMove = (e) => { |
434 | 453 | if (!dragging) return; |
435 | | - const dx = startX - e.clientX; // dragging leftwards ⇒ +dx |
| 454 | + e.preventDefault(); |
| 455 | + const clientX = e.clientX || (e.touches && e.touches[0].clientX); |
| 456 | + const dx = startX - clientX; // dragging leftwards ⇒ +dx |
436 | 457 | let newW = startW + dx; |
437 | 458 | newW = Math.min(Math.max(newW, MIN_W), MAX_W); |
438 | 459 | panel.style.width = newW + "px"; |
439 | 460 | }; |
| 461 | + |
440 | 462 | const onUp = () => { |
441 | 463 | if (!dragging) return; |
442 | 464 | dragging = false; |
| 465 | + handle.style.background = ""; |
| 466 | + document.body.style.userSelect = ""; |
| 467 | + document.body.style.cursor = ""; |
443 | 468 | localStorage.setItem("htAiWidth", parseInt(panel.style.width, 10)); |
444 | 469 | document.removeEventListener("mousemove", onMove); |
445 | 470 | document.removeEventListener("mouseup", onUp); |
| 471 | + document.removeEventListener("touchmove", onMove); |
| 472 | + document.removeEventListener("touchend", onUp); |
446 | 473 | }; |
447 | | - handle.addEventListener("mousedown", (e) => { |
| 474 | + |
| 475 | + const onStart = (e) => { |
| 476 | + e.preventDefault(); |
448 | 477 | dragging = true; |
449 | | - startX = e.clientX; |
| 478 | + startX = e.clientX || (e.touches && e.touches[0].clientX); |
450 | 479 | startW = parseInt(window.getComputedStyle(panel).width, 10); |
| 480 | + handle.style.background = "rgba(255,255,255,.25)"; |
| 481 | + document.body.style.userSelect = "none"; |
| 482 | + document.body.style.cursor = "ew-resize"; |
| 483 | + |
451 | 484 | document.addEventListener("mousemove", onMove); |
452 | 485 | document.addEventListener("mouseup", onUp); |
453 | | - }); |
| 486 | + document.addEventListener("touchmove", onMove, { passive: false }); |
| 487 | + document.addEventListener("touchend", onUp); |
| 488 | + }; |
| 489 | + |
| 490 | + handle.addEventListener("mousedown", onStart); |
| 491 | + handle.addEventListener("touchstart", onStart, { passive: false }); |
454 | 492 | } |
455 | 493 | })(); |
0 commit comments