Spaces:
Running
Running
Update templates/index.html
Browse files- templates/index.html +60 -9
templates/index.html
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
<!doctype html>
|
2 |
<html lang="en">
|
3 |
<head>
|
@@ -63,7 +64,7 @@
|
|
63 |
ol{ padding-left: 22px; }
|
64 |
ol li{ margin: 12px 0; }
|
65 |
a{ color: var(--accent2); }
|
66 |
-
.muted{ color
|
67 |
|
68 |
/* Sidebar: full merged text */
|
69 |
.sidebar-backdrop{ position: fixed; inset: 0; background: rgba(0,0,0,.35); opacity:0; pointer-events:none; transition:.18s ease; z-index:60; }
|
@@ -74,8 +75,22 @@
|
|
74 |
.sbar-hdr h3{ margin:0; font-size:16px; }
|
75 |
.sbar-body{ overflow:auto; padding:16px; }
|
76 |
.smallbtn{ font-size:12px; padding:6px 8px; border-radius:10px; background:#1a213f; color:#dbe2ff; border:1px solid #ffffff18; cursor:pointer; }
|
|
|
77 |
pre#fullText{ margin:0; white-space:pre-wrap; word-wrap:break-word; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; line-height:1.5; }
|
78 |
mark#centerMark{ background:#61e7ff55; padding:0 .5px; border-radius:3px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
</style>
|
80 |
</head>
|
81 |
<body>
|
@@ -170,10 +185,29 @@
|
|
170 |
{% for r in results %}
|
171 |
<li>
|
172 |
<p>{{ r.text }}</p>
|
173 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
</li>
|
175 |
{% endfor %}
|
176 |
</ol>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
{% endif %}
|
178 |
</div>
|
179 |
</section>
|
@@ -279,8 +313,9 @@
|
|
279 |
btnClose.addEventListener('click', closeSidebar);
|
280 |
backdrop.addEventListener('click', closeSidebar);
|
281 |
|
282 |
-
|
283 |
-
|
|
|
284 |
|
285 |
function escapeHtml(s){
|
286 |
return s.replaceAll('&','&')
|
@@ -305,14 +340,11 @@
|
|
305 |
const after = escapeHtml(merged.slice(end));
|
306 |
pre.innerHTML = before + '<mark id="centerMark">' + middle + '</mark>' + after;
|
307 |
|
308 |
-
//
|
309 |
requestAnimationFrame(() => {
|
310 |
const mark = document.getElementById('centerMark');
|
311 |
if(mark){
|
312 |
-
|
313 |
-
const bodyRect = sidebarBody.getBoundingClientRect();
|
314 |
-
const offset = (rect.top + rect.height/2) - (bodyRect.top + bodyRect.height/2);
|
315 |
-
sidebarBody.scrollBy({ top: offset, behavior: 'smooth' });
|
316 |
}
|
317 |
});
|
318 |
}
|
@@ -326,6 +358,25 @@
|
|
326 |
alert('Error: ' + err.message);
|
327 |
}
|
328 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
329 |
</script>
|
330 |
</body>
|
331 |
</html>
|
|
|
1 |
+
<!-- templates/index.html -->
|
2 |
<!doctype html>
|
3 |
<html lang="en">
|
4 |
<head>
|
|
|
64 |
ol{ padding-left: 22px; }
|
65 |
ol li{ margin: 12px 0; }
|
66 |
a{ color: var(--accent2); }
|
67 |
+
.muted{ color:#b7c0ffcc; font-size:13px; }
|
68 |
|
69 |
/* Sidebar: full merged text */
|
70 |
.sidebar-backdrop{ position: fixed; inset: 0; background: rgba(0,0,0,.35); opacity:0; pointer-events:none; transition:.18s ease; z-index:60; }
|
|
|
75 |
.sbar-hdr h3{ margin:0; font-size:16px; }
|
76 |
.sbar-body{ overflow:auto; padding:16px; }
|
77 |
.smallbtn{ font-size:12px; padding:6px 8px; border-radius:10px; background:#1a213f; color:#dbe2ff; border:1px solid #ffffff18; cursor:pointer; }
|
78 |
+
|
79 |
pre#fullText{ margin:0; white-space:pre-wrap; word-wrap:break-word; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; line-height:1.5; }
|
80 |
mark#centerMark{ background:#61e7ff55; padding:0 .5px; border-radius:3px; }
|
81 |
+
|
82 |
+
/* New: results toolbuttons + file label */
|
83 |
+
.tools{ display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-top:6px; }
|
84 |
+
.iconbtn{
|
85 |
+
display:inline-flex; align-items:center; justify-content:center;
|
86 |
+
width:28px; height:28px; border-radius:8px; border:1px solid #ffffff18;
|
87 |
+
background:#1a213f; color:#e6ecff; cursor:pointer; font-size:14px;
|
88 |
+
}
|
89 |
+
.filetag{
|
90 |
+
display:inline-flex; align-items:center; gap:6px;
|
91 |
+
padding:4px 8px; border-radius:999px; border:1px solid #ffffff18;
|
92 |
+
background:#0d1333; color:#cfe1ff; font-size:12px;
|
93 |
+
}
|
94 |
</style>
|
95 |
</head>
|
96 |
<body>
|
|
|
185 |
{% for r in results %}
|
186 |
<li>
|
187 |
<p>{{ r.text }}</p>
|
188 |
+
<div class="tools">
|
189 |
+
<button type="button" class="smallbtn" onclick="openContext({{ r.idx }})" title="Open full context sidebar">π View context</button>
|
190 |
+
|
191 |
+
<!-- Clipboard icon: copies the 2nd line of the source file -->
|
192 |
+
<button type="button" class="iconbtn" onclick="copySecond({{ r.idx }}, this)" title="Copy 2nd line of this file">π</button>
|
193 |
+
|
194 |
+
<!-- File name label -->
|
195 |
+
<span class="filetag">π {{ r.file }}</span>
|
196 |
+
</div>
|
197 |
</li>
|
198 |
{% endfor %}
|
199 |
</ol>
|
200 |
+
|
201 |
+
<!-- Provide per-paragraph metadata for JS (2nd line + filename) -->
|
202 |
+
<script>
|
203 |
+
window.PARA_META = {};
|
204 |
+
{% for r in results %}
|
205 |
+
PARA_META[{{ r.idx }}] = {
|
206 |
+
second: {{ r.second_line | tojson }},
|
207 |
+
file: {{ r.file | tojson }}
|
208 |
+
};
|
209 |
+
{% endfor %}
|
210 |
+
</script>
|
211 |
{% endif %}
|
212 |
</div>
|
213 |
</section>
|
|
|
313 |
btnClose.addEventListener('click', closeSidebar);
|
314 |
backdrop.addEventListener('click', closeSidebar);
|
315 |
|
316 |
+
// Instant jumps for top/bottom
|
317 |
+
jumpTop.addEventListener('click', () => { sidebarBody.scrollTop = 0; });
|
318 |
+
jumpBottom.addEventListener('click', () => { sidebarBody.scrollTop = sidebarBody.scrollHeight; });
|
319 |
|
320 |
function escapeHtml(s){
|
321 |
return s.replaceAll('&','&')
|
|
|
340 |
const after = escapeHtml(merged.slice(end));
|
341 |
pre.innerHTML = before + '<mark id="centerMark">' + middle + '</mark>' + after;
|
342 |
|
343 |
+
// Instantly jump to the highlight
|
344 |
requestAnimationFrame(() => {
|
345 |
const mark = document.getElementById('centerMark');
|
346 |
if(mark){
|
347 |
+
mark.scrollIntoView({ block: 'center', inline: 'nearest' });
|
|
|
|
|
|
|
348 |
}
|
349 |
});
|
350 |
}
|
|
|
358 |
alert('Error: ' + err.message);
|
359 |
}
|
360 |
}
|
361 |
+
|
362 |
+
// Clipboard: copy the 2nd line of the source file for this paragraph
|
363 |
+
window.copySecond = function(idx, btn){
|
364 |
+
try{
|
365 |
+
const meta = window.PARA_META?.[idx];
|
366 |
+
if(!meta){ throw new Error("Missing metadata"); }
|
367 |
+
const text = meta.second || "";
|
368 |
+
navigator.clipboard.writeText(text).then(() => {
|
369 |
+
// simple visual feedback
|
370 |
+
const old = btn.textContent;
|
371 |
+
btn.textContent = 'β
';
|
372 |
+
setTimeout(()=>{ btn.textContent = 'π'; }, 900);
|
373 |
+
}, () => {
|
374 |
+
alert("Clipboard copy failed");
|
375 |
+
});
|
376 |
+
}catch(e){
|
377 |
+
alert("Clipboard error: " + e.message);
|
378 |
+
}
|
379 |
+
}
|
380 |
</script>
|
381 |
</body>
|
382 |
</html>
|