|
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 | | - # Stop if user already dismissed |
| 15 | + // Stop if user already dismissed |
13 | 16 | if (localStorage.getItem(KEY) === 'true') return; |
14 | 17 |
|
15 | | - # Quick helper |
16 | | - const $ = (tag, css = '') => Object.assign(document.createElement(tag), { style: css }); |
| 18 | + // Quick helper |
| 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 | | - # --- Overlay (blur + dim) --- |
| 34 | + // --- Overlay (blur + dim) --- |
19 | 35 | const overlay = $('div', ` |
20 | 36 | position: fixed; inset: 0; |
21 | 37 | background: rgba(0,0,0,.4); |
|
24 | 40 | z-index: 10000; |
25 | 41 | `); |
26 | 42 |
|
27 | | - # --- Modal --- |
| 43 | + // --- Modal --- |
28 | 44 | const modal = $('div', ` |
29 | 45 | max-width: 90vw; width: 480px; |
30 | 46 | background: #fff; border-radius: 12px; overflow: hidden; |
|
33 | 49 | display: flex; flex-direction: column; align-items: stretch; |
34 | 50 | `); |
35 | 51 |
|
36 | | - # --- Title bar (link + close) --- |
| 52 | + // --- Title bar (link + close) --- |
37 | 53 | const titleBar = $('div', ` |
38 | 54 | position: relative; |
39 | | - padding: 1rem 2.5rem 1rem 1rem; # room for the close button |
| 55 | + padding: 1rem 2.5rem 1rem 1rem; // room for the close button |
40 | 56 | text-align: center; |
41 | 57 | background: #222; color: #fff; |
42 | 58 | font-size: 1.3rem; font-weight: 700; |
|
53 | 69 | link.textContent = TXT; |
54 | 70 | titleBar.appendChild(link); |
55 | 71 |
|
56 | | - # Close "X" (no persistence) |
| 72 | + // Close "X" (no persistence) |
57 | 73 | const closeBtn = $('button', ` |
58 | 74 | position: absolute; top: .25rem; right: .5rem; |
59 | 75 | background: transparent; border: none; |
|
65 | 81 | closeBtn.onclick = () => overlay.remove(); |
66 | 82 | titleBar.appendChild(closeBtn); |
67 | 83 |
|
68 | | - # --- Image --- |
| 84 | + // --- Image --- |
69 | 85 | const img = $('img'); |
70 | 86 | img.src = IMG; img.alt = TXT; img.style.width = '100%'; |
71 | 87 |
|
72 | | - # --- Checkbox row --- |
| 88 | + // --- Checkbox row --- |
73 | 89 | const label = $('label', ` |
74 | 90 | display: flex; align-items: center; justify-content: center; gap: .6rem; |
75 | 91 | padding: 1rem; font-size: 1rem; color: #222; cursor: pointer; |
|
83 | 99 | }; |
84 | 100 | label.append(cb, document.createTextNode("Don't show again")); |
85 | 101 |
|
86 | | - # --- Assemble & inject --- |
| 102 | + // --- Assemble & inject --- |
87 | 103 | modal.append(titleBar, img, label); |
88 | 104 | overlay.appendChild(modal); |
89 | 105 |
|
|
93 | 109 | document.body.appendChild(overlay); |
94 | 110 | } |
95 | 111 | })(); |
96 | | -
|
97 | 112 | */ |
98 | 113 |
|
99 | 114 |
|
100 | | - |
101 | | - |
102 | 115 | /** |
103 | 116 | * HackTricks AI Chat Widget v1.16 – resizable sidebar |
104 | 117 | * --------------------------------------------------- |
105 | 118 | * ❶ Markdown rendering + sanitised (same as before) |
106 | 119 | * ❷ NEW: drag‑to‑resize panel, width persists via localStorage |
107 | 120 | */ |
| 121 | + |
| 122 | + |
| 123 | + |
108 | 124 | (function () { |
109 | | - const LOG = "[HackTricks‑AI]"; |
| 125 | + const LOG = "[HackTricks-AI]"; |
110 | 126 | /* ---------------- User‑tunable constants ---------------- */ |
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 | | - "💡 Highlight any text on the page,\nthen click to ask HackTricks AI about it"; |
| 133 | + "💡 Highlight any text on the page,\nthen click to ask HackTricks AI about it"; |
118 | 134 |
|
119 | 135 | const API_BASE = "https://www.hacktricks.ai/api/assistants/threads"; |
120 | 136 | const BRAND_RED = "#b31328"; |
|
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