Spaces:
Running
Running
Delete static
#4
by MohsenAltayar2311 - opened
- static/app.js +0 -1020
- static/chat.js +0 -759
- static/css/_chat.css +0 -144
- static/css/_chatbot.css +0 -170
- static/css/_dark.css +0 -194
- static/css/_examples.css +0 -142
- static/css/_hide.css +0 -131
- static/css/_input.css +0 -114
- static/css/_layout.css +0 -41
- static/css/_legacy.css +0 -50
- static/css/_math.css +0 -132
- static/css/_misc.css +0 -111
- static/css/_modals.css +0 -266
- static/css/_perf.css +0 -50
- static/css/_thinking.css +0 -35
- static/css/_typing.css +0 -29
- static/css/_variables.css +0 -81
- static/vendor/highlight/LICENSE +0 -29
- static/vendor/highlight/github-dark.min.css +0 -10
- static/vendor/highlight/github.min.css +0 -18
- static/vendor/highlight/highlight.min.js +0 -0
- static/vendor/katex/LICENSE +0 -27
- static/vendor/katex/auto-render.min.js +0 -1
- static/vendor/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- static/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- static/vendor/katex/fonts/OFL.txt +0 -98
- static/vendor/katex/katex.min.css +0 -1
- static/vendor/katex/katex.min.js +0 -0
- static/vendor/marked/LICENSE +0 -60
- static/vendor/marked/marked.min.js +0 -8
static/app.js
DELETED
|
@@ -1,1020 +0,0 @@
|
|
| 1 |
-
/* eslint-disable */
|
| 2 |
-
/**
|
| 3 |
-
* Gradio app bootstrap.
|
| 4 |
-
*
|
| 5 |
-
* The Python side injects window.HY_EXAMPLES / window.HY_I18N before this
|
| 6 |
-
* script runs. The custom chat renderer (static/chat.js) owns all DOM
|
| 7 |
-
* mutations under #hy-chat — this file only deals with the surrounding
|
| 8 |
-
* UX (overlay, scroll, send-button state, copy/preview buttons).
|
| 9 |
-
*
|
| 10 |
-
* Responsibilities
|
| 11 |
-
* ────────────────
|
| 12 |
-
* 1. Render the empty-state "What can I help you with?" overlay above the
|
| 13 |
-
* chat surface, with example prompts that auto-send when clicked.
|
| 14 |
-
* 2. Add a "▶ html preview" button below every Markdown HTML code block,
|
| 15 |
-
* and render the code in a sandboxed iframe modal.
|
| 16 |
-
* 3. Add a "Copy" button to the top-right of every <pre> code block.
|
| 17 |
-
* 4. Own scroll behaviour: follow-the-tail while streaming, full user
|
| 18 |
-
* control after streaming ends.
|
| 19 |
-
* 5. OWN the Send-button busy state. The server NEVER toggles the
|
| 20 |
-
* button. Instead, the streaming generators in chat.py drive a
|
| 21 |
-
* dedicated hidden ``gr.HTML`` component (``#hy-busy-marker``):
|
| 22 |
-
* while streaming → it contains a single
|
| 23 |
-
* ``<span data-hy-streaming="1">``; on the final yield → it's
|
| 24 |
-
* idle. We observe that one component and disable Send iff the
|
| 25 |
-
* marker span is present.
|
| 26 |
-
*
|
| 27 |
-
* The marker lives in its OWN component (not inside the chat) so
|
| 28 |
-
* unclosed ``<style>``/``<script>``/``<textarea>``/``<title>``/
|
| 29 |
-
* ``<noscript>`` in model output cannot hijack it.
|
| 30 |
-
*/
|
| 31 |
-
(() => {
|
| 32 |
-
if (window.__HY_APP_INIT) return;
|
| 33 |
-
window.__HY_APP_INIT = true;
|
| 34 |
-
|
| 35 |
-
const EXAMPLES = (window.HY_EXAMPLES || []).slice();
|
| 36 |
-
const BUSY_MSG =
|
| 37 |
-
(window.HY_I18N && window.HY_I18N.model_busy) ||
|
| 38 |
-
"Model is still responding. Please wait for it to finish.";
|
| 39 |
-
|
| 40 |
-
// The chat surface lives at #hy-chat (built by static/chat.js into the
|
| 41 |
-
// value of the gr.HTML at #hy-chat-host). Throughout this file we treat
|
| 42 |
-
// #hy-chat as "the chatbot" — it's our custom replacement.
|
| 43 |
-
const CHAT_SELECTOR = "#hy-chat";
|
| 44 |
-
|
| 45 |
-
// CSS selector for the in-flight streaming marker. See chat.py
|
| 46 |
-
// (HY_BUSY_HTML) for the producer side.
|
| 47 |
-
const BUSY_MARKER_HOST_ID = "hy-busy-marker";
|
| 48 |
-
const STREAM_MARKER_SELECTOR =
|
| 49 |
-
'#' + BUSY_MARKER_HOST_ID + ' [data-hy-streaming="1"]';
|
| 50 |
-
// Explicit "server says idle" marker. Distinct from "no marker yet"
|
| 51 |
-
// (the host's initial empty value), so we can tell apart "still
|
| 52 |
-
// waiting for the first server frame" from "server already responded
|
| 53 |
-
// with idle" (e.g. validation short-circuit before any streaming).
|
| 54 |
-
const IDLE_MARKER_SELECTOR =
|
| 55 |
-
'#' + BUSY_MARKER_HOST_ID + ' [data-hy-busy="0"]';
|
| 56 |
-
|
| 57 |
-
// Set to ``performance.now()`` whenever the user clicks Send / hits Enter.
|
| 58 |
-
// Bridges the brief window between "user dispatched" and "first marker
|
| 59 |
-
// frame arrived" so a fast double-click can't sneak through.
|
| 60 |
-
let lastSendAt = 0;
|
| 61 |
-
const SEND_DEBOUNCE_MS = 400;
|
| 62 |
-
|
| 63 |
-
// Set to true the moment the user dispatches a send, cleared the moment
|
| 64 |
-
// either (a) the server's first busy-marker frame actually arrives, or
|
| 65 |
-
// (b) FIRST_FRAME_TIMEOUT_MS elapses (defensive timeout in case the
|
| 66 |
-
// request never lands — e.g. WebSocket dropped before the first frame).
|
| 67 |
-
//
|
| 68 |
-
// SEND_DEBOUNCE_MS alone is NOT enough: on a slow link the round-trip
|
| 69 |
-
// for the first frame can easily exceed 400ms and a second click slips
|
| 70 |
-
// through, causing two parallel streams (server-side concurrency_limit
|
| 71 |
-
// is 8 for the chat fn so the second request DOES run).
|
| 72 |
-
let awaitingFirstFrame = false;
|
| 73 |
-
const FIRST_FRAME_TIMEOUT_MS = 30 * 1000;
|
| 74 |
-
|
| 75 |
-
// Soft watchdog: if the busy marker is set but the chat DOM has been
|
| 76 |
-
// observably idle for this long AND it's been at least
|
| 77 |
-
// CHAT_IDLE_MIN_SINCE_SEND_MS since the user clicked Send, we force-
|
| 78 |
-
// clear the marker. Safety net for "the server's IDLE marker frame
|
| 79 |
-
// got coalesced/dropped on the wire".
|
| 80 |
-
//
|
| 81 |
-
// CHAT_IDLE_MS MUST be comfortably greater than the server-side
|
| 82 |
-
// ``_HEARTBEAT_INTERVAL`` (5s in core/chat.py). The watchdog is reset
|
| 83 |
-
// on every applied delta — including heartbeats with empty ops — so
|
| 84 |
-
// a healthy stream with periodic heartbeats keeps the timer well
|
| 85 |
-
// below the threshold. The margin guards against jitter in heartbeat
|
| 86 |
-
// arrival (proxy buffering, two-window contention slowing the
|
| 87 |
-
// server's first-content yield, etc.) so the watchdog only fires
|
| 88 |
-
// when the stream is actually dead.
|
| 89 |
-
const CHAT_IDLE_MS = 12000;
|
| 90 |
-
const CHAT_IDLE_MIN_SINCE_SEND_MS = 1500;
|
| 91 |
-
|
| 92 |
-
// Hard absolute cap. Defence-in-depth backstop in case the soft
|
| 93 |
-
// watchdog also fails for some reason.
|
| 94 |
-
const ABSOLUTE_BUSY_TIMEOUT_MS = 5 * 60 * 1000;
|
| 95 |
-
|
| 96 |
-
// Flipped to true on a real send dispatch so the scroll lock knows to
|
| 97 |
-
// re-enter follow mode for the next streaming turn even if the user had
|
| 98 |
-
// scrolled up during the previous turn.
|
| 99 |
-
let justSentNewMessage = false;
|
| 100 |
-
|
| 101 |
-
/* ── Chat mutation hub (rAF-batched) ──────────────────────��────────────
|
| 102 |
-
*
|
| 103 |
-
* The chat DOM gets HAMMERED during streaming: every new token may
|
| 104 |
-
* mutate the trailing streaming segment. With each subsystem
|
| 105 |
-
* (scroll lock, code-block injector, busy-marker timestamp,
|
| 106 |
-
* empty-state visibility) installing its OWN MutationObserver,
|
| 107 |
-
* the per-mutation work multiplied by the number of subsystems
|
| 108 |
-
* was the dominant browser-side cost as conversations grew.
|
| 109 |
-
*
|
| 110 |
-
* We run a single MutationObserver and dispatch to subscribers via
|
| 111 |
-
* requestAnimationFrame. This caps total dispatches at ≤60/sec
|
| 112 |
-
* regardless of how many mutations the chat fires, and lets each
|
| 113 |
-
* subscriber see the WHOLE batch of mutations in one call instead
|
| 114 |
-
* of being woken N times in the same tick.
|
| 115 |
-
*
|
| 116 |
-
* Subscribers MUST be cheap — the rAF callback is on the critical
|
| 117 |
-
* path of the next paint. */
|
| 118 |
-
const chatSubscribers = [];
|
| 119 |
-
let chatPending = null;
|
| 120 |
-
let chatScheduled = false;
|
| 121 |
-
|
| 122 |
-
function subscribeChatMutations(cb) {
|
| 123 |
-
chatSubscribers.push(cb);
|
| 124 |
-
}
|
| 125 |
-
|
| 126 |
-
function startChatMutationHub(chatEl) {
|
| 127 |
-
new MutationObserver((mutations) => {
|
| 128 |
-
if (chatPending === null) chatPending = [];
|
| 129 |
-
// Ref-share the records — they're owned by the observer and we
|
| 130 |
-
// don't mutate them, just iterate.
|
| 131 |
-
for (let i = 0; i < mutations.length; i++) {
|
| 132 |
-
chatPending.push(mutations[i]);
|
| 133 |
-
}
|
| 134 |
-
if (chatScheduled) return;
|
| 135 |
-
chatScheduled = true;
|
| 136 |
-
requestAnimationFrame(() => {
|
| 137 |
-
chatScheduled = false;
|
| 138 |
-
const batch = chatPending;
|
| 139 |
-
chatPending = null;
|
| 140 |
-
for (let i = 0; i < chatSubscribers.length; i++) {
|
| 141 |
-
try {
|
| 142 |
-
chatSubscribers[i](batch);
|
| 143 |
-
} catch (err) {
|
| 144 |
-
console.error("[hy] chat subscriber error:", err);
|
| 145 |
-
}
|
| 146 |
-
}
|
| 147 |
-
});
|
| 148 |
-
}).observe(chatEl, {
|
| 149 |
-
childList: true,
|
| 150 |
-
subtree: true,
|
| 151 |
-
characterData: true,
|
| 152 |
-
});
|
| 153 |
-
}
|
| 154 |
-
|
| 155 |
-
/* ── Empty-state examples overlay ─────────────────────────────────────── */
|
| 156 |
-
function createOverlay() {
|
| 157 |
-
const chatEl = document.querySelector(CHAT_SELECTOR);
|
| 158 |
-
if (!chatEl) {
|
| 159 |
-
setTimeout(createOverlay, 500);
|
| 160 |
-
return;
|
| 161 |
-
}
|
| 162 |
-
if (document.getElementById("examples-overlay")) return;
|
| 163 |
-
|
| 164 |
-
const overlay = document.createElement("div");
|
| 165 |
-
overlay.id = "examples-overlay";
|
| 166 |
-
|
| 167 |
-
const wrapper = document.createElement("div");
|
| 168 |
-
wrapper.className = "examples-wrapper";
|
| 169 |
-
|
| 170 |
-
const heading = document.createElement("p");
|
| 171 |
-
heading.className = "examples-heading";
|
| 172 |
-
heading.textContent =
|
| 173 |
-
(window.HY_I18N && window.HY_I18N.examples_heading) ||
|
| 174 |
-
"What can I help you with?";
|
| 175 |
-
wrapper.appendChild(heading);
|
| 176 |
-
|
| 177 |
-
const grid = document.createElement("div");
|
| 178 |
-
grid.className = "examples-grid";
|
| 179 |
-
|
| 180 |
-
// Example-button label.
|
| 181 |
-
// * Collapse internal whitespace/newlines to single spaces so each
|
| 182 |
-
// card flows as one paragraph; the CSS 2-line clamp on
|
| 183 |
-
// .example-btn handles the visual cut-off + ellipsis.
|
| 184 |
-
// * Hard cap at LABEL_MAX_CHARS as defence-in-depth — the prompts
|
| 185 |
-
// can be multi-kilobyte system instructions and we don't want
|
| 186 |
-
// all of that in the DOM just to be invisibly clamped.
|
| 187 |
-
// * ``title`` shows the full text on hover.
|
| 188 |
-
// The FULL prompt is always what we dispatch to the model; this is
|
| 189 |
-
// a display-only transform.
|
| 190 |
-
const LABEL_MAX_CHARS = 200;
|
| 191 |
-
function makeLabel(text) {
|
| 192 |
-
const oneLine = String(text).replace(/\s+/g, " ").trim();
|
| 193 |
-
if (oneLine.length <= LABEL_MAX_CHARS) return oneLine;
|
| 194 |
-
return oneLine.slice(0, LABEL_MAX_CHARS).trimEnd() + "…";
|
| 195 |
-
}
|
| 196 |
-
|
| 197 |
-
EXAMPLES.forEach((text) => {
|
| 198 |
-
// Two-layer structure:
|
| 199 |
-
// .example-btn → flex container, owns size + centering
|
| 200 |
-
// .example-btn-text → -webkit-box, owns the 2-line clamp
|
| 201 |
-
// Splitting these is the only reliable way to get BOTH "vertical
|
| 202 |
-
// centering" (needs display:flex) AND "clamp to 2 lines with auto
|
| 203 |
-
// ellipsis" (needs display:-webkit-box) on the same card. Single-
|
| 204 |
-
// element setups force a choice and we always lost one.
|
| 205 |
-
const btn = document.createElement("div");
|
| 206 |
-
btn.className = "example-btn";
|
| 207 |
-
const inner = document.createElement("span");
|
| 208 |
-
inner.className = "example-btn-text";
|
| 209 |
-
inner.textContent = makeLabel(text);
|
| 210 |
-
btn.appendChild(inner);
|
| 211 |
-
btn.title = text;
|
| 212 |
-
btn.addEventListener("click", () => {
|
| 213 |
-
const textarea = document.querySelector(".msg-input textarea");
|
| 214 |
-
if (!textarea) return;
|
| 215 |
-
textarea.focus();
|
| 216 |
-
textarea.select();
|
| 217 |
-
document.execCommand("insertText", false, text);
|
| 218 |
-
setTimeout(() => {
|
| 219 |
-
const sendBtn = document.querySelector("#send-btn");
|
| 220 |
-
if (sendBtn) sendBtn.click();
|
| 221 |
-
}, 200);
|
| 222 |
-
});
|
| 223 |
-
grid.appendChild(btn);
|
| 224 |
-
});
|
| 225 |
-
|
| 226 |
-
wrapper.appendChild(grid);
|
| 227 |
-
overlay.appendChild(wrapper);
|
| 228 |
-
|
| 229 |
-
function positionOverlay() {
|
| 230 |
-
const r = chatEl.getBoundingClientRect();
|
| 231 |
-
overlay.style.top = `${r.top}px`;
|
| 232 |
-
overlay.style.left = `${r.left}px`;
|
| 233 |
-
overlay.style.width = `${r.width}px`;
|
| 234 |
-
overlay.style.height = `${r.height}px`;
|
| 235 |
-
}
|
| 236 |
-
positionOverlay();
|
| 237 |
-
document.body.appendChild(overlay);
|
| 238 |
-
|
| 239 |
-
function syncVisibility() {
|
| 240 |
-
const msgs = chatEl.querySelectorAll(".message-row");
|
| 241 |
-
overlay.style.display = msgs.length > 0 ? "none" : "";
|
| 242 |
-
}
|
| 243 |
-
syncVisibility();
|
| 244 |
-
subscribeChatMutations(syncVisibility);
|
| 245 |
-
|
| 246 |
-
window.addEventListener("resize", positionOverlay);
|
| 247 |
-
new ResizeObserver(positionOverlay).observe(chatEl);
|
| 248 |
-
}
|
| 249 |
-
|
| 250 |
-
/* ── HTML preview modal ───────────────────────────────────────────────── */
|
| 251 |
-
function openHtmlPreview(htmlCode) {
|
| 252 |
-
const existing = document.querySelector(".html-preview-overlay");
|
| 253 |
-
if (existing) existing.remove();
|
| 254 |
-
|
| 255 |
-
const overlay = document.createElement("div");
|
| 256 |
-
overlay.className = "html-preview-overlay";
|
| 257 |
-
overlay.addEventListener("click", (e) => {
|
| 258 |
-
if (e.target === overlay) overlay.remove();
|
| 259 |
-
});
|
| 260 |
-
|
| 261 |
-
const modal = document.createElement("div");
|
| 262 |
-
modal.className = "html-preview-modal";
|
| 263 |
-
|
| 264 |
-
const header = document.createElement("div");
|
| 265 |
-
header.className = "html-preview-header";
|
| 266 |
-
|
| 267 |
-
const title = document.createElement("span");
|
| 268 |
-
title.className = "html-preview-title";
|
| 269 |
-
title.textContent = "HTML Preview";
|
| 270 |
-
|
| 271 |
-
const closeBtn = document.createElement("button");
|
| 272 |
-
closeBtn.className = "html-preview-close";
|
| 273 |
-
closeBtn.innerHTML = "×";
|
| 274 |
-
closeBtn.addEventListener("click", () => overlay.remove());
|
| 275 |
-
|
| 276 |
-
header.appendChild(title);
|
| 277 |
-
header.appendChild(closeBtn);
|
| 278 |
-
|
| 279 |
-
const iframe = document.createElement("iframe");
|
| 280 |
-
iframe.className = "html-preview-iframe";
|
| 281 |
-
// Intentionally NOT including allow-same-origin: that would let the
|
| 282 |
-
// user-supplied HTML reach into the parent page and steal cookies/state.
|
| 283 |
-
iframe.sandbox = "allow-scripts allow-modals allow-forms allow-popups";
|
| 284 |
-
|
| 285 |
-
modal.appendChild(header);
|
| 286 |
-
modal.appendChild(iframe);
|
| 287 |
-
overlay.appendChild(modal);
|
| 288 |
-
document.body.appendChild(overlay);
|
| 289 |
-
|
| 290 |
-
iframe.srcdoc = htmlCode;
|
| 291 |
-
|
| 292 |
-
document.addEventListener("keydown", function escHandler(e) {
|
| 293 |
-
if (e.key === "Escape") {
|
| 294 |
-
overlay.remove();
|
| 295 |
-
document.removeEventListener("keydown", escHandler);
|
| 296 |
-
}
|
| 297 |
-
});
|
| 298 |
-
}
|
| 299 |
-
|
| 300 |
-
const HTML_TAG_RE =
|
| 301 |
-
/<\/(div|body|html|section|main|head|style|script|p|h[1-6]|span|table|form|ul|ol|nav|header|footer|article)>/i;
|
| 302 |
-
|
| 303 |
-
function looksLikeHtml(text) {
|
| 304 |
-
const trimmed = text.trim();
|
| 305 |
-
if (!trimmed) return false;
|
| 306 |
-
if (
|
| 307 |
-
trimmed.startsWith("<!DOCTYPE") ||
|
| 308 |
-
trimmed.startsWith("<!doctype") ||
|
| 309 |
-
trimmed.startsWith("<html")
|
| 310 |
-
) {
|
| 311 |
-
return true;
|
| 312 |
-
}
|
| 313 |
-
return (
|
| 314 |
-
trimmed.startsWith("<") &&
|
| 315 |
-
trimmed.endsWith(">") &&
|
| 316 |
-
HTML_TAG_RE.test(trimmed)
|
| 317 |
-
);
|
| 318 |
-
}
|
| 319 |
-
|
| 320 |
-
function injectPreviewButtonFor(codeEl) {
|
| 321 |
-
// ``previewBtnInserted`` — set once on the codeEl after we attach a
|
| 322 |
-
// button. Must NEVER be set on a code element living inside
|
| 323 |
-
// ``.hy-streaming`` because that container's innerHTML is replaced
|
| 324 |
-
// on every delta — the codeEl gets discarded and a fresh one (no
|
| 325 |
-
// flag) appears, while the button (a sibling outside .hy-streaming)
|
| 326 |
-
// would silently leak. We only inject for code blocks that have
|
| 327 |
-
// settled into ``.hy-frozen`` (append-only, never re-rendered).
|
| 328 |
-
if (codeEl.dataset.previewBtnInserted) {
|
| 329 |
-
codeEl.__hyPreviewText = codeEl.textContent || "";
|
| 330 |
-
return;
|
| 331 |
-
}
|
| 332 |
-
|
| 333 |
-
const pre = codeEl.closest("pre");
|
| 334 |
-
if (!pre) return;
|
| 335 |
-
|
| 336 |
-
// Skip code blocks still in the streaming half. They'll be
|
| 337 |
-
// re-evaluated once the freeze boundary advances past them and the
|
| 338 |
-
// pre is moved into ``.hy-frozen`` as a fresh DOM node — at which
|
| 339 |
-
// point this MutationObserver fires again with the new pre as an
|
| 340 |
-
// added node and we inject exactly once.
|
| 341 |
-
const frozenAncestor = pre.closest(".hy-frozen");
|
| 342 |
-
if (!frozenAncestor) return;
|
| 343 |
-
|
| 344 |
-
const text = codeEl.textContent || "";
|
| 345 |
-
if (!looksLikeHtml(text)) return;
|
| 346 |
-
|
| 347 |
-
codeEl.dataset.previewBtnInserted = "true";
|
| 348 |
-
codeEl.__hyPreviewText = text;
|
| 349 |
-
|
| 350 |
-
const btn = document.createElement("button");
|
| 351 |
-
btn.className = "html-preview-btn";
|
| 352 |
-
btn.title = "Preview HTML";
|
| 353 |
-
btn.addEventListener("click", (e) => {
|
| 354 |
-
e.stopPropagation();
|
| 355 |
-
e.preventDefault();
|
| 356 |
-
openHtmlPreview(codeEl.__hyPreviewText || codeEl.textContent || "");
|
| 357 |
-
});
|
| 358 |
-
|
| 359 |
-
// Insert directly after the <pre> inside the same .hy-frozen
|
| 360 |
-
// container. This binds the button's lifecycle to the specific
|
| 361 |
-
// code block (instead of dumping all preview buttons into b.md as
|
| 362 |
-
// siblings of .hy-frozen / .hy-streaming) and keeps its position
|
| 363 |
-
// visually anchored to its source block.
|
| 364 |
-
pre.parentElement.insertBefore(btn, pre.nextSibling);
|
| 365 |
-
}
|
| 366 |
-
|
| 367 |
-
/* ── Code-block chrome (header w/ lang label + copy button) ───────────── */
|
| 368 |
-
function copyText(text) {
|
| 369 |
-
if (navigator.clipboard && navigator.clipboard.writeText) {
|
| 370 |
-
return navigator.clipboard.writeText(text).catch(() => fallbackCopy(text));
|
| 371 |
-
}
|
| 372 |
-
return fallbackCopy(text);
|
| 373 |
-
}
|
| 374 |
-
|
| 375 |
-
function fallbackCopy(text) {
|
| 376 |
-
return new Promise((resolve, reject) => {
|
| 377 |
-
try {
|
| 378 |
-
const ta = document.createElement("textarea");
|
| 379 |
-
ta.value = text;
|
| 380 |
-
ta.setAttribute("readonly", "");
|
| 381 |
-
ta.style.position = "absolute";
|
| 382 |
-
ta.style.left = "-9999px";
|
| 383 |
-
document.body.appendChild(ta);
|
| 384 |
-
ta.select();
|
| 385 |
-
document.execCommand("copy");
|
| 386 |
-
document.body.removeChild(ta);
|
| 387 |
-
resolve();
|
| 388 |
-
} catch (err) {
|
| 389 |
-
reject(err);
|
| 390 |
-
}
|
| 391 |
-
});
|
| 392 |
-
}
|
| 393 |
-
|
| 394 |
-
const COPY_ICON_SVG =
|
| 395 |
-
'<svg viewBox="0 0 24 24" width="14" height="14" fill="none" ' +
|
| 396 |
-
'stroke="currentColor" stroke-width="2" stroke-linecap="round" ' +
|
| 397 |
-
'stroke-linejoin="round" aria-hidden="true">' +
|
| 398 |
-
'<rect x="9" y="9" width="11" height="11" rx="2" ry="2"></rect>' +
|
| 399 |
-
'<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>' +
|
| 400 |
-
"</svg>";
|
| 401 |
-
const CHECK_ICON_SVG =
|
| 402 |
-
'<svg viewBox="0 0 24 24" width="14" height="14" fill="none" ' +
|
| 403 |
-
'stroke="currentColor" stroke-width="2.5" stroke-linecap="round" ' +
|
| 404 |
-
'stroke-linejoin="round" aria-hidden="true">' +
|
| 405 |
-
'<polyline points="4 12 10 18 20 6"></polyline>' +
|
| 406 |
-
"</svg>";
|
| 407 |
-
|
| 408 |
-
// Pull the language label off the <code> element. ``marked`` always
|
| 409 |
-
// emits ``class="language-X"`` from the fence info string, and
|
| 410 |
-
// ``hljs.highlightElement`` may also add ``language-X`` after detection.
|
| 411 |
-
// Anything else (no fence info, hljs failed) → blank label so the
|
| 412 |
-
// header still renders consistently.
|
| 413 |
-
function detectCodeLang(codeEl) {
|
| 414 |
-
const cls = codeEl.className || "";
|
| 415 |
-
const m = cls.match(/(?:^|\s)language-([\w+#.-]+)/i);
|
| 416 |
-
if (!m) return "";
|
| 417 |
-
const lang = m[1].toLowerCase();
|
| 418 |
-
// A few common aliases for nicer display.
|
| 419 |
-
const ALIASES = {
|
| 420 |
-
js: "javascript",
|
| 421 |
-
ts: "typescript",
|
| 422 |
-
sh: "shell",
|
| 423 |
-
bash: "shell",
|
| 424 |
-
zsh: "shell",
|
| 425 |
-
yml: "yaml",
|
| 426 |
-
md: "markdown",
|
| 427 |
-
"c++": "cpp",
|
| 428 |
-
};
|
| 429 |
-
return ALIASES[lang] || lang;
|
| 430 |
-
}
|
| 431 |
-
|
| 432 |
-
const COPY_LABEL =
|
| 433 |
-
(window.HY_I18N && window.HY_I18N.code_copy) || "Copy";
|
| 434 |
-
const COPIED_LABEL =
|
| 435 |
-
(window.HY_I18N && window.HY_I18N.code_copied) || "Copied";
|
| 436 |
-
|
| 437 |
-
function injectCopyButtonFor(codeEl) {
|
| 438 |
-
const pre = codeEl.closest("pre");
|
| 439 |
-
if (!pre || pre.dataset.copyInjected) return;
|
| 440 |
-
pre.dataset.copyInjected = "true";
|
| 441 |
-
|
| 442 |
-
// ── Build the wrapper card ────────────────────────────────────────
|
| 443 |
-
const wrapper = document.createElement("div");
|
| 444 |
-
wrapper.className = "hy-codeblock";
|
| 445 |
-
|
| 446 |
-
const header = document.createElement("div");
|
| 447 |
-
header.className = "hy-codeblock-header";
|
| 448 |
-
|
| 449 |
-
const lang = document.createElement("span");
|
| 450 |
-
lang.className = "hy-codeblock-lang";
|
| 451 |
-
lang.textContent = detectCodeLang(codeEl);
|
| 452 |
-
header.appendChild(lang);
|
| 453 |
-
|
| 454 |
-
const btn = document.createElement("button");
|
| 455 |
-
btn.type = "button";
|
| 456 |
-
btn.className = "code-copy-btn";
|
| 457 |
-
btn.setAttribute("aria-label", COPY_LABEL);
|
| 458 |
-
btn.title = COPY_LABEL;
|
| 459 |
-
btn.innerHTML = COPY_ICON_SVG;
|
| 460 |
-
|
| 461 |
-
let resetTimer = null;
|
| 462 |
-
btn.addEventListener("click", (e) => {
|
| 463 |
-
e.stopPropagation();
|
| 464 |
-
e.preventDefault();
|
| 465 |
-
const text = codeEl.textContent || "";
|
| 466 |
-
copyText(text).then(
|
| 467 |
-
() => {
|
| 468 |
-
btn.innerHTML = CHECK_ICON_SVG;
|
| 469 |
-
btn.classList.add("copied");
|
| 470 |
-
btn.title = COPIED_LABEL;
|
| 471 |
-
if (resetTimer) clearTimeout(resetTimer);
|
| 472 |
-
resetTimer = setTimeout(() => {
|
| 473 |
-
btn.innerHTML = COPY_ICON_SVG;
|
| 474 |
-
btn.classList.remove("copied");
|
| 475 |
-
btn.title = COPY_LABEL;
|
| 476 |
-
}, 1400);
|
| 477 |
-
},
|
| 478 |
-
() => {
|
| 479 |
-
btn.title = "Copy failed";
|
| 480 |
-
if (resetTimer) clearTimeout(resetTimer);
|
| 481 |
-
resetTimer = setTimeout(() => {
|
| 482 |
-
btn.title = COPY_LABEL;
|
| 483 |
-
}, 1400);
|
| 484 |
-
}
|
| 485 |
-
);
|
| 486 |
-
});
|
| 487 |
-
header.appendChild(btn);
|
| 488 |
-
|
| 489 |
-
// ── Splice wrapper into the DOM around <pre> ─────────────────────
|
| 490 |
-
// Insert the wrapper where <pre> lived, then move <pre> into it.
|
| 491 |
-
// The mutation observer that drives this function will re-fire for
|
| 492 |
-
// the wrapper's appearance, but ``dataset.copyInjected`` on <pre>
|
| 493 |
-
// makes the second pass a no-op.
|
| 494 |
-
const parent = pre.parentElement;
|
| 495 |
-
if (!parent) return;
|
| 496 |
-
parent.insertBefore(wrapper, pre);
|
| 497 |
-
wrapper.appendChild(header);
|
| 498 |
-
wrapper.appendChild(pre);
|
| 499 |
-
}
|
| 500 |
-
|
| 501 |
-
function processCodeBlock(codeEl) {
|
| 502 |
-
injectCopyButtonFor(codeEl);
|
| 503 |
-
injectPreviewButtonFor(codeEl);
|
| 504 |
-
}
|
| 505 |
-
|
| 506 |
-
function watchForHtmlBlocks() {
|
| 507 |
-
const chatEl = document.querySelector(CHAT_SELECTOR);
|
| 508 |
-
if (!chatEl) {
|
| 509 |
-
setTimeout(watchForHtmlBlocks, 500);
|
| 510 |
-
return;
|
| 511 |
-
}
|
| 512 |
-
|
| 513 |
-
chatEl.querySelectorAll("pre code").forEach(processCodeBlock);
|
| 514 |
-
|
| 515 |
-
// Subscribers receive the whole rAF batch in one call. Within a
|
| 516 |
-
// single batch the same code element may appear in many records
|
| 517 |
-
// (one per streamed token); we de-dup with a Set so we only
|
| 518 |
-
// re-evaluate ``injectPreviewButtonFor`` ONCE per affected code
|
| 519 |
-
// element per frame instead of once per mutation.
|
| 520 |
-
subscribeChatMutations((mutations) => {
|
| 521 |
-
const codeElsToCheck = new Set();
|
| 522 |
-
for (let i = 0; i < mutations.length; i++) {
|
| 523 |
-
const m = mutations[i];
|
| 524 |
-
if (m.type === "childList") {
|
| 525 |
-
const added = m.addedNodes;
|
| 526 |
-
for (let j = 0; j < added.length; j++) {
|
| 527 |
-
const node = added[j];
|
| 528 |
-
if (!(node instanceof HTMLElement)) continue;
|
| 529 |
-
if (node.matches && node.matches("pre code")) {
|
| 530 |
-
processCodeBlock(node);
|
| 531 |
-
} else if (node.querySelectorAll) {
|
| 532 |
-
const found = node.querySelectorAll("pre code");
|
| 533 |
-
for (let k = 0; k < found.length; k++) {
|
| 534 |
-
processCodeBlock(found[k]);
|
| 535 |
-
}
|
| 536 |
-
}
|
| 537 |
-
}
|
| 538 |
-
} else if (m.type === "characterData") {
|
| 539 |
-
const el = m.target.parentElement;
|
| 540 |
-
if (el && el.tagName === "CODE") codeElsToCheck.add(el);
|
| 541 |
-
}
|
| 542 |
-
}
|
| 543 |
-
// Late-arriving HTML detection: a code block may not have looked
|
| 544 |
-
// like HTML when first added but does now that more tokens have
|
| 545 |
-
// streamed in. injectPreviewButtonFor is idempotent so calling it
|
| 546 |
-
// again is safe and cheap.
|
| 547 |
-
codeElsToCheck.forEach(injectPreviewButtonFor);
|
| 548 |
-
});
|
| 549 |
-
}
|
| 550 |
-
|
| 551 |
-
/* ── Send button: helpers ─────────────────────────────────────────────── */
|
| 552 |
-
function getSendButton() {
|
| 553 |
-
const wrap = document.querySelector("#send-btn");
|
| 554 |
-
if (!wrap) return null;
|
| 555 |
-
if (wrap.tagName === "BUTTON") return wrap;
|
| 556 |
-
return wrap.querySelector("button");
|
| 557 |
-
}
|
| 558 |
-
|
| 559 |
-
function setSendDisabled(disabled) {
|
| 560 |
-
const btn = getSendButton();
|
| 561 |
-
if (!btn) return;
|
| 562 |
-
if (disabled) {
|
| 563 |
-
if (!btn.disabled) {
|
| 564 |
-
btn.setAttribute("disabled", "");
|
| 565 |
-
btn.disabled = true;
|
| 566 |
-
}
|
| 567 |
-
} else {
|
| 568 |
-
if (btn.disabled || btn.hasAttribute("disabled")) {
|
| 569 |
-
btn.removeAttribute("disabled");
|
| 570 |
-
btn.disabled = false;
|
| 571 |
-
}
|
| 572 |
-
}
|
| 573 |
-
}
|
| 574 |
-
|
| 575 |
-
function streamMarkerPresent() {
|
| 576 |
-
return !!document.querySelector(STREAM_MARKER_SELECTOR);
|
| 577 |
-
}
|
| 578 |
-
|
| 579 |
-
function idleMarkerPresent() {
|
| 580 |
-
return !!document.querySelector(IDLE_MARKER_SELECTOR);
|
| 581 |
-
}
|
| 582 |
-
|
| 583 |
-
function isModelBusy() {
|
| 584 |
-
const now = performance.now();
|
| 585 |
-
// Awaiting the server's first frame after a dispatch — must remain
|
| 586 |
-
// busy regardless of marker state, with a hard timeout to avoid a
|
| 587 |
-
// permanently-stuck button if the request silently failed.
|
| 588 |
-
if (awaitingFirstFrame && now - lastSendAt < FIRST_FRAME_TIMEOUT_MS) {
|
| 589 |
-
return true;
|
| 590 |
-
}
|
| 591 |
-
if (now - lastSendAt < SEND_DEBOUNCE_MS) return true;
|
| 592 |
-
return streamMarkerPresent();
|
| 593 |
-
}
|
| 594 |
-
|
| 595 |
-
/* ── Busy toast ───────────────────────────────────────────────────────── */
|
| 596 |
-
function ensureBusyToastHost() {
|
| 597 |
-
let host = document.getElementById("hy-busy-toast-host");
|
| 598 |
-
if (host) return host;
|
| 599 |
-
host = document.createElement("div");
|
| 600 |
-
host.id = "hy-busy-toast-host";
|
| 601 |
-
Object.assign(host.style, {
|
| 602 |
-
position: "fixed",
|
| 603 |
-
top: "24px",
|
| 604 |
-
left: "50%",
|
| 605 |
-
transform: "translateX(-50%)",
|
| 606 |
-
zIndex: "9999",
|
| 607 |
-
display: "flex",
|
| 608 |
-
flexDirection: "column",
|
| 609 |
-
gap: "8px",
|
| 610 |
-
pointerEvents: "none",
|
| 611 |
-
});
|
| 612 |
-
document.body.appendChild(host);
|
| 613 |
-
return host;
|
| 614 |
-
}
|
| 615 |
-
|
| 616 |
-
let lastToastAt = 0;
|
| 617 |
-
function showBusyToast() {
|
| 618 |
-
const now = performance.now();
|
| 619 |
-
if (now - lastToastAt < 800) return;
|
| 620 |
-
lastToastAt = now;
|
| 621 |
-
|
| 622 |
-
const host = ensureBusyToastHost();
|
| 623 |
-
const toast = document.createElement("div");
|
| 624 |
-
toast.className = "hy-busy-toast";
|
| 625 |
-
toast.textContent = BUSY_MSG;
|
| 626 |
-
Object.assign(toast.style, {
|
| 627 |
-
background: "#1f2937",
|
| 628 |
-
color: "#fff",
|
| 629 |
-
padding: "10px 16px",
|
| 630 |
-
borderRadius: "8px",
|
| 631 |
-
boxShadow: "0 6px 20px rgba(0,0,0,0.25)",
|
| 632 |
-
fontSize: "14px",
|
| 633 |
-
maxWidth: "min(92vw, 520px)",
|
| 634 |
-
lineHeight: "1.4",
|
| 635 |
-
opacity: "0",
|
| 636 |
-
transition: "opacity 180ms ease",
|
| 637 |
-
pointerEvents: "none",
|
| 638 |
-
});
|
| 639 |
-
host.appendChild(toast);
|
| 640 |
-
requestAnimationFrame(() => {
|
| 641 |
-
toast.style.opacity = "1";
|
| 642 |
-
});
|
| 643 |
-
setTimeout(() => {
|
| 644 |
-
toast.style.opacity = "0";
|
| 645 |
-
setTimeout(() => toast.remove(), 250);
|
| 646 |
-
}, 3200);
|
| 647 |
-
}
|
| 648 |
-
|
| 649 |
-
/* ── Send-button busy guard ───────────────────────────────────────────── */
|
| 650 |
-
// Three-layer disable signal, in priority order:
|
| 651 |
-
//
|
| 652 |
-
// 1. SEND_DEBOUNCE_MS round-trip window after the user dispatched
|
| 653 |
-
// → disabled (prevents fast double-click before first server
|
| 654 |
-
// frame arrives).
|
| 655 |
-
// 2. #hy-busy-marker contains [data-hy-streaming="1"]
|
| 656 |
-
// → disabled (server is actively streaming).
|
| 657 |
-
// 3. Chat DOM has been *completely* idle for CHAT_IDLE_MS AND
|
| 658 |
-
// we're past CHAT_IDLE_MIN_SINCE_SEND_MS since dispatch
|
| 659 |
-
// → soft override: force-clear the marker and enable. Safety
|
| 660 |
-
// net for "the server's IDLE marker frame was lost on the
|
| 661 |
-
// wire".
|
| 662 |
-
let busyStartedAt = 0;
|
| 663 |
-
let lastChatMutationAt = 0;
|
| 664 |
-
|
| 665 |
-
function syncSendButtonState() {
|
| 666 |
-
const marker = streamMarkerPresent();
|
| 667 |
-
const now = performance.now();
|
| 668 |
-
|
| 669 |
-
if (marker) {
|
| 670 |
-
// First server frame has arrived — stop relying on the dispatch
|
| 671 |
-
// timer and hand over to the marker as the source of truth.
|
| 672 |
-
awaitingFirstFrame = false;
|
| 673 |
-
if (busyStartedAt === 0) busyStartedAt = now;
|
| 674 |
-
|
| 675 |
-
const sinceSend = now - lastSendAt;
|
| 676 |
-
const sinceMutation = now - lastChatMutationAt;
|
| 677 |
-
if (
|
| 678 |
-
lastSendAt > 0 &&
|
| 679 |
-
sinceSend > CHAT_IDLE_MIN_SINCE_SEND_MS &&
|
| 680 |
-
sinceMutation > CHAT_IDLE_MS
|
| 681 |
-
) {
|
| 682 |
-
console.warn(
|
| 683 |
-
"[hy] Marker stuck while chat DOM idle for",
|
| 684 |
-
(sinceMutation / 1000).toFixed(1),
|
| 685 |
-
"s — force-clearing (server IDLE frame likely lost)."
|
| 686 |
-
);
|
| 687 |
-
document.querySelectorAll(STREAM_MARKER_SELECTOR).forEach((el) => {
|
| 688 |
-
el.removeAttribute("data-hy-streaming");
|
| 689 |
-
});
|
| 690 |
-
busyStartedAt = 0;
|
| 691 |
-
setSendDisabled(false);
|
| 692 |
-
return;
|
| 693 |
-
}
|
| 694 |
-
|
| 695 |
-
if (now - busyStartedAt > ABSOLUTE_BUSY_TIMEOUT_MS) {
|
| 696 |
-
console.warn(
|
| 697 |
-
"[hy] Stream marker stuck >",
|
| 698 |
-
ABSOLUTE_BUSY_TIMEOUT_MS / 1000,
|
| 699 |
-
"s — force-enabling Send."
|
| 700 |
-
);
|
| 701 |
-
document.querySelectorAll(STREAM_MARKER_SELECTOR).forEach((el) => {
|
| 702 |
-
el.removeAttribute("data-hy-streaming");
|
| 703 |
-
});
|
| 704 |
-
busyStartedAt = 0;
|
| 705 |
-
setSendDisabled(false);
|
| 706 |
-
return;
|
| 707 |
-
}
|
| 708 |
-
|
| 709 |
-
setSendDisabled(true);
|
| 710 |
-
return;
|
| 711 |
-
}
|
| 712 |
-
|
| 713 |
-
busyStartedAt = 0;
|
| 714 |
-
|
| 715 |
-
// Marker is idle. We may still be waiting for the FIRST frame after
|
| 716 |
-
// a freshly-dispatched send: keep the button disabled so a second
|
| 717 |
-
// click can't slip through during the initial request round-trip.
|
| 718 |
-
if (awaitingFirstFrame) {
|
| 719 |
-
// If the marker host explicitly contains the IDLE marker, the
|
| 720 |
-
// server has already responded — typically a short-circuit path
|
| 721 |
-
// like the functions-JSON validation failure in send_message,
|
| 722 |
-
// which yields HY_IDLE_HTML without ever yielding HY_BUSY_HTML.
|
| 723 |
-
// Without this branch, awaitingFirstFrame would stay set until
|
| 724 |
-
// FIRST_FRAME_TIMEOUT_MS (30s), causing the next Enter/click to
|
| 725 |
-
// wrongly trigger the "model is busy" toast.
|
| 726 |
-
if (idleMarkerPresent()) {
|
| 727 |
-
awaitingFirstFrame = false;
|
| 728 |
-
} else if (now - lastSendAt > FIRST_FRAME_TIMEOUT_MS) {
|
| 729 |
-
console.warn(
|
| 730 |
-
"[hy] First-frame timeout — re-enabling Send (request likely failed)."
|
| 731 |
-
);
|
| 732 |
-
awaitingFirstFrame = false;
|
| 733 |
-
setSendDisabled(false);
|
| 734 |
-
return;
|
| 735 |
-
} else {
|
| 736 |
-
setSendDisabled(true);
|
| 737 |
-
return;
|
| 738 |
-
}
|
| 739 |
-
}
|
| 740 |
-
|
| 741 |
-
if (now - lastSendAt < SEND_DEBOUNCE_MS) {
|
| 742 |
-
setSendDisabled(true);
|
| 743 |
-
return;
|
| 744 |
-
}
|
| 745 |
-
setSendDisabled(false);
|
| 746 |
-
}
|
| 747 |
-
|
| 748 |
-
function installBusyGuard() {
|
| 749 |
-
const sendBtn = document.querySelector("#send-btn");
|
| 750 |
-
const textarea = document.querySelector(".msg-input textarea");
|
| 751 |
-
const markerHost = document.getElementById(BUSY_MARKER_HOST_ID);
|
| 752 |
-
const chatEl = document.querySelector(CHAT_SELECTOR);
|
| 753 |
-
if (!sendBtn || !textarea || !markerHost || !chatEl) {
|
| 754 |
-
setTimeout(installBusyGuard, 500);
|
| 755 |
-
return;
|
| 756 |
-
}
|
| 757 |
-
|
| 758 |
-
// Track chat DOM activity for the soft watchdog above. ANY mutation
|
| 759 |
-
// refreshes the timestamp — including post-stream KaTeX/highlight
|
| 760 |
-
// injection — because if anything is still rendering the streaming
|
| 761 |
-
// MIGHT not be over yet. The watchdog only fires after a long quiet
|
| 762 |
-
// period.
|
| 763 |
-
lastChatMutationAt = performance.now();
|
| 764 |
-
subscribeChatMutations(() => {
|
| 765 |
-
lastChatMutationAt = performance.now();
|
| 766 |
-
});
|
| 767 |
-
|
| 768 |
-
// Heartbeats — the server emits an empty-ops delta every ~5s during
|
| 769 |
-
// long thinking pauses to keep the SSE/WebSocket connection alive
|
| 770 |
-
// (see ``_HEARTBEAT_INTERVAL`` in core/chat.py). Empty-ops deltas
|
| 771 |
-
// do NOT mutate ``#hy-chat`` so the MutationObserver above never
|
| 772 |
-
// sees them, but they DO trigger the ``hy-chat:updated`` event that
|
| 773 |
-
// applyDelta dispatches on every payload. Without this listener the
|
| 774 |
-
// watchdog would mistakenly fire during legitimate thinking pauses
|
| 775 |
-
// (especially with two windows in flight, where the per-request
|
| 776 |
-
// first-content latency is higher) and unlock Send while the stream
|
| 777 |
-
// is still running — letting the user dispatch a duplicate turn.
|
| 778 |
-
chatEl.addEventListener("hy-chat:updated", () => {
|
| 779 |
-
lastChatMutationAt = performance.now();
|
| 780 |
-
});
|
| 781 |
-
|
| 782 |
-
// Block clicks while busy. Capture phase + stopImmediatePropagation
|
| 783 |
-
// ensures Gradio's own bubble-phase click handler never sees the
|
| 784 |
-
// event when we want to reject it.
|
| 785 |
-
//
|
| 786 |
-
// CRITICAL: in the NOT-busy path we do NOT call setSendDisabled(true)
|
| 787 |
-
// here. Gradio's Svelte Button checks ``this.disabled`` inside its
|
| 788 |
-
// own click handler that runs AFTER ours; if we flip the disabled
|
| 789 |
-
// attribute synchronously in capture, the actual send request is
|
| 790 |
-
// silently swallowed.
|
| 791 |
-
// Disable the Send button on the NEXT tick (after Gradio's own
|
| 792 |
-
// bubble-phase click handler has run and dispatched the request).
|
| 793 |
-
// We can't disable synchronously in capture or Gradio's Svelte
|
| 794 |
-
// Button checks ``this.disabled`` and silently swallows the send.
|
| 795 |
-
function lockSendAfterDispatch() {
|
| 796 |
-
setTimeout(() => {
|
| 797 |
-
setSendDisabled(true);
|
| 798 |
-
}, 0);
|
| 799 |
-
}
|
| 800 |
-
|
| 801 |
-
sendBtn.addEventListener(
|
| 802 |
-
"click",
|
| 803 |
-
(e) => {
|
| 804 |
-
if (isModelBusy()) {
|
| 805 |
-
e.preventDefault();
|
| 806 |
-
e.stopImmediatePropagation();
|
| 807 |
-
e.stopPropagation();
|
| 808 |
-
showBusyToast();
|
| 809 |
-
return;
|
| 810 |
-
}
|
| 811 |
-
lastSendAt = performance.now();
|
| 812 |
-
awaitingFirstFrame = true;
|
| 813 |
-
justSentNewMessage = true;
|
| 814 |
-
lockSendAfterDispatch();
|
| 815 |
-
},
|
| 816 |
-
true
|
| 817 |
-
);
|
| 818 |
-
|
| 819 |
-
// Same logic for Enter-to-submit on the textarea. Gradio's
|
| 820 |
-
// Textbox.submit fires regardless of the Send button's disabled
|
| 821 |
-
// state, so we ALSO need this gate.
|
| 822 |
-
textarea.addEventListener(
|
| 823 |
-
"keydown",
|
| 824 |
-
(e) => {
|
| 825 |
-
if (e.key !== "Enter" || e.shiftKey || e.isComposing) return;
|
| 826 |
-
if (isModelBusy()) {
|
| 827 |
-
e.preventDefault();
|
| 828 |
-
e.stopImmediatePropagation();
|
| 829 |
-
e.stopPropagation();
|
| 830 |
-
showBusyToast();
|
| 831 |
-
return;
|
| 832 |
-
}
|
| 833 |
-
lastSendAt = performance.now();
|
| 834 |
-
awaitingFirstFrame = true;
|
| 835 |
-
justSentNewMessage = true;
|
| 836 |
-
lockSendAfterDispatch();
|
| 837 |
-
},
|
| 838 |
-
true
|
| 839 |
-
);
|
| 840 |
-
|
| 841 |
-
// Drive the busy state from mutations of the dedicated marker host.
|
| 842 |
-
// Tiny subtree (one component, one inner span at most) so this is
|
| 843 |
-
// essentially free.
|
| 844 |
-
new MutationObserver(syncSendButtonState).observe(markerHost, {
|
| 845 |
-
childList: true,
|
| 846 |
-
subtree: true,
|
| 847 |
-
characterData: true,
|
| 848 |
-
attributes: true,
|
| 849 |
-
attributeFilter: ["data-hy-streaming", "data-hy-busy"],
|
| 850 |
-
});
|
| 851 |
-
|
| 852 |
-
// Slow heartbeat in case the MutationObserver misses something.
|
| 853 |
-
setInterval(syncSendButtonState, 500);
|
| 854 |
-
|
| 855 |
-
// Initial sync.
|
| 856 |
-
syncSendButtonState();
|
| 857 |
-
}
|
| 858 |
-
|
| 859 |
-
/* ── Follow-the-tail scroller ─────────────────────────────────────────── */
|
| 860 |
-
// Design (simple & robust):
|
| 861 |
-
// * ``follow`` mirrors "user is currently near the bottom of the
|
| 862 |
-
// chat". It is updated on EVERY scroll event — both user-driven
|
| 863 |
-
// and programmatic — because after our own ``scrollToBottom`` the
|
| 864 |
-
// position IS at the bottom, so follow stays true automatically.
|
| 865 |
-
// * When the user scrolls UP, the very next scroll event flips
|
| 866 |
-
// follow to false; subsequent mutations don't re-pin the view.
|
| 867 |
-
// * When the user is actively scrolling (wheel / touchmove /
|
| 868 |
-
// scroll-key) we briefly pause programmatic scrolling so we don't
|
| 869 |
-
// fight their fingers; once they let go (no gesture for
|
| 870 |
-
// USER_QUIET_MS) auto-follow resumes if they ended near bottom.
|
| 871 |
-
// * Two redundant triggers ensure we never miss a delta: the global
|
| 872 |
-
// chat MutationObserver AND the explicit ``hy-chat:updated``
|
| 873 |
-
// custom event dispatched by static/chat.js after each delta is
|
| 874 |
-
// applied.
|
| 875 |
-
function installScrollLock() {
|
| 876 |
-
const chatEl = document.querySelector(CHAT_SELECTOR);
|
| 877 |
-
if (!chatEl) {
|
| 878 |
-
setTimeout(installScrollLock, 500);
|
| 879 |
-
return;
|
| 880 |
-
}
|
| 881 |
-
|
| 882 |
-
const NEAR_BOTTOM_PX = 100;
|
| 883 |
-
const USER_QUIET_MS = 120;
|
| 884 |
-
|
| 885 |
-
let scrollable = null;
|
| 886 |
-
let follow = true;
|
| 887 |
-
let lastUserGestureAt = 0;
|
| 888 |
-
|
| 889 |
-
function markUserGesture() {
|
| 890 |
-
lastUserGestureAt = performance.now();
|
| 891 |
-
}
|
| 892 |
-
window.addEventListener("wheel", markUserGesture, {
|
| 893 |
-
passive: true,
|
| 894 |
-
capture: true,
|
| 895 |
-
});
|
| 896 |
-
window.addEventListener("touchmove", markUserGesture, {
|
| 897 |
-
passive: true,
|
| 898 |
-
capture: true,
|
| 899 |
-
});
|
| 900 |
-
const SCROLL_KEYS = new Set([
|
| 901 |
-
"ArrowUp",
|
| 902 |
-
"ArrowDown",
|
| 903 |
-
"PageUp",
|
| 904 |
-
"PageDown",
|
| 905 |
-
"Home",
|
| 906 |
-
"End",
|
| 907 |
-
"Space",
|
| 908 |
-
" ",
|
| 909 |
-
]);
|
| 910 |
-
window.addEventListener(
|
| 911 |
-
"keydown",
|
| 912 |
-
(e) => {
|
| 913 |
-
if (SCROLL_KEYS.has(e.key)) markUserGesture();
|
| 914 |
-
},
|
| 915 |
-
{ capture: true }
|
| 916 |
-
);
|
| 917 |
-
|
| 918 |
-
function isNearBottom(el) {
|
| 919 |
-
return el.scrollHeight - el.scrollTop - el.clientHeight < NEAR_BOTTOM_PX;
|
| 920 |
-
}
|
| 921 |
-
|
| 922 |
-
function onScroll() {
|
| 923 |
-
if (!scrollable) return;
|
| 924 |
-
// Always reflect the current viewport state. After programmatic
|
| 925 |
-
// scrollToBottom the position IS at the bottom, so follow=true.
|
| 926 |
-
// After user scrolls up, follow flips to false on the very next
|
| 927 |
-
// scroll event. Simple and self-correcting.
|
| 928 |
-
follow = isNearBottom(scrollable);
|
| 929 |
-
}
|
| 930 |
-
|
| 931 |
-
function scrollToBottom() {
|
| 932 |
-
if (!scrollable) return;
|
| 933 |
-
// Don't fight an active user gesture. Once they stop (>120ms of
|
| 934 |
-
// silence) we'll catch up on the very next mutation OR custom
|
| 935 |
-
// event — both of which fire for every streamed delta.
|
| 936 |
-
if (performance.now() - lastUserGestureAt < USER_QUIET_MS) return;
|
| 937 |
-
const target = scrollable.scrollHeight - scrollable.clientHeight;
|
| 938 |
-
if (target > scrollable.scrollTop) scrollable.scrollTop = target;
|
| 939 |
-
}
|
| 940 |
-
|
| 941 |
-
function findScrollable() {
|
| 942 |
-
// Our chat element IS itself the scrollable container (see
|
| 943 |
-
// _chat.css). Attach to it eagerly even before content overflows
|
| 944 |
-
// so we catch the first scroll event the moment overflow appears.
|
| 945 |
-
const s = getComputedStyle(chatEl);
|
| 946 |
-
if (s.overflowY === "auto" || s.overflowY === "scroll") return chatEl;
|
| 947 |
-
// Fallback for unexpected layouts: walk the subtree.
|
| 948 |
-
const candidates = chatEl.querySelectorAll("*");
|
| 949 |
-
for (const el of candidates) {
|
| 950 |
-
const cs = getComputedStyle(el);
|
| 951 |
-
if (cs.overflowY === "auto" || cs.overflowY === "scroll") {
|
| 952 |
-
if (el.scrollHeight > el.clientHeight + 4) return el;
|
| 953 |
-
}
|
| 954 |
-
}
|
| 955 |
-
return chatEl;
|
| 956 |
-
}
|
| 957 |
-
|
| 958 |
-
function attach(el) {
|
| 959 |
-
if (scrollable === el) return;
|
| 960 |
-
if (scrollable) scrollable.removeEventListener("scroll", onScroll);
|
| 961 |
-
scrollable = el;
|
| 962 |
-
el.addEventListener("scroll", onScroll, { passive: true });
|
| 963 |
-
if (follow) scrollToBottom();
|
| 964 |
-
}
|
| 965 |
-
|
| 966 |
-
// Attach immediately — chat.js may not have any content yet but the
|
| 967 |
-
// element exists, so we can already wire the scroll listener.
|
| 968 |
-
attach(findScrollable());
|
| 969 |
-
|
| 970 |
-
function tick() {
|
| 971 |
-
if (justSentNewMessage) {
|
| 972 |
-
follow = true;
|
| 973 |
-
justSentNewMessage = false;
|
| 974 |
-
}
|
| 975 |
-
if (!scrollable || !document.contains(scrollable)) {
|
| 976 |
-
attach(findScrollable());
|
| 977 |
-
}
|
| 978 |
-
if (scrollable && follow) {
|
| 979 |
-
scrollToBottom();
|
| 980 |
-
}
|
| 981 |
-
}
|
| 982 |
-
|
| 983 |
-
// Trigger 1: the global chat MutationObserver hub. Catches every
|
| 984 |
-
// DOM change under #hy-chat (delta-driven appends, frozen flush,
|
| 985 |
-
// streaming innerHTML swaps, post-stream highlight injection).
|
| 986 |
-
subscribeChatMutations(tick);
|
| 987 |
-
|
| 988 |
-
// Trigger 2: the explicit ``hy-chat:updated`` event dispatched by
|
| 989 |
-
// static/chat.js at the end of every applyDelta. Belt-and-braces
|
| 990 |
-
// in case some pathological mutation pattern slips past the rAF
|
| 991 |
-
// batcher above.
|
| 992 |
-
chatEl.addEventListener("hy-chat:updated", tick);
|
| 993 |
-
|
| 994 |
-
// Trigger 3: window resize can change clientHeight which makes the
|
| 995 |
-
// previous "at bottom" position no longer at bottom. Re-pin.
|
| 996 |
-
window.addEventListener("resize", () => {
|
| 997 |
-
if (scrollable && follow) scrollToBottom();
|
| 998 |
-
});
|
| 999 |
-
}
|
| 1000 |
-
|
| 1001 |
-
/* ── kick off ─────────────────────────────────────────────────────────── */
|
| 1002 |
-
function bootstrap() {
|
| 1003 |
-
const chatEl = document.querySelector(CHAT_SELECTOR);
|
| 1004 |
-
if (!chatEl) {
|
| 1005 |
-
// chat.js renders #hy-chat into the gr.HTML wrapper; until that
|
| 1006 |
-
// happens we can't install observers. Retry until ready —
|
| 1007 |
-
// subsystems below all guard for the same node themselves but
|
| 1008 |
-
// the mutation hub MUST be running before they install their
|
| 1009 |
-
// subscribers — otherwise early mutations would be missed.
|
| 1010 |
-
setTimeout(bootstrap, 200);
|
| 1011 |
-
return;
|
| 1012 |
-
}
|
| 1013 |
-
startChatMutationHub(chatEl);
|
| 1014 |
-
createOverlay();
|
| 1015 |
-
watchForHtmlBlocks();
|
| 1016 |
-
installScrollLock();
|
| 1017 |
-
installBusyGuard();
|
| 1018 |
-
}
|
| 1019 |
-
setTimeout(bootstrap, 800);
|
| 1020 |
-
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/chat.js
DELETED
|
@@ -1,759 +0,0 @@
|
|
| 1 |
-
/* eslint-disable */
|
| 2 |
-
/**
|
| 3 |
-
* Hy3 custom chat renderer.
|
| 4 |
-
*
|
| 5 |
-
* The DOM under ``#hy-chat`` is owned exclusively by this module —
|
| 6 |
-
* nothing in Gradio touches it. The server pushes JSON deltas via the
|
| 7 |
-
* hidden ``#hy-chat-delta`` ``gr.HTML`` component; we observe its
|
| 8 |
-
* mutations, parse, and apply each op to the chat container.
|
| 9 |
-
*
|
| 10 |
-
* Design notes
|
| 11 |
-
* ────────────
|
| 12 |
-
* 1. Append-only DOM. Each new bubble is its own ``.message-row``.
|
| 13 |
-
* The browser's per-row layout/paint isolation (``contain`` +
|
| 14 |
-
* ``content-visibility`` from ``_perf.css``) keeps rendering cost
|
| 15 |
-
* O(visible) regardless of conversation length.
|
| 16 |
-
*
|
| 17 |
-
* 2. Frozen / streaming split inside each assistant bubble. As content
|
| 18 |
-
* streams in, every paragraph (or fenced code / display math) that
|
| 19 |
-
* has CLOSED gets rendered ONCE into a stable ``.hy-frozen`` DOM
|
| 20 |
-
* subtree and never touched again — KaTeX, ``marked``, and the
|
| 21 |
-
* syntax highlighter all run exactly once per closed block. Only
|
| 22 |
-
* the trailing in-progress paragraph re-renders on each delta,
|
| 23 |
-
* and that block is small. As a result already-rendered formulas
|
| 24 |
-
* never flicker / re-layout mid-stream.
|
| 25 |
-
*
|
| 26 |
-
* 3. Wire payload is ~just the new characters. A 100-char delta is
|
| 27 |
-
* ~150 bytes on the wire, so WebSocket back-pressure essentially
|
| 28 |
-
* goes away.
|
| 29 |
-
*
|
| 30 |
-
* Op contract — keep in sync with chat.py:
|
| 31 |
-
*
|
| 32 |
-
* {type: "reset"}
|
| 33 |
-
* {type: "user", text: "..."}
|
| 34 |
-
* {type: "assistant_begin", id: "a-N"}
|
| 35 |
-
* {type: "reasoning_delta", id: "a-N", delta: "..."}
|
| 36 |
-
* {type: "content_delta", id: "a-N", delta: "...", thinking_done?: bool}
|
| 37 |
-
* {type: "assistant_end", id: "a-N"}
|
| 38 |
-
* {type: "tool_call", id: "a-N", markdown: "..."}
|
| 39 |
-
* {type: "remove_bubble", id: "a-N"}
|
| 40 |
-
*/
|
| 41 |
-
(() => {
|
| 42 |
-
if (window.__HY_CHAT_INIT) return;
|
| 43 |
-
window.__HY_CHAT_INIT = true;
|
| 44 |
-
|
| 45 |
-
// ─── State ─────────────────────────────────────────────────────────────
|
| 46 |
-
const state = {
|
| 47 |
-
host: null, // <div id="hy-chat">
|
| 48 |
-
bubbles: new Map(), // bubble_id -> bubble record (see ensureBubble)
|
| 49 |
-
lastSeq: 0, // de-dup gate against re-fires of the same payload
|
| 50 |
-
// Current chat epoch — bumped server-side every time the user clicks
|
| 51 |
-
// "+" / new_chat. Each delta payload carries the epoch it was
|
| 52 |
-
// produced under; deltas whose epoch doesn't match ours are dropped
|
| 53 |
-
// (they're tail bytes from a stream the user already abandoned).
|
| 54 |
-
// Initialised lazily from the first payload that arrives so legacy
|
| 55 |
-
// payloads without an epoch field still apply.
|
| 56 |
-
currentEpoch: null,
|
| 57 |
-
};
|
| 58 |
-
|
| 59 |
-
// ─── DOM helpers ───────────────────────────────────────────────────────
|
| 60 |
-
function ensureHost() {
|
| 61 |
-
if (state.host && document.contains(state.host)) return state.host;
|
| 62 |
-
state.host = document.getElementById("hy-chat");
|
| 63 |
-
return state.host;
|
| 64 |
-
}
|
| 65 |
-
|
| 66 |
-
function escapeHtml(s) {
|
| 67 |
-
return String(s)
|
| 68 |
-
.replace(/&/g, "&")
|
| 69 |
-
.replace(/</g, "<")
|
| 70 |
-
.replace(/>/g, ">")
|
| 71 |
-
.replace(/"/g, """)
|
| 72 |
-
.replace(/'/g, "'");
|
| 73 |
-
}
|
| 74 |
-
|
| 75 |
-
// ─── Markdown + math renderer ──────────────────────────────────────────
|
| 76 |
-
// We DELIBERATELY do not sanitize here. The rest of the app depends
|
| 77 |
-
// on the model being able to emit raw HTML (e.g.
|
| 78 |
-
// <details class="thinking-block">, the HTML-preview workflow on raw
|
| 79 |
-
// HTML code blocks). The model is trusted output for this product
|
| 80 |
-
// surface; if that ever changes, swap marked for a sanitizing parser
|
| 81 |
-
// like markdown-it + DOMPurify.
|
| 82 |
-
const MARKED_OPTS = { gfm: true, breaks: false };
|
| 83 |
-
|
| 84 |
-
const KATEX_DELIMS = [
|
| 85 |
-
{ left: "$$", right: "$$", display: true },
|
| 86 |
-
{ left: "$", right: "$", display: false },
|
| 87 |
-
// We pre-convert \[…\] / \(…\) → $$…$$ / $…$ via normalizeMathDelims
|
| 88 |
-
// BEFORE marked.parse runs (see below) — so the auto-render scan
|
| 89 |
-
// never needs to worry about them. They are NOT listed here on
|
| 90 |
-
// purpose: marked treats ``\[`` and ``\(`` as backslash escapes
|
| 91 |
-
// and silently drops the leading ``\`` in the rendered HTML, so by
|
| 92 |
-
// the time KaTeX scans the DOM the original bracket delimiters are
|
| 93 |
-
// already gone. Pre-conversion is the only reliable fix.
|
| 94 |
-
];
|
| 95 |
-
|
| 96 |
-
// ─── Math handling: two-stage pipeline ────────────────────────────────
|
| 97 |
-
//
|
| 98 |
-
// The model emits LaTeX in any of four delimiter styles: ``$$…$$``,
|
| 99 |
-
// ``\[…\]``, ``$…$``, ``\(…\)``. We need KaTeX (via auto-render) to
|
| 100 |
-
// pick all of them up while still letting ``marked.parse`` handle the
|
| 101 |
-
// surrounding markdown.
|
| 102 |
-
//
|
| 103 |
-
// Two problems block the naïve approach:
|
| 104 |
-
//
|
| 105 |
-
// 1. ``marked`` treats ``\[``, ``\]``, ``\(``, ``\)`` as backslash
|
| 106 |
-
// escapes and silently drops the ``\``. By the time KaTeX scans
|
| 107 |
-
// the rendered HTML the bracket delimiters are gone.
|
| 108 |
-
//
|
| 109 |
-
// 2. Even inside ``$$…$$``, ``marked`` strips backslashes before
|
| 110 |
-
// ``\{``, ``\}``, ``\_``, etc. — so things like ``\{(0:0:1:0)\}``
|
| 111 |
-
// lose their literal-brace escapes and KaTeX renders an empty
|
| 112 |
-
// group instead of the intended literal braces.
|
| 113 |
-
//
|
| 114 |
-
// The fix is two passes that together keep marked away from the math
|
| 115 |
-
// content:
|
| 116 |
-
//
|
| 117 |
-
// Stage A — ``normalizeMathDelims`` converts ``\[/\]`` → ``$$`` and
|
| 118 |
-
// ``\(/\)`` → ``$`` OUTSIDE fenced/inline code blocks. After this
|
| 119 |
-
// pass every math region is delimited with dollars.
|
| 120 |
-
//
|
| 121 |
-
// Stage B — ``protectMath`` extracts every ``$$…$$`` / ``$…$`` from
|
| 122 |
-
// the text and replaces it with a unique placeholder token (a NUL
|
| 123 |
-
// character that ``marked`` will leave alone). After ``marked.parse``
|
| 124 |
-
// we substitute the original math source back in. ``ignoredTags``
|
| 125 |
-
// already keeps KaTeX out of ``<pre>``/``<code>``, so the only
|
| 126 |
-
// regions that end up containing dollars in the rendered HTML are
|
| 127 |
-
// the math ones — exactly what we want.
|
| 128 |
-
//
|
| 129 |
-
// The placeholder uses NUL as a delimiter because ``marked`` cannot
|
| 130 |
-
// produce a literal NUL on its own (every input source we'd see is
|
| 131 |
-
// valid Unicode text without NULs), so the ``restoreMath`` regex is
|
| 132 |
-
// unambiguous.
|
| 133 |
-
function normalizeMathDelims(text) {
|
| 134 |
-
if (!text) return text;
|
| 135 |
-
let out = "";
|
| 136 |
-
let i = 0;
|
| 137 |
-
const n = text.length;
|
| 138 |
-
while (i < n) {
|
| 139 |
-
const ch = text[i];
|
| 140 |
-
|
| 141 |
-
// Triple-backtick or triple-tilde fenced block — passthrough until
|
| 142 |
-
// matching closing fence on its own (or anywhere on a) line.
|
| 143 |
-
if ((ch === "`" && text.startsWith("```", i)) ||
|
| 144 |
-
(ch === "~" && text.startsWith("~~~", i))) {
|
| 145 |
-
const marker = text.substr(i, 3);
|
| 146 |
-
out += marker;
|
| 147 |
-
i += 3;
|
| 148 |
-
const close = text.indexOf(marker, i);
|
| 149 |
-
if (close < 0) {
|
| 150 |
-
// Unclosed fence — emit rest verbatim and stop.
|
| 151 |
-
out += text.slice(i);
|
| 152 |
-
return out;
|
| 153 |
-
}
|
| 154 |
-
out += text.slice(i, close + 3);
|
| 155 |
-
i = close + 3;
|
| 156 |
-
continue;
|
| 157 |
-
}
|
| 158 |
-
|
| 159 |
-
// Inline code: single or double backticks, ended by the same run
|
| 160 |
-
// length. Common case is a single backtick.
|
| 161 |
-
if (ch === "`") {
|
| 162 |
-
let runLen = 1;
|
| 163 |
-
while (i + runLen < n && text[i + runLen] === "`") runLen++;
|
| 164 |
-
const open = text.substr(i, runLen);
|
| 165 |
-
out += open;
|
| 166 |
-
i += runLen;
|
| 167 |
-
const close = text.indexOf(open, i);
|
| 168 |
-
if (close < 0) {
|
| 169 |
-
out += text.slice(i);
|
| 170 |
-
return out;
|
| 171 |
-
}
|
| 172 |
-
out += text.slice(i, close + runLen);
|
| 173 |
-
i = close + runLen;
|
| 174 |
-
continue;
|
| 175 |
-
}
|
| 176 |
-
|
| 177 |
-
// Backslash-bracket / backslash-paren delimiters. Must be the
|
| 178 |
-
// FIRST conversion check after the code-fence skip so we don't
|
| 179 |
-
// mistake e.g. ``\[`` inside a code fence for math.
|
| 180 |
-
if (ch === "\\") {
|
| 181 |
-
if (text[i + 1] === "[") { out += "$$"; i += 2; continue; }
|
| 182 |
-
if (text[i + 1] === "]") { out += "$$"; i += 2; continue; }
|
| 183 |
-
if (text[i + 1] === "(") { out += "$"; i += 2; continue; }
|
| 184 |
-
if (text[i + 1] === ")") { out += "$"; i += 2; continue; }
|
| 185 |
-
}
|
| 186 |
-
|
| 187 |
-
out += ch;
|
| 188 |
-
i++;
|
| 189 |
-
}
|
| 190 |
-
return out;
|
| 191 |
-
}
|
| 192 |
-
|
| 193 |
-
// Inline math regex requires the opening ``$`` to be IMMEDIATELY
|
| 194 |
-
// followed by a non-space, non-``$`` char (avoids matching prices like
|
| 195 |
-
// ``I have $5 and $10``) and the closing ``$`` to be IMMEDIATELY
|
| 196 |
-
// preceded by a non-space, non-``$`` char. Display math (``$$…$$``)
|
| 197 |
-
// is matched first (the alternative is left-most-greedy in a JS
|
| 198 |
-
// regex, but with non-greedy bodies and ``$$`` being a longer prefix
|
| 199 |
-
// it wins ties naturally).
|
| 200 |
-
const MATH_RE = /\$\$[\s\S]+?\$\$|\$(?=[^\s$])[^\n$]*?(?<=[^\s$])\$/g;
|
| 201 |
-
|
| 202 |
-
function protectMath(text) {
|
| 203 |
-
const stash = [];
|
| 204 |
-
const escaped = text.replace(MATH_RE, (m) => {
|
| 205 |
-
const idx = stash.length;
|
| 206 |
-
stash.push(m);
|
| 207 |
-
return `\u0000M${idx}\u0000`;
|
| 208 |
-
});
|
| 209 |
-
return { escaped, stash };
|
| 210 |
-
}
|
| 211 |
-
|
| 212 |
-
function restoreMath(html, stash) {
|
| 213 |
-
if (!stash.length) return html;
|
| 214 |
-
return html.replace(/\u0000M(\d+)\u0000/g, (_, n) => stash[+n]);
|
| 215 |
-
}
|
| 216 |
-
|
| 217 |
-
function renderMarkdownInto(el, text) {
|
| 218 |
-
if (!text) {
|
| 219 |
-
el.innerHTML = "";
|
| 220 |
-
return;
|
| 221 |
-
}
|
| 222 |
-
const normalized = normalizeMathDelims(text);
|
| 223 |
-
const { escaped, stash } = protectMath(normalized);
|
| 224 |
-
const rawMd = (window.marked && window.marked.parse)
|
| 225 |
-
? window.marked.parse(escaped, MARKED_OPTS)
|
| 226 |
-
: escapeHtml(escaped);
|
| 227 |
-
el.innerHTML = restoreMath(rawMd, stash);
|
| 228 |
-
|
| 229 |
-
// Math
|
| 230 |
-
if (window.renderMathInElement) {
|
| 231 |
-
try {
|
| 232 |
-
window.renderMathInElement(el, {
|
| 233 |
-
delimiters: KATEX_DELIMS,
|
| 234 |
-
throwOnError: false,
|
| 235 |
-
// Skip math-detection inside elements that should never contain
|
| 236 |
-
// math (matches KaTeX auto-render defaults).
|
| 237 |
-
ignoredTags: ["script", "noscript", "style", "textarea", "pre", "code"],
|
| 238 |
-
});
|
| 239 |
-
} catch (err) {
|
| 240 |
-
console.warn("[hy-chat] katex render error:", err);
|
| 241 |
-
}
|
| 242 |
-
}
|
| 243 |
-
|
| 244 |
-
// Syntax highlighting (idempotent if hljs not loaded yet)
|
| 245 |
-
if (window.hljs && window.hljs.highlightElement) {
|
| 246 |
-
const codes = el.querySelectorAll("pre code");
|
| 247 |
-
for (let i = 0; i < codes.length; i++) {
|
| 248 |
-
const c = codes[i];
|
| 249 |
-
if (c.dataset.hljsDone) continue;
|
| 250 |
-
try {
|
| 251 |
-
window.hljs.highlightElement(c);
|
| 252 |
-
} catch (err) {
|
| 253 |
-
// hljs throws if the language is unknown — harmless, ignore.
|
| 254 |
-
}
|
| 255 |
-
c.dataset.hljsDone = "1";
|
| 256 |
-
}
|
| 257 |
-
}
|
| 258 |
-
}
|
| 259 |
-
|
| 260 |
-
// ─── Frozen / streaming split ──────────────────────────────────────────
|
| 261 |
-
// Find the highest "safe" boundary in the current content buffer up to
|
| 262 |
-
// which we can freeze the rendered DOM and never touch it again. A
|
| 263 |
-
// boundary is safe iff the markdown above it forms a complete set of
|
| 264 |
-
// top-level blocks — i.e. we are NOT inside an open fenced code block
|
| 265 |
-
// (``` / ~~~), display math ($$), or LaTeX env (\begin{…}).
|
| 266 |
-
//
|
| 267 |
-
// Returns the index in ``text`` immediately after the last safe block
|
| 268 |
-
// separator (\n\n).
|
| 269 |
-
function findFreezeBoundary(text) {
|
| 270 |
-
const len = text.length;
|
| 271 |
-
let i = 0;
|
| 272 |
-
let inFence = false; // inside ``` … ``` or ~~~ … ~~~
|
| 273 |
-
let fenceMarker = null;
|
| 274 |
-
let inMath = false; // inside $$ … $$
|
| 275 |
-
let inEnv = false; // inside \begin{…} … \end{…}
|
| 276 |
-
let lastSafe = 0;
|
| 277 |
-
|
| 278 |
-
while (i < len) {
|
| 279 |
-
const ch = text[i];
|
| 280 |
-
|
| 281 |
-
// Fence detection (must check before single-char paths)
|
| 282 |
-
if (!inMath && !inEnv) {
|
| 283 |
-
if (ch === "`" && text.startsWith("```", i)) {
|
| 284 |
-
if (!inFence) { inFence = true; fenceMarker = "```"; }
|
| 285 |
-
else if (fenceMarker === "```") { inFence = false; fenceMarker = null; }
|
| 286 |
-
i += 3;
|
| 287 |
-
continue;
|
| 288 |
-
}
|
| 289 |
-
if (ch === "~" && text.startsWith("~~~", i)) {
|
| 290 |
-
if (!inFence) { inFence = true; fenceMarker = "~~~"; }
|
| 291 |
-
else if (fenceMarker === "~~~") { inFence = false; fenceMarker = null; }
|
| 292 |
-
i += 3;
|
| 293 |
-
continue;
|
| 294 |
-
}
|
| 295 |
-
}
|
| 296 |
-
|
| 297 |
-
if (inFence) { i++; continue; }
|
| 298 |
-
|
| 299 |
-
// Display math $$ … $$
|
| 300 |
-
if (!inEnv && ch === "$" && text[i + 1] === "$") {
|
| 301 |
-
inMath = !inMath;
|
| 302 |
-
i += 2;
|
| 303 |
-
continue;
|
| 304 |
-
}
|
| 305 |
-
|
| 306 |
-
if (inMath) { i++; continue; }
|
| 307 |
-
|
| 308 |
-
// \begin{env} … \end{env}
|
| 309 |
-
if (ch === "\\") {
|
| 310 |
-
if (text.startsWith("\\begin{", i)) { inEnv = true; i += 7; continue; }
|
| 311 |
-
if (text.startsWith("\\end{", i)) { inEnv = false; i += 5; continue; }
|
| 312 |
-
}
|
| 313 |
-
|
| 314 |
-
if (inEnv) { i++; continue; }
|
| 315 |
-
|
| 316 |
-
// Paragraph break outside any block — candidate freeze point.
|
| 317 |
-
if (ch === "\n" && text[i + 1] === "\n") {
|
| 318 |
-
// Skip past the entire run of blank lines so we don't freeze
|
| 319 |
-
// mid-blank-paragraph.
|
| 320 |
-
let j = i + 2;
|
| 321 |
-
while (j < len && (text[j] === "\n" || text[j] === " " || text[j] === "\t")) j++;
|
| 322 |
-
lastSafe = j;
|
| 323 |
-
i = j;
|
| 324 |
-
continue;
|
| 325 |
-
}
|
| 326 |
-
|
| 327 |
-
i++;
|
| 328 |
-
}
|
| 329 |
-
|
| 330 |
-
return lastSafe;
|
| 331 |
-
}
|
| 332 |
-
|
| 333 |
-
// ─── Bubble lifecycle ──────────────────────────────────────────────────
|
| 334 |
-
function ensureBubble(id) {
|
| 335 |
-
return state.bubbles.get(id);
|
| 336 |
-
}
|
| 337 |
-
|
| 338 |
-
// Re-fire ``hy-chat:updated`` so the scroll-lock in app.js reconsiders
|
| 339 |
-
// whether to re-pin to the bottom now that geometry may have changed.
|
| 340 |
-
// Coalesced via rAF so a flurry of layout changes (e.g. KaTeX +
|
| 341 |
-
// hljs + table column-width pass all in the same frame) only
|
| 342 |
-
// dispatches once.
|
| 343 |
-
let _nudgePending = false;
|
| 344 |
-
function nudgeScrollSoon() {
|
| 345 |
-
if (_nudgePending) return;
|
| 346 |
-
_nudgePending = true;
|
| 347 |
-
requestAnimationFrame(() => {
|
| 348 |
-
_nudgePending = false;
|
| 349 |
-
if (!state.host) return;
|
| 350 |
-
state.host.dispatchEvent(new CustomEvent("hy-chat:updated", {
|
| 351 |
-
bubbles: false,
|
| 352 |
-
}));
|
| 353 |
-
});
|
| 354 |
-
}
|
| 355 |
-
|
| 356 |
-
// Forces ``row`` to flush any pending layout, then schedules a
|
| 357 |
-
// single rAF-coalesced ``hy-chat:updated`` dispatch. Used both
|
| 358 |
-
// when a ``<details>`` toggles and as the ``ResizeObserver``
|
| 359 |
-
// callback for each row.
|
| 360 |
-
function nudgeScrollAfterToggle(b) {
|
| 361 |
-
if (!b || !b.row) return;
|
| 362 |
-
void b.row.offsetHeight;
|
| 363 |
-
nudgeScrollSoon();
|
| 364 |
-
}
|
| 365 |
-
|
| 366 |
-
// Per-row ResizeObserver. Many things that change a row's height
|
| 367 |
-
// happen ASYNCHRONOUSLY after the streaming op that created the
|
| 368 |
-
// content: KaTeX glyphs render once their fonts arrive, hljs
|
| 369 |
-
// decorates code blocks on the next idle tick, browsers do a
|
| 370 |
-
// second column-width pass on tables once all rows are in. None
|
| 371 |
-
// of these go through ``applyDelta`` so the scroll-lock would
|
| 372 |
-
// otherwise miss them, leaving the user stuck at a now-stale
|
| 373 |
-
// ``scrollHeight - clientHeight``. Wiring a ResizeObserver per
|
| 374 |
-
// row covers all of them with one mechanism.
|
| 375 |
-
const _rowResizeObserver =
|
| 376 |
-
typeof ResizeObserver !== "undefined"
|
| 377 |
-
? new ResizeObserver(() => nudgeScrollSoon())
|
| 378 |
-
: null;
|
| 379 |
-
|
| 380 |
-
function createAssistantBubble(id) {
|
| 381 |
-
const row = document.createElement("div");
|
| 382 |
-
row.className = "message-row bot-row";
|
| 383 |
-
row.dataset.testid = "bot";
|
| 384 |
-
row.dataset.role = "assistant";
|
| 385 |
-
row.dataset.bubbleId = id;
|
| 386 |
-
|
| 387 |
-
const msg = document.createElement("div");
|
| 388 |
-
msg.className = "message bot";
|
| 389 |
-
|
| 390 |
-
const md = document.createElement("div");
|
| 391 |
-
md.className = "markdown hy-markdown";
|
| 392 |
-
|
| 393 |
-
const typing = document.createElement("div");
|
| 394 |
-
typing.className = "typing-indicator hy-typing";
|
| 395 |
-
typing.innerHTML = "<span></span><span></span><span></span>";
|
| 396 |
-
md.appendChild(typing);
|
| 397 |
-
|
| 398 |
-
msg.appendChild(md);
|
| 399 |
-
row.appendChild(msg);
|
| 400 |
-
state.host.appendChild(row);
|
| 401 |
-
if (_rowResizeObserver) _rowResizeObserver.observe(row);
|
| 402 |
-
|
| 403 |
-
const record = {
|
| 404 |
-
row, md, typing,
|
| 405 |
-
// Reasoning (optional, lazily created)
|
| 406 |
-
reasoningEl: null,
|
| 407 |
-
reasoningSummaryEl: null,
|
| 408 |
-
reasoningBodyEl: null,
|
| 409 |
-
reasoningBuf: "",
|
| 410 |
-
thinkingDone: false,
|
| 411 |
-
// Content (lazily created on first content_delta)
|
| 412 |
-
frozenEl: null,
|
| 413 |
-
streamingEl: null,
|
| 414 |
-
contentBuf: "",
|
| 415 |
-
frozenLen: 0,
|
| 416 |
-
// Tool-call append region (lazily created)
|
| 417 |
-
toolCallContainer: null,
|
| 418 |
-
ended: false,
|
| 419 |
-
};
|
| 420 |
-
state.bubbles.set(id, record);
|
| 421 |
-
return record;
|
| 422 |
-
}
|
| 423 |
-
|
| 424 |
-
function ensureReasoning(b) {
|
| 425 |
-
if (b.reasoningEl) return;
|
| 426 |
-
const det = document.createElement("details");
|
| 427 |
-
det.className = "thinking-block";
|
| 428 |
-
det.open = true;
|
| 429 |
-
const sum = document.createElement("summary");
|
| 430 |
-
sum.textContent = (window.HY_I18N && window.HY_I18N.thinking) || "Thinking...";
|
| 431 |
-
det.appendChild(sum);
|
| 432 |
-
const body = document.createElement("div");
|
| 433 |
-
body.className = "hy-reasoning-body";
|
| 434 |
-
body.style.whiteSpace = "pre-wrap";
|
| 435 |
-
body.style.wordBreak = "break-word";
|
| 436 |
-
det.appendChild(body);
|
| 437 |
-
b.reasoningEl = det;
|
| 438 |
-
b.reasoningSummaryEl = sum;
|
| 439 |
-
b.reasoningBodyEl = body;
|
| 440 |
-
if (b.typing && b.typing.parentNode) b.typing.remove();
|
| 441 |
-
// Reasoning always goes ABOVE content, even if content has already
|
| 442 |
-
// started rendering (rare — most models stream reasoning first).
|
| 443 |
-
b.md.insertBefore(det, b.md.firstChild);
|
| 444 |
-
// Keep the parent chat's scroll geometry in sync whenever the user
|
| 445 |
-
// (or markThinkingDone) toggles this block. See nudgeScrollAfterToggle.
|
| 446 |
-
det.addEventListener("toggle", () => nudgeScrollAfterToggle(b));
|
| 447 |
-
}
|
| 448 |
-
|
| 449 |
-
function ensureContent(b) {
|
| 450 |
-
if (b.frozenEl) return;
|
| 451 |
-
if (b.typing && b.typing.parentNode) b.typing.remove();
|
| 452 |
-
const frozen = document.createElement("div");
|
| 453 |
-
frozen.className = "hy-frozen";
|
| 454 |
-
const streaming = document.createElement("div");
|
| 455 |
-
streaming.className = "hy-streaming";
|
| 456 |
-
b.md.appendChild(frozen);
|
| 457 |
-
b.md.appendChild(streaming);
|
| 458 |
-
b.frozenEl = frozen;
|
| 459 |
-
b.streamingEl = streaming;
|
| 460 |
-
}
|
| 461 |
-
|
| 462 |
-
function markThinkingDone(b) {
|
| 463 |
-
if (!b.reasoningEl || b.thinkingDone) return;
|
| 464 |
-
b.thinkingDone = true;
|
| 465 |
-
b.reasoningSummaryEl.textContent =
|
| 466 |
-
(window.HY_I18N && window.HY_I18N.thinking_done) || "Thought";
|
| 467 |
-
b.reasoningEl.open = false;
|
| 468 |
-
}
|
| 469 |
-
|
| 470 |
-
// ─── Op handlers ───────────────────────────────────────────────────────
|
| 471 |
-
function opReset() {
|
| 472 |
-
if (_rowResizeObserver) {
|
| 473 |
-
for (const b of state.bubbles.values()) {
|
| 474 |
-
if (b.row) _rowResizeObserver.unobserve(b.row);
|
| 475 |
-
}
|
| 476 |
-
}
|
| 477 |
-
state.host.innerHTML = "";
|
| 478 |
-
state.bubbles.clear();
|
| 479 |
-
state.lastSeq = 0;
|
| 480 |
-
// currentEpoch is updated by applyDelta BEFORE op dispatch when a
|
| 481 |
-
// reset op is in the payload — see the epoch handling there. We
|
| 482 |
-
// intentionally do NOT clear it here, otherwise we'd reopen the
|
| 483 |
-
// window for stale post-reset deltas.
|
| 484 |
-
}
|
| 485 |
-
|
| 486 |
-
function opUser(op) {
|
| 487 |
-
const row = document.createElement("div");
|
| 488 |
-
row.className = "message-row user-row";
|
| 489 |
-
row.dataset.testid = "user";
|
| 490 |
-
row.dataset.role = "user";
|
| 491 |
-
|
| 492 |
-
const msg = document.createElement("div");
|
| 493 |
-
msg.className = "message user user-message";
|
| 494 |
-
|
| 495 |
-
const md = document.createElement("div");
|
| 496 |
-
md.className = "markdown hy-markdown hy-user-text";
|
| 497 |
-
// Render as plain text — never run user input through marked / KaTeX.
|
| 498 |
-
md.style.whiteSpace = "pre-wrap";
|
| 499 |
-
md.style.wordBreak = "break-word";
|
| 500 |
-
md.textContent = op.text || "";
|
| 501 |
-
|
| 502 |
-
msg.appendChild(md);
|
| 503 |
-
row.appendChild(msg);
|
| 504 |
-
state.host.appendChild(row);
|
| 505 |
-
}
|
| 506 |
-
|
| 507 |
-
function opAssistantBegin(op) {
|
| 508 |
-
if (state.bubbles.has(op.id)) return; // idempotent on retry
|
| 509 |
-
createAssistantBubble(op.id);
|
| 510 |
-
}
|
| 511 |
-
|
| 512 |
-
function opReasoningDelta(op) {
|
| 513 |
-
let b = ensureBubble(op.id);
|
| 514 |
-
if (!b) b = createAssistantBubble(op.id);
|
| 515 |
-
ensureReasoning(b);
|
| 516 |
-
const d = op.delta || "";
|
| 517 |
-
if (!d) return;
|
| 518 |
-
b.reasoningBuf += d;
|
| 519 |
-
// Reasoning is shown as raw text — fast and never re-renders math.
|
| 520 |
-
// Append-only via textContent means even very long reasoning stays
|
| 521 |
-
// O(delta) per update; the DOM tree is just a single text node.
|
| 522 |
-
b.reasoningBodyEl.textContent = b.reasoningBuf;
|
| 523 |
-
// Keep the latest reasoning line visible inside the (max-height-
|
| 524 |
-
// scrollable) details body.
|
| 525 |
-
b.reasoningBodyEl.scrollTop = b.reasoningBodyEl.scrollHeight;
|
| 526 |
-
}
|
| 527 |
-
|
| 528 |
-
function opContentDelta(op) {
|
| 529 |
-
let b = ensureBubble(op.id);
|
| 530 |
-
if (!b) b = createAssistantBubble(op.id);
|
| 531 |
-
if (op.thinking_done) markThinkingDone(b);
|
| 532 |
-
ensureContent(b);
|
| 533 |
-
const d = op.delta || "";
|
| 534 |
-
if (!d) return;
|
| 535 |
-
b.contentBuf += d;
|
| 536 |
-
|
| 537 |
-
// Compute new freeze boundary. If it advanced past the last frozen
|
| 538 |
-
// length, render JUST the newly-frozen chunk (text since last
|
| 539 |
-
// boundary) ONCE and APPEND its DOM to the frozen container. The
|
| 540 |
-
// already-frozen DOM is never touched — KaTeX, hljs, and marked
|
| 541 |
-
// run exactly once per closed block.
|
| 542 |
-
//
|
| 543 |
-
// Why we can render the new chunk in isolation: the boundary is
|
| 544 |
-
// always at a paragraph break (\n\n) outside any open code fence /
|
| 545 |
-
// display math / LaTeX env, so each chunk is a complete set of
|
| 546 |
-
// top-level markdown blocks that ``marked`` parses identically
|
| 547 |
-
// whether or not it has the prior context.
|
| 548 |
-
const text = b.contentBuf;
|
| 549 |
-
const newBoundary = findFreezeBoundary(text);
|
| 550 |
-
if (newBoundary > b.frozenLen) {
|
| 551 |
-
const newChunk = text.slice(b.frozenLen, newBoundary);
|
| 552 |
-
const temp = document.createElement("div");
|
| 553 |
-
renderMarkdownInto(temp, newChunk);
|
| 554 |
-
// Move children from temp into frozenEl. Moving (not cloning)
|
| 555 |
-
// preserves the KaTeX/hljs work we just did, and crucially does
|
| 556 |
-
// NOT re-trigger any rendering of the already-frozen DOM.
|
| 557 |
-
while (temp.firstChild) {
|
| 558 |
-
b.frozenEl.appendChild(temp.firstChild);
|
| 559 |
-
}
|
| 560 |
-
b.frozenLen = newBoundary;
|
| 561 |
-
}
|
| 562 |
-
// Streaming segment (everything after the boundary) is re-rendered
|
| 563 |
-
// in full on each delta. It's bounded to roughly one paragraph, so
|
| 564 |
-
// the KaTeX / marked / hljs work is O(paragraph) — and since
|
| 565 |
-
// ``innerHTML = ...`` wipes the previous DOM, KaTeX never
|
| 566 |
-
// double-renders the same formula here either.
|
| 567 |
-
const streamingText = text.slice(b.frozenLen);
|
| 568 |
-
renderMarkdownInto(b.streamingEl, streamingText);
|
| 569 |
-
}
|
| 570 |
-
|
| 571 |
-
function opAssistantEnd(op) {
|
| 572 |
-
const b = ensureBubble(op.id);
|
| 573 |
-
if (!b) return;
|
| 574 |
-
b.ended = true;
|
| 575 |
-
if (b.typing && b.typing.parentNode) b.typing.remove();
|
| 576 |
-
// Defer one extra nudge to the next animation frame: post-stream
|
| 577 |
-
// KaTeX/hljs decoration of the just-flushed tail can run after
|
| 578 |
-
// applyDelta returns, growing the bubble's height beyond what
|
| 579 |
-
// ``hy-chat:updated`` already saw at the end of this op.
|
| 580 |
-
nudgeScrollSoon();
|
| 581 |
-
// Final flush: take whatever is still in the streaming segment and
|
| 582 |
-
// append it to the frozen container as one last chunk, then empty
|
| 583 |
-
// streaming. Crucially we do NOT re-render the already-frozen DOM
|
| 584 |
-
// — that would re-run KaTeX over every formula the user has been
|
| 585 |
-
// looking at and produce a final visible flicker.
|
| 586 |
-
if (b.contentBuf) {
|
| 587 |
-
ensureContent(b);
|
| 588 |
-
const tail = b.contentBuf.slice(b.frozenLen);
|
| 589 |
-
if (tail) {
|
| 590 |
-
const temp = document.createElement("div");
|
| 591 |
-
renderMarkdownInto(temp, tail);
|
| 592 |
-
while (temp.firstChild) {
|
| 593 |
-
b.frozenEl.appendChild(temp.firstChild);
|
| 594 |
-
}
|
| 595 |
-
}
|
| 596 |
-
b.frozenLen = b.contentBuf.length;
|
| 597 |
-
b.streamingEl.innerHTML = "";
|
| 598 |
-
} else if (b.streamingEl) {
|
| 599 |
-
// No content at all (might be tool-call only) — clean up.
|
| 600 |
-
b.streamingEl.innerHTML = "";
|
| 601 |
-
}
|
| 602 |
-
if (b.reasoningEl && !b.thinkingDone) markThinkingDone(b);
|
| 603 |
-
}
|
| 604 |
-
|
| 605 |
-
function opToolCall(op) {
|
| 606 |
-
let b = ensureBubble(op.id);
|
| 607 |
-
if (!b) b = createAssistantBubble(op.id);
|
| 608 |
-
if (b.typing && b.typing.parentNode) b.typing.remove();
|
| 609 |
-
if (!b.toolCallContainer) {
|
| 610 |
-
const c = document.createElement("div");
|
| 611 |
-
c.className = "hy-tool-calls";
|
| 612 |
-
b.md.appendChild(c);
|
| 613 |
-
b.toolCallContainer = c;
|
| 614 |
-
}
|
| 615 |
-
const tc = document.createElement("div");
|
| 616 |
-
tc.className = "hy-tool-call";
|
| 617 |
-
renderMarkdownInto(tc, op.markdown || "");
|
| 618 |
-
b.toolCallContainer.appendChild(tc);
|
| 619 |
-
}
|
| 620 |
-
|
| 621 |
-
function opRemoveBubble(op) {
|
| 622 |
-
const b = ensureBubble(op.id);
|
| 623 |
-
if (!b) return;
|
| 624 |
-
if (_rowResizeObserver && b.row) _rowResizeObserver.unobserve(b.row);
|
| 625 |
-
if (b.row && b.row.parentNode) b.row.parentNode.removeChild(b.row);
|
| 626 |
-
state.bubbles.delete(op.id);
|
| 627 |
-
}
|
| 628 |
-
|
| 629 |
-
function applyOp(op) {
|
| 630 |
-
if (!op || !op.type) return;
|
| 631 |
-
if (!ensureHost()) return;
|
| 632 |
-
switch (op.type) {
|
| 633 |
-
case "reset": opReset(); break;
|
| 634 |
-
case "user": opUser(op); break;
|
| 635 |
-
case "assistant_begin": opAssistantBegin(op); break;
|
| 636 |
-
case "reasoning_delta": opReasoningDelta(op); break;
|
| 637 |
-
case "content_delta": opContentDelta(op); break;
|
| 638 |
-
case "assistant_end": opAssistantEnd(op); break;
|
| 639 |
-
case "tool_call": opToolCall(op); break;
|
| 640 |
-
case "remove_bubble": opRemoveBubble(op); break;
|
| 641 |
-
default:
|
| 642 |
-
console.warn("[hy-chat] unknown op type:", op.type);
|
| 643 |
-
}
|
| 644 |
-
}
|
| 645 |
-
|
| 646 |
-
function applyDelta(payload) {
|
| 647 |
-
if (!payload || typeof payload !== "object") return;
|
| 648 |
-
const seq = typeof payload.seq === "number" ? payload.seq : null;
|
| 649 |
-
// Dedup: Gradio occasionally re-fires the same component value on
|
| 650 |
-
// reconnect. Since each delta has a fresh global seq, anything ≤
|
| 651 |
-
// lastSeq is a re-fire we've already applied.
|
| 652 |
-
if (seq !== null && seq <= state.lastSeq) return;
|
| 653 |
-
if (seq !== null) state.lastSeq = seq;
|
| 654 |
-
const ops = Array.isArray(payload.ops) ? payload.ops : [];
|
| 655 |
-
|
| 656 |
-
// ── Stale-epoch drop ────────────────────────────────────────────
|
| 657 |
-
// The user clicked "+" mid-stream. The reset payload carries a NEW
|
| 658 |
-
// epoch; we adopt it and apply the reset. Any later payload from
|
| 659 |
-
// the cancelled generator still carries the OLD epoch and is
|
| 660 |
-
// dropped here — without this, late content_delta ops would
|
| 661 |
-
// ``createAssistantBubble`` for the old bubble id and a ghost
|
| 662 |
-
// bubble would appear in the freshly-cleared chat.
|
| 663 |
-
const epoch = payload.epoch;
|
| 664 |
-
if (epoch !== undefined && epoch !== null) {
|
| 665 |
-
const hasReset = ops.some((op) => op && op.type === "reset");
|
| 666 |
-
if (hasReset) {
|
| 667 |
-
state.currentEpoch = epoch;
|
| 668 |
-
} else if (state.currentEpoch === null) {
|
| 669 |
-
// First payload of the session: adopt whatever epoch we see.
|
| 670 |
-
state.currentEpoch = epoch;
|
| 671 |
-
} else if (epoch !== state.currentEpoch) {
|
| 672 |
-
return;
|
| 673 |
-
}
|
| 674 |
-
}
|
| 675 |
-
|
| 676 |
-
for (let i = 0; i < ops.length; i++) {
|
| 677 |
-
try {
|
| 678 |
-
applyOp(ops[i]);
|
| 679 |
-
} catch (err) {
|
| 680 |
-
console.error("[hy-chat] op failed:", ops[i], err);
|
| 681 |
-
}
|
| 682 |
-
}
|
| 683 |
-
// Notify subscribers (the scroll lock and code-block injector in
|
| 684 |
-
// app.js) that the chat DOM changed. We dispatch a single CustomEvent
|
| 685 |
-
// per applied delta — coarser than per-op so subscribers can do their
|
| 686 |
-
// own coalescing on top.
|
| 687 |
-
if (state.host) {
|
| 688 |
-
state.host.dispatchEvent(new CustomEvent("hy-chat:updated", {
|
| 689 |
-
bubbles: false,
|
| 690 |
-
}));
|
| 691 |
-
}
|
| 692 |
-
}
|
| 693 |
-
|
| 694 |
-
// ─── Wire up the delta channel ─────────────────────────────────────────
|
| 695 |
-
function startDeltaObserver() {
|
| 696 |
-
const deltaHost = document.getElementById("hy-chat-delta");
|
| 697 |
-
if (!deltaHost) {
|
| 698 |
-
setTimeout(startDeltaObserver, 200);
|
| 699 |
-
return;
|
| 700 |
-
}
|
| 701 |
-
let lastValue = "";
|
| 702 |
-
function handle() {
|
| 703 |
-
// Gradio may put the value in textContent or in a nested element
|
| 704 |
-
// depending on version. Walk the subtree to be defensive.
|
| 705 |
-
//
|
| 706 |
-
// While a generator is actively yielding, Gradio also injects a
|
| 707 |
-
// status / elapsed-time text node ("0.0s", "0.1s", …) INSIDE the
|
| 708 |
-
// output component's wrapper. That node bubbles into textContent
|
| 709 |
-
// and ticks every ~100ms, which would (a) make JSON.parse choke
|
| 710 |
-
// on the leading "0.0s" prefix and (b) re-fire the observer on
|
| 711 |
-
// every timer tick. Slice from the first '{' to the last '}' to
|
| 712 |
-
// skip the status overlay entirely.
|
| 713 |
-
const raw = (deltaHost.textContent || "");
|
| 714 |
-
const start = raw.indexOf("{");
|
| 715 |
-
const end = raw.lastIndexOf("}");
|
| 716 |
-
if (start < 0 || end < start) return;
|
| 717 |
-
const v = raw.slice(start, end + 1);
|
| 718 |
-
if (!v || v === lastValue) return;
|
| 719 |
-
lastValue = v;
|
| 720 |
-
let payload;
|
| 721 |
-
try {
|
| 722 |
-
payload = JSON.parse(v);
|
| 723 |
-
} catch (err) {
|
| 724 |
-
// Real malformed payload (rare): keep visibility, but at debug
|
| 725 |
-
// level so the timer overlay can't ever spam the console.
|
| 726 |
-
console.debug("[hy-chat] bad delta JSON:", v.slice(0, 200), err);
|
| 727 |
-
return;
|
| 728 |
-
}
|
| 729 |
-
applyDelta(payload);
|
| 730 |
-
}
|
| 731 |
-
new MutationObserver(handle).observe(deltaHost, {
|
| 732 |
-
childList: true,
|
| 733 |
-
subtree: true,
|
| 734 |
-
characterData: true,
|
| 735 |
-
});
|
| 736 |
-
handle(); // pick up initial value if any
|
| 737 |
-
}
|
| 738 |
-
|
| 739 |
-
function init() {
|
| 740 |
-
if (!ensureHost()) {
|
| 741 |
-
setTimeout(init, 200);
|
| 742 |
-
return;
|
| 743 |
-
}
|
| 744 |
-
startDeltaObserver();
|
| 745 |
-
}
|
| 746 |
-
|
| 747 |
-
// Public surface for the rest of the page (app.js).
|
| 748 |
-
window.HY_CHAT = {
|
| 749 |
-
init,
|
| 750 |
-
applyDelta,
|
| 751 |
-
getHost: ensureHost,
|
| 752 |
-
};
|
| 753 |
-
|
| 754 |
-
if (document.readyState === "loading") {
|
| 755 |
-
document.addEventListener("DOMContentLoaded", () => setTimeout(init, 200));
|
| 756 |
-
} else {
|
| 757 |
-
setTimeout(init, 200);
|
| 758 |
-
}
|
| 759 |
-
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_chat.css
DELETED
|
@@ -1,144 +0,0 @@
|
|
| 1 |
-
/* ─────────────────────────────────────────────────────────────────────────
|
| 2 |
-
* Custom chat surface
|
| 3 |
-
*
|
| 4 |
-
* Layout
|
| 5 |
-
* ──────
|
| 6 |
-
* #hy-chat-host → the gr.HTML wrapper component. Owns the
|
| 7 |
-
* viewport-relative height; pure flex container.
|
| 8 |
-
* #hy-chat → our scrollable chat surface. Append-only DOM
|
| 9 |
-
* owned by static/chat.js; one .message-row per
|
| 10 |
-
* bubble.
|
| 11 |
-
*
|
| 12 |
-
* The rest of the file is component styling for the renderer's emitted
|
| 13 |
-
* DOM. The class names (``.message-row``, ``.message``, ``.bot``,
|
| 14 |
-
* ``.user``, ``.markdown``) are deliberately shared with the rules in
|
| 15 |
-
* _chatbot.css / _math.css / _thinking.css / _misc.css so those
|
| 16 |
-
* rulesets apply transparently to our bubbles.
|
| 17 |
-
* ───────────────────────────────────────────────────────────────────────── */
|
| 18 |
-
|
| 19 |
-
/* ── Outer wrapper: takes up the available vertical space. ─────────────
|
| 20 |
-
* We use absolute positioning on #hy-chat so it pins to all four edges
|
| 21 |
-
* of the host regardless of how many intermediate wrapper divs Gradio
|
| 22 |
-
* inserts (varies between versions). The host establishes the
|
| 23 |
-
* positioning context with ``position: relative``. */
|
| 24 |
-
#hy-chat-host {
|
| 25 |
-
position: relative !important;
|
| 26 |
-
height: calc(100vh - 200px) !important;
|
| 27 |
-
padding: 0 !important;
|
| 28 |
-
margin: 0 !important;
|
| 29 |
-
background: var(--hy-bg) !important;
|
| 30 |
-
border: none !important;
|
| 31 |
-
box-shadow: none !important;
|
| 32 |
-
min-height: 0 !important;
|
| 33 |
-
overflow: hidden !important;
|
| 34 |
-
}
|
| 35 |
-
/* Strip styling and positioning from any wrappers Gradio inserts
|
| 36 |
-
* between #hy-chat-host and #hy-chat — they would otherwise create new
|
| 37 |
-
* containing blocks and break the absolute-positioned scroll surface. */
|
| 38 |
-
#hy-chat-host > div,
|
| 39 |
-
#hy-chat-host > div > div {
|
| 40 |
-
position: static !important;
|
| 41 |
-
padding: 0 !important;
|
| 42 |
-
margin: 0 !important;
|
| 43 |
-
background: transparent !important;
|
| 44 |
-
border: none !important;
|
| 45 |
-
box-shadow: none !important;
|
| 46 |
-
height: auto !important;
|
| 47 |
-
}
|
| 48 |
-
|
| 49 |
-
/* ── Inner scrollable surface ──────────────────────────────────────────── */
|
| 50 |
-
#hy-chat {
|
| 51 |
-
position: absolute;
|
| 52 |
-
inset: 0;
|
| 53 |
-
overflow-y: auto;
|
| 54 |
-
overflow-x: hidden;
|
| 55 |
-
padding: 16px 24px 32px;
|
| 56 |
-
background: var(--hy-bg);
|
| 57 |
-
scroll-behavior: auto; /* programmatic scroll-to-bottom should be instant */
|
| 58 |
-
}
|
| 59 |
-
|
| 60 |
-
/* ── Message rows ──────────────────────────────────────────────────────── */
|
| 61 |
-
#hy-chat .message-row {
|
| 62 |
-
display: block;
|
| 63 |
-
width: 100%;
|
| 64 |
-
margin: 0 0 4px;
|
| 65 |
-
padding: 0;
|
| 66 |
-
}
|
| 67 |
-
#hy-chat .message-row.user-row {
|
| 68 |
-
/* Right-align user messages similar to Gradio's bubble layout. */
|
| 69 |
-
display: flex;
|
| 70 |
-
justify-content: flex-end;
|
| 71 |
-
margin: 12px 0 8px;
|
| 72 |
-
}
|
| 73 |
-
#hy-chat .message-row.bot-row {
|
| 74 |
-
margin: 0 0 18px;
|
| 75 |
-
}
|
| 76 |
-
|
| 77 |
-
/* ── Inner message containers ──────────────────────────────────────────── */
|
| 78 |
-
#hy-chat .message {
|
| 79 |
-
max-width: 95%;
|
| 80 |
-
background: transparent;
|
| 81 |
-
border: none;
|
| 82 |
-
padding: 0;
|
| 83 |
-
}
|
| 84 |
-
#hy-chat .message.user {
|
| 85 |
-
background: var(--hy-bg-muted, #f5f5f7);
|
| 86 |
-
border-radius: 18px;
|
| 87 |
-
padding: 10px 18px !important;
|
| 88 |
-
max-width: min(720px, 75%);
|
| 89 |
-
}
|
| 90 |
-
.dark #hy-chat .message.user {
|
| 91 |
-
background: #2a2a2a;
|
| 92 |
-
}
|
| 93 |
-
#hy-chat .message.bot {
|
| 94 |
-
background: transparent;
|
| 95 |
-
padding: 4px 0 !important;
|
| 96 |
-
}
|
| 97 |
-
|
| 98 |
-
/* ── User-text appearance (no markdown rendering — pre-wrap text). ────── */
|
| 99 |
-
#hy-chat .hy-user-text {
|
| 100 |
-
font-size: 15px;
|
| 101 |
-
line-height: 1.7;
|
| 102 |
-
color: var(--hy-text);
|
| 103 |
-
}
|
| 104 |
-
|
| 105 |
-
/* ── Frozen vs streaming segments inside the assistant bubble ──────────
|
| 106 |
-
* Both are direct children of .markdown so the existing #hy-chat .bot
|
| 107 |
-
* .markdown styling cascades into them transparently. The only thing
|
| 108 |
-
* we add here is to mark the streaming segment so future debugging or
|
| 109 |
-
* styling can target it (e.g. a subtle pulse to indicate "still
|
| 110 |
-
* generating" without flickering already-rendered formulas). */
|
| 111 |
-
#hy-chat .hy-frozen,
|
| 112 |
-
#hy-chat .hy-streaming {
|
| 113 |
-
display: block;
|
| 114 |
-
}
|
| 115 |
-
|
| 116 |
-
/* ── Tool-call display block (server-rendered Markdown HTML). ─────────── */
|
| 117 |
-
#hy-chat .hy-tool-calls {
|
| 118 |
-
margin-top: 10px;
|
| 119 |
-
}
|
| 120 |
-
#hy-chat .hy-tool-call + .hy-tool-call {
|
| 121 |
-
margin-top: 8px;
|
| 122 |
-
}
|
| 123 |
-
|
| 124 |
-
/* ── Hide the delta channel completely ─────────────────────────────────
|
| 125 |
-
* The bridge component for delta JSON. Must never occupy layout, must
|
| 126 |
-
* never trap pointer / focus / scroll events — but its content has to
|
| 127 |
-
* remain readable to the JS MutationObserver that drives the renderer
|
| 128 |
-
* (so we cannot use display:none). */
|
| 129 |
-
#hy-chat-delta,
|
| 130 |
-
#hy-chat-delta * {
|
| 131 |
-
position: absolute !important;
|
| 132 |
-
width: 0 !important;
|
| 133 |
-
height: 0 !important;
|
| 134 |
-
margin: 0 !important;
|
| 135 |
-
padding: 0 !important;
|
| 136 |
-
border: 0 !important;
|
| 137 |
-
overflow: hidden !important;
|
| 138 |
-
clip: rect(0 0 0 0) !important;
|
| 139 |
-
clip-path: inset(50%) !important;
|
| 140 |
-
visibility: hidden !important;
|
| 141 |
-
opacity: 0 !important;
|
| 142 |
-
pointer-events: none !important;
|
| 143 |
-
user-select: none !important;
|
| 144 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_chatbot.css
DELETED
|
@@ -1,170 +0,0 @@
|
|
| 1 |
-
/* ── chatbot container ── */
|
| 2 |
-
#hy-chat {
|
| 3 |
-
border: none !important;
|
| 4 |
-
box-shadow: none !important;
|
| 5 |
-
background: #ffffff !important;
|
| 6 |
-
--border-color-primary: transparent !important;
|
| 7 |
-
--color-accent-soft: #ffffff !important;
|
| 8 |
-
--background-fill-secondary: #ffffff !important;
|
| 9 |
-
}
|
| 10 |
-
.dark #hy-chat {
|
| 11 |
-
background: #171717 !important;
|
| 12 |
-
--border-color-primary: transparent !important;
|
| 13 |
-
--color-accent-soft: #1f1f1f !important;
|
| 14 |
-
--background-fill-secondary: #171717 !important;
|
| 15 |
-
}
|
| 16 |
-
|
| 17 |
-
/* ── message panel: uniform style for both user and bot ── */
|
| 18 |
-
#hy-chat .message-row .message-bubble-border,
|
| 19 |
-
#hy-chat .bot .message-bubble-border,
|
| 20 |
-
#hy-chat .user .message-bubble-border,
|
| 21 |
-
#hy-chat [data-testid="bot"] .message-bubble-border,
|
| 22 |
-
#hy-chat [data-testid="user"] .message-bubble-border {
|
| 23 |
-
border-color: transparent !important;
|
| 24 |
-
border-width: 0 !important;
|
| 25 |
-
box-shadow: none !important;
|
| 26 |
-
outline: none !important;
|
| 27 |
-
background: #ffffff !important;
|
| 28 |
-
padding: 4px 16px 4px 0 !important;
|
| 29 |
-
max-width: 100% !important;
|
| 30 |
-
}
|
| 31 |
-
.dark #hy-chat .message-row .message-bubble-border,
|
| 32 |
-
.dark #hy-chat .bot .message-bubble-border,
|
| 33 |
-
.dark #hy-chat .user .message-bubble-border,
|
| 34 |
-
.dark #hy-chat [data-testid="bot"] .message-bubble-border,
|
| 35 |
-
.dark #hy-chat [data-testid="user"] .message-bubble-border {
|
| 36 |
-
background: #171717 !important;
|
| 37 |
-
}
|
| 38 |
-
|
| 39 |
-
/* ── remove user message bubble border (all themes) ── */
|
| 40 |
-
#hy-chat .user,
|
| 41 |
-
#hy-chat .user .message,
|
| 42 |
-
#hy-chat .user .bubble,
|
| 43 |
-
#hy-chat .user > div,
|
| 44 |
-
#hy-chat [data-testid="user"],
|
| 45 |
-
#hy-chat [data-testid="user"] .message,
|
| 46 |
-
#hy-chat [data-testid="user"] .bubble,
|
| 47 |
-
#hy-chat [data-testid="user"] > div,
|
| 48 |
-
#hy-chat .message-row.user-row,
|
| 49 |
-
#hy-chat .message-row.user-row > div,
|
| 50 |
-
#hy-chat .user-message,
|
| 51 |
-
#hy-chat .message.user {
|
| 52 |
-
border: none !important;
|
| 53 |
-
border-width: 0 !important;
|
| 54 |
-
border-color: transparent !important;
|
| 55 |
-
box-shadow: none !important;
|
| 56 |
-
outline: none !important;
|
| 57 |
-
}
|
| 58 |
-
#hy-chat .user .message,
|
| 59 |
-
#hy-chat [data-testid="user"] .message,
|
| 60 |
-
#hy-chat .user-message {
|
| 61 |
-
background: transparent !important;
|
| 62 |
-
padding: 4px 16px !important;
|
| 63 |
-
}
|
| 64 |
-
.dark #hy-chat .user .message,
|
| 65 |
-
.dark #hy-chat [data-testid="user"] .message,
|
| 66 |
-
.dark #hy-chat .user-message {
|
| 67 |
-
background: transparent !important;
|
| 68 |
-
}
|
| 69 |
-
|
| 70 |
-
/* ── user text: match bot text style ── */
|
| 71 |
-
#hy-chat .user .markdown,
|
| 72 |
-
#hy-chat .user .message-content,
|
| 73 |
-
#hy-chat .user p,
|
| 74 |
-
#hy-chat [data-testid="user"] .markdown,
|
| 75 |
-
#hy-chat [data-testid="user"] .message-content,
|
| 76 |
-
#hy-chat [data-testid="user"] p {
|
| 77 |
-
font-size: 15px !important;
|
| 78 |
-
line-height: 1.8 !important;
|
| 79 |
-
color: #222222 !important;
|
| 80 |
-
letter-spacing: 0.01em !important;
|
| 81 |
-
}
|
| 82 |
-
.dark #hy-chat .user .markdown,
|
| 83 |
-
.dark #hy-chat .user .message-content,
|
| 84 |
-
.dark #hy-chat .user p,
|
| 85 |
-
.dark #hy-chat [data-testid="user"] .markdown,
|
| 86 |
-
.dark #hy-chat [data-testid="user"] .message-content,
|
| 87 |
-
.dark #hy-chat [data-testid="user"] p {
|
| 88 |
-
color: #e8e8e8 !important;
|
| 89 |
-
}
|
| 90 |
-
|
| 91 |
-
/* ── bot text styling ── */
|
| 92 |
-
#hy-chat .bot .markdown,
|
| 93 |
-
#hy-chat .bot .message-content,
|
| 94 |
-
#hy-chat [data-testid="bot"] .markdown {
|
| 95 |
-
font-size: 15px !important;
|
| 96 |
-
line-height: 1.8 !important;
|
| 97 |
-
color: #222222 !important;
|
| 98 |
-
letter-spacing: 0.01em !important;
|
| 99 |
-
}
|
| 100 |
-
.dark #hy-chat .bot .markdown,
|
| 101 |
-
.dark #hy-chat .bot .message-content,
|
| 102 |
-
.dark #hy-chat [data-testid="bot"] .markdown {
|
| 103 |
-
color: #e8e8e8 !important;
|
| 104 |
-
}
|
| 105 |
-
#hy-chat .bot p { margin: 0.6em 0 !important; }
|
| 106 |
-
#hy-chat .bot strong, #hy-chat .bot b {
|
| 107 |
-
font-weight: 600 !important;
|
| 108 |
-
color: #111 !important;
|
| 109 |
-
}
|
| 110 |
-
.dark #hy-chat .bot strong, .dark #hy-chat .bot b {
|
| 111 |
-
color: #fff !important;
|
| 112 |
-
}
|
| 113 |
-
#hy-chat .bot ul, #hy-chat .bot ol {
|
| 114 |
-
padding-left: 1.5em !important;
|
| 115 |
-
margin: 0.5em 0 !important;
|
| 116 |
-
}
|
| 117 |
-
#hy-chat .bot li {
|
| 118 |
-
margin: 0.3em 0 !important;
|
| 119 |
-
line-height: 1.8 !important;
|
| 120 |
-
}
|
| 121 |
-
|
| 122 |
-
/* ── headings ── */
|
| 123 |
-
#hy-chat .bot h1 { font-size: 22px !important; font-weight: 700 !important; color: #111 !important; margin: 1em 0 0.5em !important; }
|
| 124 |
-
#hy-chat .bot h2 { font-size: 19px !important; font-weight: 700 !important; color: #111 !important; margin: 0.9em 0 0.4em !important; }
|
| 125 |
-
#hy-chat .bot h3 { font-size: 17px !important; font-weight: 600 !important; color: #111 !important; margin: 0.8em 0 0.35em !important; }
|
| 126 |
-
#hy-chat .bot h4 { font-size: 15px !important; font-weight: 600 !important; color: #222 !important; margin: 0.7em 0 0.3em !important; }
|
| 127 |
-
.dark #hy-chat .bot h1 { color: #f2f2f2 !important; }
|
| 128 |
-
.dark #hy-chat .bot h2 { color: #ebebeb !important; }
|
| 129 |
-
.dark #hy-chat .bot h3 { color: #e0e0e0 !important; }
|
| 130 |
-
.dark #hy-chat .bot h4 { color: #d4d4d4 !important; }
|
| 131 |
-
|
| 132 |
-
/* ── tables ── */
|
| 133 |
-
#hy-chat table {
|
| 134 |
-
border-collapse: collapse !important;
|
| 135 |
-
width: auto !important;
|
| 136 |
-
margin: 1em 0 !important;
|
| 137 |
-
font-size: 14px !important;
|
| 138 |
-
line-height: 1.6 !important;
|
| 139 |
-
}
|
| 140 |
-
#hy-chat th, #hy-chat td {
|
| 141 |
-
border: 1px solid #e8e8e8 !important;
|
| 142 |
-
padding: 10px 20px !important;
|
| 143 |
-
text-align: left !important;
|
| 144 |
-
}
|
| 145 |
-
#hy-chat th {
|
| 146 |
-
background: #fafafa !important;
|
| 147 |
-
font-weight: 600 !important;
|
| 148 |
-
color: #333 !important;
|
| 149 |
-
}
|
| 150 |
-
#hy-chat td {
|
| 151 |
-
color: #444 !important;
|
| 152 |
-
background: #fff !important;
|
| 153 |
-
}
|
| 154 |
-
#hy-chat tr:hover td {
|
| 155 |
-
background: #fafcff !important;
|
| 156 |
-
}
|
| 157 |
-
.dark #hy-chat th, .dark #hy-chat td {
|
| 158 |
-
border-color: #2a2a2a !important;
|
| 159 |
-
}
|
| 160 |
-
.dark #hy-chat th {
|
| 161 |
-
background: #242424 !important;
|
| 162 |
-
color: #e0e0e0 !important;
|
| 163 |
-
}
|
| 164 |
-
.dark #hy-chat td {
|
| 165 |
-
color: #d0d0d0 !important;
|
| 166 |
-
background: #1c1c1c !important;
|
| 167 |
-
}
|
| 168 |
-
.dark #hy-chat tr:hover td {
|
| 169 |
-
background: #262626 !important;
|
| 170 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_dark.css
DELETED
|
@@ -1,194 +0,0 @@
|
|
| 1 |
-
/* ── Dark mode: sidebar ── */
|
| 2 |
-
.dark .sidebar, .dark [class*="sidebar"] {
|
| 3 |
-
background: #1a1a1a !important;
|
| 4 |
-
border: none !important;
|
| 5 |
-
box-shadow: none !important;
|
| 6 |
-
}
|
| 7 |
-
.dark .sidebar h1, .dark [class*="sidebar"] h1 {
|
| 8 |
-
color: #e8e8e8 !important;
|
| 9 |
-
}
|
| 10 |
-
.dark .sidebar .block,
|
| 11 |
-
.dark .sidebar .form,
|
| 12 |
-
.dark .sidebar .panel,
|
| 13 |
-
.dark .sidebar > div,
|
| 14 |
-
.dark [class*="sidebar"] .block,
|
| 15 |
-
.dark [class*="sidebar"] .form,
|
| 16 |
-
.dark [class*="sidebar"] .panel,
|
| 17 |
-
.dark [class*="sidebar"] > div {
|
| 18 |
-
background: transparent !important;
|
| 19 |
-
border: none !important;
|
| 20 |
-
box-shadow: none !important;
|
| 21 |
-
}
|
| 22 |
-
|
| 23 |
-
/* ── Dark mode: global inputs ── */
|
| 24 |
-
.dark textarea, .dark input[type="text"] {
|
| 25 |
-
background: #2a2a2a !important;
|
| 26 |
-
color: #e8e8e8 !important;
|
| 27 |
-
border-color: #3a3a3a !important;
|
| 28 |
-
}
|
| 29 |
-
.dark textarea::placeholder, .dark input[type="text"]::placeholder {
|
| 30 |
-
color: #666 !important;
|
| 31 |
-
}
|
| 32 |
-
|
| 33 |
-
/* ── Dark mode: slider tracks ── */
|
| 34 |
-
.dark .gradio-container input[type="range"]::-moz-range-progress { background-color: #6b9fff !important; }
|
| 35 |
-
.dark .gradio-container input[type="range"]::-moz-range-track { background: #2a2a2a !important; }
|
| 36 |
-
|
| 37 |
-
/* ── Dark mode: dropdowns ── */
|
| 38 |
-
.dark select, .dark .wrap[data-testid="dropdown"] {
|
| 39 |
-
background: #2a2a2a !important;
|
| 40 |
-
color: #e8e8e8 !important;
|
| 41 |
-
border-color: #3a3a3a !important;
|
| 42 |
-
}
|
| 43 |
-
|
| 44 |
-
/* ── Dark mode: accordion ── */
|
| 45 |
-
.dark .accordion {
|
| 46 |
-
background: #1f1f1f !important;
|
| 47 |
-
border-color: #2a2a2a !important;
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
/* ── Dark mode: forms & labels ── */
|
| 51 |
-
.dark .form {
|
| 52 |
-
border-color: #2a2a2a !important;
|
| 53 |
-
}
|
| 54 |
-
.dark label, .dark .label-wrap {
|
| 55 |
-
color: #c0c0c0 !important;
|
| 56 |
-
}
|
| 57 |
-
.dark .info-text, .dark span[data-testid="block-info"] {
|
| 58 |
-
color: #808080 !important;
|
| 59 |
-
}
|
| 60 |
-
|
| 61 |
-
/* ── Dark mode: scrollbars ── */
|
| 62 |
-
.dark *::-webkit-scrollbar {
|
| 63 |
-
width: 8px !important;
|
| 64 |
-
height: 8px !important;
|
| 65 |
-
background: transparent !important;
|
| 66 |
-
}
|
| 67 |
-
.dark *::-webkit-scrollbar-track {
|
| 68 |
-
background: transparent !important;
|
| 69 |
-
border: none !important;
|
| 70 |
-
}
|
| 71 |
-
.dark *::-webkit-scrollbar-thumb {
|
| 72 |
-
background: #3a3a3a !important;
|
| 73 |
-
border-radius: 4px !important;
|
| 74 |
-
border: 2px solid transparent !important;
|
| 75 |
-
background-clip: padding-box !important;
|
| 76 |
-
}
|
| 77 |
-
.dark *::-webkit-scrollbar-thumb:hover {
|
| 78 |
-
background: #505050 !important;
|
| 79 |
-
background-clip: padding-box !important;
|
| 80 |
-
}
|
| 81 |
-
.dark *::-webkit-scrollbar-corner {
|
| 82 |
-
background: transparent !important;
|
| 83 |
-
}
|
| 84 |
-
.dark * {
|
| 85 |
-
scrollbar-width: thin !important;
|
| 86 |
-
scrollbar-color: #3a3a3a transparent !important;
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
/* ── Dark mode: sliders (track + thumb) ── */
|
| 90 |
-
.dark input[type="range"] {
|
| 91 |
-
-webkit-appearance: none !important;
|
| 92 |
-
appearance: none !important;
|
| 93 |
-
background: transparent !important;
|
| 94 |
-
height: 4px !important;
|
| 95 |
-
cursor: pointer !important;
|
| 96 |
-
}
|
| 97 |
-
.dark input[type="range"]::-webkit-slider-runnable-track {
|
| 98 |
-
background: #2f2f2f !important;
|
| 99 |
-
height: 4px !important;
|
| 100 |
-
border-radius: 2px !important;
|
| 101 |
-
border: none !important;
|
| 102 |
-
}
|
| 103 |
-
.dark input[type="range"]::-moz-range-track {
|
| 104 |
-
background: #2f2f2f !important;
|
| 105 |
-
height: 4px !important;
|
| 106 |
-
border-radius: 2px !important;
|
| 107 |
-
border: none !important;
|
| 108 |
-
}
|
| 109 |
-
.dark input[type="range"]::-webkit-slider-thumb {
|
| 110 |
-
-webkit-appearance: none !important;
|
| 111 |
-
appearance: none !important;
|
| 112 |
-
width: 18px !important;
|
| 113 |
-
height: 18px !important;
|
| 114 |
-
border-radius: 50% !important;
|
| 115 |
-
background: #6b9fff !important;
|
| 116 |
-
border: 2px solid #1f1f1f !important;
|
| 117 |
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4) !important;
|
| 118 |
-
margin-top: -7px !important;
|
| 119 |
-
cursor: pointer !important;
|
| 120 |
-
}
|
| 121 |
-
.dark input[type="range"]::-moz-range-thumb {
|
| 122 |
-
width: 18px !important;
|
| 123 |
-
height: 18px !important;
|
| 124 |
-
border-radius: 50% !important;
|
| 125 |
-
background: #6b9fff !important;
|
| 126 |
-
border: 2px solid #1f1f1f !important;
|
| 127 |
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4) !important;
|
| 128 |
-
cursor: pointer !important;
|
| 129 |
-
}
|
| 130 |
-
.dark input[type="range"]::-moz-range-progress {
|
| 131 |
-
background-color: #4b7fd6 !important;
|
| 132 |
-
height: 4px !important;
|
| 133 |
-
border-radius: 2px !important;
|
| 134 |
-
}
|
| 135 |
-
|
| 136 |
-
/* ── Dark mode: number/spin inputs (slider value boxes) ── */
|
| 137 |
-
.dark input[type="number"] {
|
| 138 |
-
background: #1f1f1f !important;
|
| 139 |
-
color: #c8c8c8 !important;
|
| 140 |
-
border: 1px solid #262626 !important;
|
| 141 |
-
border-radius: 6px !important;
|
| 142 |
-
box-shadow: none !important;
|
| 143 |
-
}
|
| 144 |
-
.dark input[type="number"]:focus {
|
| 145 |
-
border-color: rgba(107, 159, 255, 0.35) !important;
|
| 146 |
-
outline: none !important;
|
| 147 |
-
}
|
| 148 |
-
.dark input[type="number"]::-webkit-inner-spin-button,
|
| 149 |
-
.dark input[type="number"]::-webkit-outer-spin-button {
|
| 150 |
-
filter: invert(0.85) !important;
|
| 151 |
-
opacity: 0.4 !important;
|
| 152 |
-
}
|
| 153 |
-
/* Number-input wrappers (the small editable boxes next to sliders).
|
| 154 |
-
* Previously also targeted .wrap.svelte-1cl284s; dropped the hash since
|
| 155 |
-
* Gradio regenerates it. Stable selectors below cover the same elements. */
|
| 156 |
-
.dark .gradio-container [class*="number_input"],
|
| 157 |
-
.dark .gradio-container [data-testid*="number"] input,
|
| 158 |
-
.dark .gradio-container [data-testid*="number"] .wrap,
|
| 159 |
-
.dark .gradio-container .head .wrap,
|
| 160 |
-
.dark .gradio-container .head input {
|
| 161 |
-
background: #1f1f1f !important;
|
| 162 |
-
color: #c8c8c8 !important;
|
| 163 |
-
border-color: #262626 !important;
|
| 164 |
-
box-shadow: none !important;
|
| 165 |
-
}
|
| 166 |
-
.dark .gradio-container .head,
|
| 167 |
-
.dark .gradio-container .head > div,
|
| 168 |
-
.dark .gradio-container .tabular-nums {
|
| 169 |
-
background: transparent !important;
|
| 170 |
-
border-color: #262626 !important;
|
| 171 |
-
}
|
| 172 |
-
|
| 173 |
-
/* ── Dark mode: slider min/max range labels (e.g. "0", "1", "65536") ── */
|
| 174 |
-
.dark .gradio-container .min,
|
| 175 |
-
.dark .gradio-container .max,
|
| 176 |
-
.dark .head .min,
|
| 177 |
-
.dark .head .max,
|
| 178 |
-
.dark span.tabular-nums {
|
| 179 |
-
color: #707070 !important;
|
| 180 |
-
}
|
| 181 |
-
|
| 182 |
-
/* ── Dark mode: reset-to-default arrow button next to inputs ── */
|
| 183 |
-
.dark button[aria-label="Reset to default value"],
|
| 184 |
-
.dark button[title="Reset to default value"] {
|
| 185 |
-
background: transparent !important;
|
| 186 |
-
color: #707070 !important;
|
| 187 |
-
border: none !important;
|
| 188 |
-
box-shadow: none !important;
|
| 189 |
-
}
|
| 190 |
-
.dark button[aria-label="Reset to default value"]:hover,
|
| 191 |
-
.dark button[title="Reset to default value"]:hover {
|
| 192 |
-
color: #b0b0b0 !important;
|
| 193 |
-
background: transparent !important;
|
| 194 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_examples.css
DELETED
|
@@ -1,142 +0,0 @@
|
|
| 1 |
-
/* ─────────────────────────────────────────────────────────────────────────
|
| 2 |
-
* Empty-state "What can I help you with?" overlay.
|
| 3 |
-
* Lives outside the Gradio container (appended to <body>) so we don't need
|
| 4 |
-
* !important to win against framework styles.
|
| 5 |
-
* ───────────────────────────────────────────────────────────────────────── */
|
| 6 |
-
|
| 7 |
-
#examples-overlay {
|
| 8 |
-
position: fixed;
|
| 9 |
-
left: 0; right: 0;
|
| 10 |
-
display: flex;
|
| 11 |
-
align-items: center;
|
| 12 |
-
justify-content: center;
|
| 13 |
-
z-index: 100;
|
| 14 |
-
background: var(--hy-bg);
|
| 15 |
-
pointer-events: none;
|
| 16 |
-
overflow-y: auto;
|
| 17 |
-
}
|
| 18 |
-
|
| 19 |
-
.examples-wrapper {
|
| 20 |
-
display: flex;
|
| 21 |
-
flex-direction: column;
|
| 22 |
-
align-items: center;
|
| 23 |
-
margin: auto;
|
| 24 |
-
pointer-events: auto;
|
| 25 |
-
padding: 40px 20px;
|
| 26 |
-
}
|
| 27 |
-
|
| 28 |
-
.examples-heading {
|
| 29 |
-
font-size: 22px;
|
| 30 |
-
font-weight: 600;
|
| 31 |
-
color: var(--hy-text);
|
| 32 |
-
margin: 0 0 28px;
|
| 33 |
-
letter-spacing: -0.01em;
|
| 34 |
-
}
|
| 35 |
-
|
| 36 |
-
/* 1-2-1 "diamond" layout for exactly 4 example cards.
|
| 37 |
-
* row 1: card #1 (centered, spans both columns)
|
| 38 |
-
* row 2: card #2 (right-aligned in left col) | card #3 (left-aligned in right col)
|
| 39 |
-
* row 3: card #4 (centered, spans both columns)
|
| 40 |
-
* Using CSS grid with explicit nth-child placements rather than flex-
|
| 41 |
-
* wrap, because flex-wrap on equal-width children can only produce
|
| 42 |
-
* 1xN, 2x2, or 4x1 — never 1-2-1. */
|
| 43 |
-
.examples-grid {
|
| 44 |
-
display: grid;
|
| 45 |
-
grid-template-columns: minmax(0, 480px) minmax(0, 480px);
|
| 46 |
-
column-gap: 20px;
|
| 47 |
-
row-gap: 14px;
|
| 48 |
-
justify-content: center;
|
| 49 |
-
width: min(1020px, 100%);
|
| 50 |
-
}
|
| 51 |
-
|
| 52 |
-
.example-btn:nth-child(1),
|
| 53 |
-
.example-btn:nth-child(4) {
|
| 54 |
-
grid-column: 1 / span 2;
|
| 55 |
-
justify-self: center;
|
| 56 |
-
}
|
| 57 |
-
.example-btn:nth-child(2) {
|
| 58 |
-
grid-column: 1;
|
| 59 |
-
justify-self: end;
|
| 60 |
-
}
|
| 61 |
-
.example-btn:nth-child(3) {
|
| 62 |
-
grid-column: 2;
|
| 63 |
-
justify-self: start;
|
| 64 |
-
}
|
| 65 |
-
|
| 66 |
-
.example-btn {
|
| 67 |
-
/* Outer card: flex container that vertically + horizontally centers
|
| 68 |
-
* its single inner ``.example-btn-text`` child. We CANNOT also be
|
| 69 |
-
* a ``-webkit-box`` here (that's the inner element's job, see
|
| 70 |
-
* below) — line-clamp and flex centering need separate elements. */
|
| 71 |
-
display: flex !important;
|
| 72 |
-
align-items: center;
|
| 73 |
-
justify-content: center;
|
| 74 |
-
overflow: hidden !important;
|
| 75 |
-
box-sizing: border-box !important;
|
| 76 |
-
|
| 77 |
-
width: 460px;
|
| 78 |
-
/* 14px font * 1.5 line-height = 21px per line. 2 lines = 42px.
|
| 79 |
-
* + 14px*2 padding-y = 28px. + 1px*2 border = 2px. Total 72px. */
|
| 80 |
-
height: 72px;
|
| 81 |
-
|
| 82 |
-
background: var(--hy-bg);
|
| 83 |
-
border: 1px solid var(--hy-border);
|
| 84 |
-
border-radius: 18px;
|
| 85 |
-
padding: 14px 20px;
|
| 86 |
-
font-size: 14px;
|
| 87 |
-
line-height: 1.5;
|
| 88 |
-
color: var(--hy-text);
|
| 89 |
-
cursor: pointer;
|
| 90 |
-
transition: transform 0.15s ease, background 0.2s ease,
|
| 91 |
-
border-color 0.2s ease, box-shadow 0.2s ease, color 0.2s ease;
|
| 92 |
-
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC",
|
| 93 |
-
"Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica,
|
| 94 |
-
Arial, sans-serif;
|
| 95 |
-
user-select: none;
|
| 96 |
-
text-align: center;
|
| 97 |
-
}
|
| 98 |
-
|
| 99 |
-
/* Inner text element: owns the 2-line clamp + auto ellipsis. The
|
| 100 |
-
* ``!important`` triplet defends against framework-level resets that
|
| 101 |
-
* would otherwise silently change ``display`` and let a 3rd line
|
| 102 |
-
* bleed into view. */
|
| 103 |
-
.example-btn-text {
|
| 104 |
-
display: -webkit-box !important;
|
| 105 |
-
-webkit-line-clamp: 2 !important;
|
| 106 |
-
-webkit-box-orient: vertical !important;
|
| 107 |
-
overflow: hidden !important;
|
| 108 |
-
word-break: break-word;
|
| 109 |
-
width: 100%;
|
| 110 |
-
text-align: center;
|
| 111 |
-
}
|
| 112 |
-
|
| 113 |
-
/* On narrow screens the diamond would overflow horizontally — collapse
|
| 114 |
-
* to a single centered column instead. */
|
| 115 |
-
@media (max-width: 1020px) {
|
| 116 |
-
.examples-grid {
|
| 117 |
-
grid-template-columns: minmax(0, 1fr);
|
| 118 |
-
}
|
| 119 |
-
.example-btn:nth-child(1),
|
| 120 |
-
.example-btn:nth-child(2),
|
| 121 |
-
.example-btn:nth-child(3),
|
| 122 |
-
.example-btn:nth-child(4) {
|
| 123 |
-
grid-column: 1;
|
| 124 |
-
justify-self: center;
|
| 125 |
-
}
|
| 126 |
-
.example-btn {
|
| 127 |
-
width: 100%;
|
| 128 |
-
max-width: 520px;
|
| 129 |
-
}
|
| 130 |
-
}
|
| 131 |
-
.example-btn:hover {
|
| 132 |
-
background: var(--hy-bg-muted);
|
| 133 |
-
border-color: var(--hy-border-strong);
|
| 134 |
-
color: var(--hy-text-strong);
|
| 135 |
-
box-shadow: var(--hy-shadow);
|
| 136 |
-
transform: translateY(-1px);
|
| 137 |
-
}
|
| 138 |
-
|
| 139 |
-
.dark .example-btn:hover {
|
| 140 |
-
border-color: rgba(107, 159, 255, 0.35);
|
| 141 |
-
box-shadow: 0 0 8px rgba(107, 159, 255, 0.08);
|
| 142 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_hide.css
DELETED
|
@@ -1,131 +0,0 @@
|
|
| 1 |
-
/* ── hide all avatars ── */
|
| 2 |
-
#hy-chat [class*="avatar"] {
|
| 3 |
-
display: none !important;
|
| 4 |
-
width: 0 !important;
|
| 5 |
-
height: 0 !important;
|
| 6 |
-
min-width: 0 !important;
|
| 7 |
-
min-height: 0 !important;
|
| 8 |
-
overflow: hidden !important;
|
| 9 |
-
opacity: 0 !important;
|
| 10 |
-
margin: 0 !important;
|
| 11 |
-
padding: 0 !important;
|
| 12 |
-
position: absolute !important;
|
| 13 |
-
pointer-events: none !important;
|
| 14 |
-
}
|
| 15 |
-
|
| 16 |
-
/* ── hide Gradio default action buttons & icons ── */
|
| 17 |
-
#hy-chat button[aria-label="Copy message"],
|
| 18 |
-
#hy-chat button[title="Copy message"],
|
| 19 |
-
#hy-chat button[aria-label="Share message"],
|
| 20 |
-
#hy-chat button[title="Share message"],
|
| 21 |
-
#hy-chat button[aria-label="Delete message"],
|
| 22 |
-
#hy-chat button[title="Delete message"],
|
| 23 |
-
#hy-chat button[aria-label="Retry"],
|
| 24 |
-
#hy-chat button[title="Retry"],
|
| 25 |
-
#hy-chat button[aria-label="Undo"],
|
| 26 |
-
#hy-chat button[title="Undo"],
|
| 27 |
-
#hy-chat .message-buttons-bot,
|
| 28 |
-
#hy-chat .message-buttons-user,
|
| 29 |
-
#hy-chat .bot .icon-button-wrapper,
|
| 30 |
-
#hy-chat .user .icon-button-wrapper,
|
| 31 |
-
#hy-chat .bot .icon-button,
|
| 32 |
-
#hy-chat .user .icon-button,
|
| 33 |
-
#hy-chat .likeable {
|
| 34 |
-
display: none !important;
|
| 35 |
-
}
|
| 36 |
-
|
| 37 |
-
/*
|
| 38 |
-
* NOTE: do NOT use a blanket `.message-row button:not(.html-preview-btn)`
|
| 39 |
-
* rule here — it would also hide our per-code-block "Copy" button that
|
| 40 |
-
* lives inside .hy-codeblock-header at the top-right of each fenced
|
| 41 |
-
* code block. The specific aria-label/title selectors above already
|
| 42 |
-
* cover the message-level action buttons we want to hide.
|
| 43 |
-
*/
|
| 44 |
-
|
| 45 |
-
/* ── hide stray images/svgs inside messages ── */
|
| 46 |
-
#hy-chat .message-row img:not([class*="markdown"]),
|
| 47 |
-
#hy-chat .message-row svg {
|
| 48 |
-
display: none !important;
|
| 49 |
-
}
|
| 50 |
-
/* …but keep the SVGs inside our custom code-copy-btn visible.
|
| 51 |
-
* Specificity is boosted via duplicated #hy-chat to beat the hide rule. */
|
| 52 |
-
#hy-chat#hy-chat .message-row .code-copy-btn,
|
| 53 |
-
#hy-chat#hy-chat .message-row .code-copy-btn svg,
|
| 54 |
-
#hy-chat#hy-chat .message-row .code-copy-btn svg * {
|
| 55 |
-
display: inline-flex !important;
|
| 56 |
-
}
|
| 57 |
-
#hy-chat#hy-chat .message-row .code-copy-btn svg {
|
| 58 |
-
display: block !important;
|
| 59 |
-
}
|
| 60 |
-
/* …and keep SVGs inside KaTeX math formulas visible.
|
| 61 |
-
* KaTeX uses SVGs for radicals, stretchy delimiters, fraction lines, etc. */
|
| 62 |
-
#hy-chat#hy-chat .message-row .katex svg,
|
| 63 |
-
#hy-chat#hy-chat .message-row .katex-display svg {
|
| 64 |
-
display: inline !important;
|
| 65 |
-
}
|
| 66 |
-
|
| 67 |
-
/* ── Hide scroll-to-bottom button (too jarring in both themes) ── */
|
| 68 |
-
#hy-chat button.scroll-hide,
|
| 69 |
-
#hy-chat button[aria-label*="scroll" i],
|
| 70 |
-
#hy-chat button[aria-label*="bottom" i],
|
| 71 |
-
#hy-chat .scroll-to-bottom,
|
| 72 |
-
#hy-chat [class*="scroll-button"],
|
| 73 |
-
#hy-chat [class*="scrollButton"],
|
| 74 |
-
#hy-chat button[class*="scroll"] {
|
| 75 |
-
display: none !important;
|
| 76 |
-
visibility: hidden !important;
|
| 77 |
-
opacity: 0 !important;
|
| 78 |
-
pointer-events: none !important;
|
| 79 |
-
}
|
| 80 |
-
|
| 81 |
-
/* ── Hide the busy-marker component completely ──
|
| 82 |
-
* Driven by chat.py: contains either "" (idle) or a single
|
| 83 |
-
* <span data-hy-streaming="1"> (streaming). It is a pure machine signal
|
| 84 |
-
* read by static/app.js; it must never occupy any visible layout
|
| 85 |
-
* regardless of value, and must never trap pointer/scroll/focus events. */
|
| 86 |
-
#hy-busy-marker,
|
| 87 |
-
#hy-busy-marker * {
|
| 88 |
-
position: absolute !important;
|
| 89 |
-
width: 0 !important;
|
| 90 |
-
height: 0 !important;
|
| 91 |
-
margin: 0 !important;
|
| 92 |
-
padding: 0 !important;
|
| 93 |
-
border: 0 !important;
|
| 94 |
-
overflow: hidden !important;
|
| 95 |
-
clip: rect(0 0 0 0) !important;
|
| 96 |
-
clip-path: inset(50%) !important;
|
| 97 |
-
visibility: hidden !important;
|
| 98 |
-
opacity: 0 !important;
|
| 99 |
-
pointer-events: none !important;
|
| 100 |
-
user-select: none !important;
|
| 101 |
-
}
|
| 102 |
-
|
| 103 |
-
/* ── Hide all Gradio progress / loading status indicators globally ── */
|
| 104 |
-
.progress-bar-wrap,
|
| 105 |
-
.progress-bar,
|
| 106 |
-
.progress-text,
|
| 107 |
-
.progress,
|
| 108 |
-
.eta-bar,
|
| 109 |
-
[data-testid="loader"],
|
| 110 |
-
.loader,
|
| 111 |
-
.wrap.default.minimal,
|
| 112 |
-
.gradio-container .status-wrap,
|
| 113 |
-
.gradio-container .status,
|
| 114 |
-
.gradio-container .meta-text,
|
| 115 |
-
.gradio-container .meta-text-center,
|
| 116 |
-
.gradio-container [class*="progress"],
|
| 117 |
-
.gradio-container [class*="Progress"],
|
| 118 |
-
.gradio-container .generating,
|
| 119 |
-
#hy-chat .generating,
|
| 120 |
-
#hy-chat .progress,
|
| 121 |
-
#hy-chat .progress-text,
|
| 122 |
-
#hy-chat [class*="progress"],
|
| 123 |
-
#hy-chat [class*="loading"],
|
| 124 |
-
#hy-chat [class*="loader"] {
|
| 125 |
-
display: none !important;
|
| 126 |
-
visibility: hidden !important;
|
| 127 |
-
opacity: 0 !important;
|
| 128 |
-
pointer-events: none !important;
|
| 129 |
-
height: 0 !important;
|
| 130 |
-
width: 0 !important;
|
| 131 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_input.css
DELETED
|
@@ -1,114 +0,0 @@
|
|
| 1 |
-
/* ── input row ── */
|
| 2 |
-
.msg-row {
|
| 3 |
-
padding: 8px 0 !important;
|
| 4 |
-
gap: 8px !important;
|
| 5 |
-
border-top: none !important;
|
| 6 |
-
background: #fff !important;
|
| 7 |
-
align-items: center !important;
|
| 8 |
-
height: 88px !important;
|
| 9 |
-
min-height: 88px !important;
|
| 10 |
-
max-height: 88px !important;
|
| 11 |
-
flex-shrink: 0 !important;
|
| 12 |
-
}
|
| 13 |
-
.dark .msg-row {
|
| 14 |
-
background: #171717 !important;
|
| 15 |
-
}
|
| 16 |
-
.dark .msg-row *:not(textarea):not(button):not(button *) {
|
| 17 |
-
background: transparent !important;
|
| 18 |
-
border-color: transparent !important;
|
| 19 |
-
box-shadow: none !important;
|
| 20 |
-
outline: none !important;
|
| 21 |
-
}
|
| 22 |
-
.msg-input textarea {
|
| 23 |
-
height: 72px !important;
|
| 24 |
-
min-height: 72px !important;
|
| 25 |
-
max-height: 72px !important;
|
| 26 |
-
overflow-y: auto !important;
|
| 27 |
-
resize: none !important;
|
| 28 |
-
border-radius: 20px !important;
|
| 29 |
-
border: 1px solid #e0e0e0 !important;
|
| 30 |
-
padding: 18px 22px !important;
|
| 31 |
-
font-size: 15px !important;
|
| 32 |
-
line-height: 1.5 !important;
|
| 33 |
-
background: #fff !important;
|
| 34 |
-
box-shadow: 0 1px 4px rgba(0,0,0,0.06) !important;
|
| 35 |
-
color: #000 !important;
|
| 36 |
-
}
|
| 37 |
-
.dark .msg-input textarea {
|
| 38 |
-
background: #2a2a2a !important;
|
| 39 |
-
border-color: #3a3a3a !important;
|
| 40 |
-
color: #e8e8e8 !important;
|
| 41 |
-
box-shadow: 0 1px 4px rgba(0,0,0,0.3) !important;
|
| 42 |
-
}
|
| 43 |
-
.msg-input textarea:focus {
|
| 44 |
-
border-color: #c0c0c0 !important;
|
| 45 |
-
box-shadow: 0 2px 8px rgba(0,0,0,0.08) !important;
|
| 46 |
-
outline: none !important;
|
| 47 |
-
}
|
| 48 |
-
.dark .msg-input textarea:focus {
|
| 49 |
-
border-color: rgba(107, 159, 255, 0.4) !important;
|
| 50 |
-
box-shadow: 0 0 0 2px rgba(107, 159, 255, 0.1), 0 2px 8px rgba(0,0,0,0.3) !important;
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
/* ── new chat (+) button ── */
|
| 54 |
-
.new-chat-btn {
|
| 55 |
-
width: 42px !important;
|
| 56 |
-
height: 42px !important;
|
| 57 |
-
min-width: 42px !important;
|
| 58 |
-
max-width: 42px !important;
|
| 59 |
-
border-radius: 50% !important;
|
| 60 |
-
border: 1px solid #e5e7eb !important;
|
| 61 |
-
background: #fff !important;
|
| 62 |
-
color: #666 !important;
|
| 63 |
-
font-size: 22px !important;
|
| 64 |
-
font-weight: 300 !important;
|
| 65 |
-
padding: 0 !important;
|
| 66 |
-
display: flex !important;
|
| 67 |
-
align-items: center !important;
|
| 68 |
-
justify-content: center !important;
|
| 69 |
-
cursor: pointer !important;
|
| 70 |
-
flex-shrink: 0 !important;
|
| 71 |
-
}
|
| 72 |
-
.new-chat-btn:hover {
|
| 73 |
-
background: #f5f5f5 !important;
|
| 74 |
-
color: #333 !important;
|
| 75 |
-
border-color: #d0d0d0 !important;
|
| 76 |
-
}
|
| 77 |
-
.dark .new-chat-btn {
|
| 78 |
-
border-color: #3a3a3a !important;
|
| 79 |
-
background: #2a2a2a !important;
|
| 80 |
-
color: #999 !important;
|
| 81 |
-
}
|
| 82 |
-
.dark .new-chat-btn:hover {
|
| 83 |
-
background: #333 !important;
|
| 84 |
-
color: #e8e8e8 !important;
|
| 85 |
-
border-color: #505050 !important;
|
| 86 |
-
}
|
| 87 |
-
|
| 88 |
-
/* ── buttons ── */
|
| 89 |
-
button.primary { border-radius: 20px !important; font-weight: 500 !important; font-size: 14px !important; padding: 8px 20px !important; }
|
| 90 |
-
button.secondary { border: 1px solid #e5e5ea !important; border-radius: 20px !important; font-size: 14px !important; color: #444 !important; padding: 8px 16px !important; }
|
| 91 |
-
.dark button.secondary { border-color: #3a3a3a !important; color: #c0c0c0 !important; }
|
| 92 |
-
|
| 93 |
-
/* ── send button ── */
|
| 94 |
-
.send-btn, #send-btn {
|
| 95 |
-
width: 42px !important;
|
| 96 |
-
height: 42px !important;
|
| 97 |
-
min-width: 42px !important;
|
| 98 |
-
max-width: 42px !important;
|
| 99 |
-
border-radius: 50% !important;
|
| 100 |
-
padding: 0 !important;
|
| 101 |
-
display: flex !important;
|
| 102 |
-
align-items: center !important;
|
| 103 |
-
justify-content: center !important;
|
| 104 |
-
font-size: 18px !important;
|
| 105 |
-
flex-shrink: 0 !important;
|
| 106 |
-
}
|
| 107 |
-
#send-btn button {
|
| 108 |
-
width: 42px !important;
|
| 109 |
-
height: 42px !important;
|
| 110 |
-
min-width: 42px !important;
|
| 111 |
-
border-radius: 50% !important;
|
| 112 |
-
padding: 0 !important;
|
| 113 |
-
font-size: 18px !important;
|
| 114 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_layout.css
DELETED
|
@@ -1,41 +0,0 @@
|
|
| 1 |
-
/* ── full-viewport layout ── */
|
| 2 |
-
html, body {
|
| 3 |
-
overflow: hidden !important;
|
| 4 |
-
height: 100vh !important;
|
| 5 |
-
background: #fff !important;
|
| 6 |
-
}
|
| 7 |
-
.dark html, .dark body, html.dark, body.dark {
|
| 8 |
-
background: #171717 !important;
|
| 9 |
-
}
|
| 10 |
-
.gradio-container {
|
| 11 |
-
height: 100vh !important;
|
| 12 |
-
overflow: hidden !important;
|
| 13 |
-
max-width: 100% !important;
|
| 14 |
-
background: #fff !important;
|
| 15 |
-
}
|
| 16 |
-
.dark .gradio-container, .gradio-container.dark {
|
| 17 |
-
background: #171717 !important;
|
| 18 |
-
}
|
| 19 |
-
.main {
|
| 20 |
-
height: 100% !important;
|
| 21 |
-
overflow: hidden !important;
|
| 22 |
-
background: #fff !important;
|
| 23 |
-
}
|
| 24 |
-
.dark .main {
|
| 25 |
-
background: #171717 !important;
|
| 26 |
-
}
|
| 27 |
-
|
| 28 |
-
/* ── global font ──
|
| 29 |
-
* font-family is set on #hy-chat only (not #hy-chat *) so that KaTeX's
|
| 30 |
-
* own math-font declarations (KaTeX_Main, KaTeX_Math, …) are not
|
| 31 |
-
* overridden. Children inherit the system stack; KaTeX overrides it
|
| 32 |
-
* via its own class-based rules. */
|
| 33 |
-
#hy-chat {
|
| 34 |
-
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC",
|
| 35 |
-
"Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica,
|
| 36 |
-
Arial, sans-serif !important;
|
| 37 |
-
}
|
| 38 |
-
#hy-chat, #hy-chat * {
|
| 39 |
-
-webkit-font-smoothing: antialiased !important;
|
| 40 |
-
-moz-osx-font-smoothing: grayscale !important;
|
| 41 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_legacy.css
DELETED
|
@@ -1,50 +0,0 @@
|
|
| 1 |
-
/* ── Form / accordion / label tweaks ──────────────────────────────────────
|
| 2 |
-
*
|
| 3 |
-
* Previously these rules targeted Svelte hash classes (e.g. .svelte-d5xbca,
|
| 4 |
-
* .svelte-xzq5jh, .svelte-e5lyqv, .svelte-jdcl7l) which Gradio re-generates on
|
| 5 |
-
* every release. We drop the hashes and use stable class/role selectors so a
|
| 6 |
-
* Gradio bump doesn't silently break our styling.
|
| 7 |
-
*/
|
| 8 |
-
|
| 9 |
-
/* hide the rectangular border Gradio puts around forms */
|
| 10 |
-
.gradio-container .form {
|
| 11 |
-
border: none !important;
|
| 12 |
-
}
|
| 13 |
-
|
| 14 |
-
/* small "Validate & Format" style accordion buttons inside forms */
|
| 15 |
-
.gradio-container .form button.sm,
|
| 16 |
-
.gradio-container .accordion button.sm {
|
| 17 |
-
background: rgb(229, 231, 235);
|
| 18 |
-
}
|
| 19 |
-
.dark .gradio-container .form button.sm,
|
| 20 |
-
.dark .gradio-container .accordion button.sm {
|
| 21 |
-
background: #2a2a2a !important;
|
| 22 |
-
color: #c0c0c0 !important;
|
| 23 |
-
}
|
| 24 |
-
|
| 25 |
-
/* accordion / dropdown / slider label colors */
|
| 26 |
-
.gradio-container .label-wrap,
|
| 27 |
-
.gradio-container .label-wrap > span {
|
| 28 |
-
color: #000;
|
| 29 |
-
}
|
| 30 |
-
.dark .gradio-container .label-wrap,
|
| 31 |
-
.dark .gradio-container .label-wrap > span {
|
| 32 |
-
color: #c0c0c0 !important;
|
| 33 |
-
}
|
| 34 |
-
|
| 35 |
-
/* bot paragraph color (kept here because it's adjacent to label color logic) */
|
| 36 |
-
#hy-chat .bot p {
|
| 37 |
-
color: #000;
|
| 38 |
-
}
|
| 39 |
-
.dark #hy-chat .bot p {
|
| 40 |
-
color: #e8e8e8 !important;
|
| 41 |
-
}
|
| 42 |
-
|
| 43 |
-
/* prose inside the Gradio container (markdown rendering); use attribute
|
| 44 |
-
* selector that matches any container-version class instead of a pinned one */
|
| 45 |
-
[class*="gradio-container"] .prose * {
|
| 46 |
-
color: #000;
|
| 47 |
-
}
|
| 48 |
-
.dark [class*="gradio-container"] .prose * {
|
| 49 |
-
color: #e8e8e8 !important;
|
| 50 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_math.css
DELETED
|
@@ -1,132 +0,0 @@
|
|
| 1 |
-
/* ─────────────────────────────────────────────────────────────────────────
|
| 2 |
-
* KaTeX math rendering
|
| 3 |
-
*
|
| 4 |
-
* The chatbot CSS sets line-height: 1.8 + letter-spacing: 0.01em on
|
| 5 |
-
* .bot .markdown. These cascade into KaTeX, where SVGs for stretchy
|
| 6 |
-
* operators (like \not=) use height: inherit + width: 100%. An inflated
|
| 7 |
-
* line-height turns those SVGs into solid-colour rectangles. We reset
|
| 8 |
-
* typographic properties on all KaTeX descendants to restore correct
|
| 9 |
-
* glyph and symbol layout.
|
| 10 |
-
* ───────────────────────────────────────────────────────────────────────── */
|
| 11 |
-
|
| 12 |
-
/* ── Restore KaTeX's own font ──
|
| 13 |
-
* _layout.css sets font-family on #hy-chat; KaTeX children inherit it.
|
| 14 |
-
* Override here so KaTeX uses its own math fonts for correct glyphs. */
|
| 15 |
-
#hy-chat .katex {
|
| 16 |
-
font: normal 1.21em KaTeX_Main, "Times New Roman", serif !important;
|
| 17 |
-
text-indent: 0 !important;
|
| 18 |
-
}
|
| 19 |
-
|
| 20 |
-
/* ── Reset inherited typography ──
|
| 21 |
-
* High-specificity selectors ensure we beat the #hy-chat .bot .markdown
|
| 22 |
-
* rule that sets line-height: 1.8 and letter-spacing: 0.01em. */
|
| 23 |
-
#hy-chat .bot .markdown .katex,
|
| 24 |
-
#hy-chat .bot .markdown .katex *,
|
| 25 |
-
#hy-chat .bot .markdown .katex-display,
|
| 26 |
-
#hy-chat .bot .markdown .katex-display *,
|
| 27 |
-
#hy-chat .katex,
|
| 28 |
-
#hy-chat .katex *,
|
| 29 |
-
#hy-chat .katex-display,
|
| 30 |
-
#hy-chat .katex-display * {
|
| 31 |
-
letter-spacing: normal !important;
|
| 32 |
-
word-spacing: normal !important;
|
| 33 |
-
line-height: 1.2 !important;
|
| 34 |
-
}
|
| 35 |
-
|
| 36 |
-
/* ── SVG rendering ──
|
| 37 |
-
* KaTeX uses SVGs for radicals (√), stretchy delimiters, fraction lines,
|
| 38 |
-
* and negation slashes. Ensure they inherit the current text colour and
|
| 39 |
-
* are not distorted by the parent's line-height. */
|
| 40 |
-
#hy-chat .katex svg {
|
| 41 |
-
fill: currentColor;
|
| 42 |
-
stroke: none;
|
| 43 |
-
}
|
| 44 |
-
#hy-chat .katex svg path {
|
| 45 |
-
fill: currentColor;
|
| 46 |
-
}
|
| 47 |
-
|
| 48 |
-
/* ── SVG overlay fix ──
|
| 49 |
-
* Constrain overlay containers (negation slashes, accents) so an
|
| 50 |
-
* inflated line-height can never stretch SVGs into black blocks. */
|
| 51 |
-
#hy-chat .katex .rlap,
|
| 52 |
-
#hy-chat .katex .llap,
|
| 53 |
-
#hy-chat .katex .clap {
|
| 54 |
-
line-height: 0 !important;
|
| 55 |
-
}
|
| 56 |
-
#hy-chat .katex .stretchy,
|
| 57 |
-
#hy-chat .katex .halfarrow-left,
|
| 58 |
-
#hy-chat .katex .halfarrow-right,
|
| 59 |
-
#hy-chat .katex .brace-left,
|
| 60 |
-
#hy-chat .katex .brace-right {
|
| 61 |
-
overflow: hidden !important;
|
| 62 |
-
}
|
| 63 |
-
#hy-chat .katex .rule,
|
| 64 |
-
#hy-chat .katex .mfrac .frac-line,
|
| 65 |
-
#hy-chat .katex .overline .overline-line,
|
| 66 |
-
#hy-chat .katex .underline .underline-line,
|
| 67 |
-
#hy-chat .katex .hline {
|
| 68 |
-
overflow: hidden !important;
|
| 69 |
-
}
|
| 70 |
-
|
| 71 |
-
/* ── Text colour ──
|
| 72 |
-
* Explicit colour in both themes so KaTeX text and SVG fills (via
|
| 73 |
-
* currentColor) always match the surrounding prose. */
|
| 74 |
-
#hy-chat .katex,
|
| 75 |
-
#hy-chat .katex-display {
|
| 76 |
-
color: var(--hy-text, #222222) !important;
|
| 77 |
-
}
|
| 78 |
-
|
| 79 |
-
/* ── Display math (block) ── */
|
| 80 |
-
#hy-chat .katex-display {
|
| 81 |
-
margin: 1em 0 !important;
|
| 82 |
-
padding: 0.4em 0 !important;
|
| 83 |
-
overflow-x: auto !important;
|
| 84 |
-
overflow-y: hidden !important;
|
| 85 |
-
-webkit-overflow-scrolling: touch;
|
| 86 |
-
}
|
| 87 |
-
#hy-chat .katex-display > .katex {
|
| 88 |
-
text-align: center !important;
|
| 89 |
-
}
|
| 90 |
-
|
| 91 |
-
/* Subtle scrollbar for wide equations */
|
| 92 |
-
#hy-chat .katex-display::-webkit-scrollbar {
|
| 93 |
-
height: 3px;
|
| 94 |
-
}
|
| 95 |
-
#hy-chat .katex-display::-webkit-scrollbar-track {
|
| 96 |
-
background: transparent;
|
| 97 |
-
}
|
| 98 |
-
#hy-chat .katex-display::-webkit-scrollbar-thumb {
|
| 99 |
-
background: #d0d0d0;
|
| 100 |
-
border-radius: 2px;
|
| 101 |
-
}
|
| 102 |
-
|
| 103 |
-
/* ── Inline math ── */
|
| 104 |
-
#hy-chat p .katex,
|
| 105 |
-
#hy-chat li .katex,
|
| 106 |
-
#hy-chat td .katex {
|
| 107 |
-
font-size: 1.05em;
|
| 108 |
-
vertical-align: baseline;
|
| 109 |
-
}
|
| 110 |
-
|
| 111 |
-
/* ── KaTeX error fallback: show raw LaTeX legibly ── */
|
| 112 |
-
#hy-chat .katex-error {
|
| 113 |
-
color: var(--hy-text-muted, #666) !important;
|
| 114 |
-
font-family: "SF Mono", "Fira Code", "JetBrains Mono", monospace !important;
|
| 115 |
-
font-size: 0.88em !important;
|
| 116 |
-
background: var(--hy-bg-muted, #f5f5f7) !important;
|
| 117 |
-
padding: 1px 5px !important;
|
| 118 |
-
border-radius: 3px !important;
|
| 119 |
-
}
|
| 120 |
-
|
| 121 |
-
/* ── Dark mode ── */
|
| 122 |
-
.dark #hy-chat .katex,
|
| 123 |
-
.dark #hy-chat .katex-display {
|
| 124 |
-
color: var(--hy-text, #e8e8e8) !important;
|
| 125 |
-
}
|
| 126 |
-
.dark #hy-chat .katex-display::-webkit-scrollbar-thumb {
|
| 127 |
-
background: #404040;
|
| 128 |
-
}
|
| 129 |
-
.dark #hy-chat .katex-error {
|
| 130 |
-
color: var(--hy-text-muted, #909090) !important;
|
| 131 |
-
background: var(--hy-bg-muted, #2a2a2a) !important;
|
| 132 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_misc.css
DELETED
|
@@ -1,111 +0,0 @@
|
|
| 1 |
-
/* ── inputs global ── */
|
| 2 |
-
textarea, input[type="text"] { border-radius: 10px !important; font-size: 15px !important; }
|
| 3 |
-
|
| 4 |
-
/* ── code blocks ── */
|
| 5 |
-
#hy-chat pre {
|
| 6 |
-
background: #f5f5f7 !important;
|
| 7 |
-
border: 1px solid #ebebeb !important;
|
| 8 |
-
border-radius: 8px !important;
|
| 9 |
-
padding: 14px 18px !important;
|
| 10 |
-
font-size: 13px !important;
|
| 11 |
-
line-height: 1.6 !important;
|
| 12 |
-
overflow-x: auto !important;
|
| 13 |
-
margin: 0.8em 0 !important;
|
| 14 |
-
}
|
| 15 |
-
.dark #hy-chat pre {
|
| 16 |
-
background: #111 !important;
|
| 17 |
-
border-color: #2a2a2a !important;
|
| 18 |
-
}
|
| 19 |
-
#hy-chat code {
|
| 20 |
-
font-family: "SF Mono", "Fira Code", "JetBrains Mono", "Consolas", "Monaco", monospace !important;
|
| 21 |
-
font-size: 0.9em !important;
|
| 22 |
-
}
|
| 23 |
-
.dark #hy-chat code {
|
| 24 |
-
color: #d4d4d4 !important;
|
| 25 |
-
}
|
| 26 |
-
#hy-chat :not(pre) > code {
|
| 27 |
-
background: #f0f0f3 !important;
|
| 28 |
-
padding: 2px 6px !important;
|
| 29 |
-
border-radius: 4px !important;
|
| 30 |
-
color: #333 !important;
|
| 31 |
-
}
|
| 32 |
-
.dark #hy-chat :not(pre) > code {
|
| 33 |
-
background: #2a2a2a !important;
|
| 34 |
-
color: #d4d4d4 !important;
|
| 35 |
-
}
|
| 36 |
-
|
| 37 |
-
/* ── blockquote ── */
|
| 38 |
-
#hy-chat blockquote {
|
| 39 |
-
border-left: 3px solid #d1d1d6 !important;
|
| 40 |
-
margin: 0.8em 0 !important;
|
| 41 |
-
padding: 4px 16px !important;
|
| 42 |
-
color: #555 !important;
|
| 43 |
-
background: transparent !important;
|
| 44 |
-
}
|
| 45 |
-
.dark #hy-chat blockquote {
|
| 46 |
-
border-left-color: #3a3a3a !important;
|
| 47 |
-
color: #909090 !important;
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
/* ── tables ──
|
| 51 |
-
* Markdown tables otherwise render with ``display: table`` and
|
| 52 |
-
* intrinsic auto sizing, which lets a wide table push past the
|
| 53 |
-
* message's ``max-width: 95%`` and overflow ``#hy-chat`` horizontally.
|
| 54 |
-
* Beyond the obvious horizontal-clip ugliness, the post-stream column-
|
| 55 |
-
* width pass (browser re-measures cells once all rows are in) was
|
| 56 |
-
* leaving ``#hy-chat``'s ``scrollHeight`` desynced from real layout —
|
| 57 |
-
* the user could drag the scrollbar to the bottom of its track without
|
| 58 |
-
* reaching the actual last row of the answer, and the wheel was dead
|
| 59 |
-
* because they really were at the (stale) max scrollTop.
|
| 60 |
-
*
|
| 61 |
-
* The fix is to (a) keep the table inside the message bubble and
|
| 62 |
-
* (b) make any too-wide table scroll horizontally inside ITS OWN
|
| 63 |
-
* bounds rather than the row's:
|
| 64 |
-
* - ``display: block`` + ``max-width: 100%`` + ``overflow-x: auto``
|
| 65 |
-
* makes the ``<table>`` itself a horizontally-scrollable inline
|
| 66 |
-
* box; column widths are still auto-computed but the layout
|
| 67 |
-
* impact stays inside the table.
|
| 68 |
-
* - ``border-collapse: collapse`` + light borders give it the
|
| 69 |
-
* conventional spreadsheet look without adding cell-spacing
|
| 70 |
-
* surprises that browsers handle inconsistently. */
|
| 71 |
-
#hy-chat table {
|
| 72 |
-
display: block !important;
|
| 73 |
-
width: max-content !important;
|
| 74 |
-
max-width: 100% !important;
|
| 75 |
-
overflow-x: auto !important;
|
| 76 |
-
border-collapse: collapse !important;
|
| 77 |
-
margin: 0.8em 0 !important;
|
| 78 |
-
font-size: 14px !important;
|
| 79 |
-
}
|
| 80 |
-
#hy-chat th,
|
| 81 |
-
#hy-chat td {
|
| 82 |
-
border: 1px solid #e5e5ea !important;
|
| 83 |
-
padding: 6px 12px !important;
|
| 84 |
-
text-align: left !important;
|
| 85 |
-
vertical-align: top !important;
|
| 86 |
-
}
|
| 87 |
-
#hy-chat th {
|
| 88 |
-
background: #f5f5f7 !important;
|
| 89 |
-
font-weight: 600 !important;
|
| 90 |
-
}
|
| 91 |
-
.dark #hy-chat th,
|
| 92 |
-
.dark #hy-chat td {
|
| 93 |
-
border-color: #333 !important;
|
| 94 |
-
}
|
| 95 |
-
.dark #hy-chat th {
|
| 96 |
-
background: #1f1f1f !important;
|
| 97 |
-
}
|
| 98 |
-
|
| 99 |
-
/* ── hr ── */
|
| 100 |
-
#hy-chat hr {
|
| 101 |
-
border: none !important;
|
| 102 |
-
border-top: 1px solid #e5e5ea !important;
|
| 103 |
-
margin: 1.2em 0 !important;
|
| 104 |
-
}
|
| 105 |
-
.dark #hy-chat hr {
|
| 106 |
-
border-top-color: #2a2a2a !important;
|
| 107 |
-
}
|
| 108 |
-
|
| 109 |
-
/* ── slider progress ── */
|
| 110 |
-
.gradio-container input[type="range"]::-moz-range-progress { background-color: #2563eb !important; }
|
| 111 |
-
.gradio-container input[type="range"]::-moz-range-track { background: #e5e7eb !important; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_modals.css
DELETED
|
@@ -1,266 +0,0 @@
|
|
| 1 |
-
/* ─────────────────────────────────────────────────────────────────────────
|
| 2 |
-
* Floating panels: tool-call input area + HTML preview modal.
|
| 3 |
-
*
|
| 4 |
-
* #tool-area lives inside the Gradio tree, so it still needs !important to
|
| 5 |
-
* win the cascade against framework styles.
|
| 6 |
-
*
|
| 7 |
-
* .html-preview-* lives directly under <body> (appended by static/app.js)
|
| 8 |
-
* so it can use plain specificity.
|
| 9 |
-
* ───────────────────────────────────────────────────────────────────────── */
|
| 10 |
-
|
| 11 |
-
/* ── tool area (inside Gradio) ─────────────────────────────────────────── */
|
| 12 |
-
#tool-area {
|
| 13 |
-
position: fixed !important;
|
| 14 |
-
bottom: 120px !important;
|
| 15 |
-
left: 50% !important;
|
| 16 |
-
transform: translateX(-50%) !important;
|
| 17 |
-
width: min(600px, 55%) !important;
|
| 18 |
-
z-index: 999 !important;
|
| 19 |
-
background: var(--hy-bg) !important;
|
| 20 |
-
border: 1px solid var(--hy-border) !important;
|
| 21 |
-
border-radius: 12px !important;
|
| 22 |
-
padding: 16px !important;
|
| 23 |
-
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08) !important;
|
| 24 |
-
}
|
| 25 |
-
.dark #tool-area {
|
| 26 |
-
background: var(--hy-bg-soft) !important;
|
| 27 |
-
border-color: var(--hy-border) !important;
|
| 28 |
-
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.5) !important;
|
| 29 |
-
}
|
| 30 |
-
.dark #tool-area *:not(button):not(button *) {
|
| 31 |
-
background: transparent !important;
|
| 32 |
-
border-color: var(--hy-border-strong) !important;
|
| 33 |
-
}
|
| 34 |
-
.dark #tool-area textarea,
|
| 35 |
-
.dark #tool-area input[type="text"] {
|
| 36 |
-
background: var(--hy-bg-muted) !important;
|
| 37 |
-
color: var(--hy-text) !important;
|
| 38 |
-
border: 1px solid var(--hy-border-strong) !important;
|
| 39 |
-
}
|
| 40 |
-
.dark #tool-area textarea::placeholder,
|
| 41 |
-
.dark #tool-area input[type="text"]::placeholder {
|
| 42 |
-
color: var(--hy-text-muted) !important;
|
| 43 |
-
}
|
| 44 |
-
|
| 45 |
-
/* ── Code-block card (header w/ language label + copy button) ──────────
|
| 46 |
-
*
|
| 47 |
-
* Each fenced code block is wrapped by static/app.js:
|
| 48 |
-
*
|
| 49 |
-
* <div class="hy-codeblock">
|
| 50 |
-
* <div class="hy-codeblock-header">
|
| 51 |
-
* <span class="hy-codeblock-lang">python</span>
|
| 52 |
-
* <button class="code-copy-btn">…</button>
|
| 53 |
-
* </div>
|
| 54 |
-
* <pre><code class="hljs language-…">…</code></pre>
|
| 55 |
-
* </div>
|
| 56 |
-
*
|
| 57 |
-
* The wrapper owns the rounded border and background so the inner <pre>
|
| 58 |
-
* can be flush with the header (no double border / gap). */
|
| 59 |
-
#hy-chat .hy-codeblock {
|
| 60 |
-
margin: 0.9em 0;
|
| 61 |
-
border: 1px solid var(--hy-border);
|
| 62 |
-
border-radius: 10px;
|
| 63 |
-
overflow: hidden;
|
| 64 |
-
background: #f6f7f9;
|
| 65 |
-
}
|
| 66 |
-
.dark #hy-chat .hy-codeblock {
|
| 67 |
-
border-color: #2a2a2a;
|
| 68 |
-
background: #0f1115;
|
| 69 |
-
}
|
| 70 |
-
|
| 71 |
-
#hy-chat .hy-codeblock-header {
|
| 72 |
-
display: flex;
|
| 73 |
-
align-items: center;
|
| 74 |
-
justify-content: space-between;
|
| 75 |
-
gap: 12px;
|
| 76 |
-
padding: 6px 8px 6px 14px;
|
| 77 |
-
background: #ececef;
|
| 78 |
-
border-bottom: 1px solid var(--hy-border);
|
| 79 |
-
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text",
|
| 80 |
-
"Segoe UI", Roboto, sans-serif;
|
| 81 |
-
font-size: 12px;
|
| 82 |
-
line-height: 1;
|
| 83 |
-
color: #6b6b6b;
|
| 84 |
-
user-select: none;
|
| 85 |
-
}
|
| 86 |
-
.dark #hy-chat .hy-codeblock-header {
|
| 87 |
-
background: #1a1d22;
|
| 88 |
-
border-bottom-color: #262a30;
|
| 89 |
-
color: #9ca3af;
|
| 90 |
-
}
|
| 91 |
-
|
| 92 |
-
#hy-chat .hy-codeblock-lang {
|
| 93 |
-
text-transform: lowercase;
|
| 94 |
-
letter-spacing: 0.02em;
|
| 95 |
-
font-weight: 500;
|
| 96 |
-
}
|
| 97 |
-
#hy-chat .hy-codeblock-lang:empty::before {
|
| 98 |
-
content: "text";
|
| 99 |
-
opacity: 0.7;
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
/* Strip the standalone <pre> chrome from _misc.css when nested in a
|
| 103 |
-
* .hy-codeblock — the wrapper provides the border/radius/background. */
|
| 104 |
-
#hy-chat .hy-codeblock pre {
|
| 105 |
-
margin: 0 !important;
|
| 106 |
-
border: none !important;
|
| 107 |
-
border-radius: 0 !important;
|
| 108 |
-
background: transparent !important;
|
| 109 |
-
padding: 12px 16px !important;
|
| 110 |
-
}
|
| 111 |
-
|
| 112 |
-
/* Copy button — lives in the header, simple icon button. */
|
| 113 |
-
#hy-chat .hy-codeblock-header .code-copy-btn {
|
| 114 |
-
flex-shrink: 0;
|
| 115 |
-
width: 26px;
|
| 116 |
-
height: 26px;
|
| 117 |
-
padding: 0;
|
| 118 |
-
display: inline-flex;
|
| 119 |
-
align-items: center;
|
| 120 |
-
justify-content: center;
|
| 121 |
-
color: inherit;
|
| 122 |
-
background: transparent;
|
| 123 |
-
border: none;
|
| 124 |
-
border-radius: 6px;
|
| 125 |
-
cursor: pointer;
|
| 126 |
-
transition: background 0.15s ease, color 0.15s ease;
|
| 127 |
-
}
|
| 128 |
-
#hy-chat .hy-codeblock-header .code-copy-btn svg {
|
| 129 |
-
display: block;
|
| 130 |
-
width: 14px;
|
| 131 |
-
height: 14px;
|
| 132 |
-
}
|
| 133 |
-
#hy-chat .hy-codeblock-header .code-copy-btn:hover {
|
| 134 |
-
background: rgba(0, 0, 0, 0.06);
|
| 135 |
-
color: #111;
|
| 136 |
-
}
|
| 137 |
-
#hy-chat .hy-codeblock-header .code-copy-btn:focus {
|
| 138 |
-
outline: none;
|
| 139 |
-
}
|
| 140 |
-
#hy-chat .hy-codeblock-header .code-copy-btn:focus-visible {
|
| 141 |
-
outline: 2px solid var(--hy-accent, #2563eb);
|
| 142 |
-
outline-offset: 1px;
|
| 143 |
-
}
|
| 144 |
-
#hy-chat .hy-codeblock-header .code-copy-btn.copied,
|
| 145 |
-
#hy-chat .hy-codeblock-header .code-copy-btn.copied:hover {
|
| 146 |
-
color: #0a7f3f;
|
| 147 |
-
background: transparent;
|
| 148 |
-
}
|
| 149 |
-
.dark #hy-chat .hy-codeblock-header .code-copy-btn:hover {
|
| 150 |
-
background: rgba(255, 255, 255, 0.08);
|
| 151 |
-
color: #f5f5f5;
|
| 152 |
-
}
|
| 153 |
-
.dark #hy-chat .hy-codeblock-header .code-copy-btn.copied,
|
| 154 |
-
.dark #hy-chat .hy-codeblock-header .code-copy-btn.copied:hover {
|
| 155 |
-
color: #4ade80;
|
| 156 |
-
background: transparent;
|
| 157 |
-
}
|
| 158 |
-
|
| 159 |
-
/* ── HTML preview play button (under code blocks) ─────────────────────── */
|
| 160 |
-
.html-preview-btn {
|
| 161 |
-
display: inline-flex;
|
| 162 |
-
align-items: center;
|
| 163 |
-
background: none;
|
| 164 |
-
border: none;
|
| 165 |
-
padding: 2px 0;
|
| 166 |
-
margin: 2px 0 6px;
|
| 167 |
-
cursor: pointer;
|
| 168 |
-
font-size: 0;
|
| 169 |
-
line-height: 1;
|
| 170 |
-
transition: opacity 0.15s ease;
|
| 171 |
-
}
|
| 172 |
-
.html-preview-btn::before {
|
| 173 |
-
content: "▶ html preview";
|
| 174 |
-
font-size: 12px;
|
| 175 |
-
color: var(--hy-accent);
|
| 176 |
-
font-weight: 400;
|
| 177 |
-
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
|
| 178 |
-
}
|
| 179 |
-
.html-preview-btn:hover {
|
| 180 |
-
opacity: 0.7;
|
| 181 |
-
}
|
| 182 |
-
|
| 183 |
-
/* ── HTML preview modal (outside Gradio, under <body>) ────────────────── */
|
| 184 |
-
.html-preview-overlay {
|
| 185 |
-
position: fixed;
|
| 186 |
-
inset: 0;
|
| 187 |
-
z-index: 10000;
|
| 188 |
-
background: rgba(0, 0, 0, 0.5);
|
| 189 |
-
display: flex;
|
| 190 |
-
align-items: center;
|
| 191 |
-
justify-content: center;
|
| 192 |
-
animation: fadeIn 0.2s ease;
|
| 193 |
-
}
|
| 194 |
-
@keyframes fadeIn {
|
| 195 |
-
from { opacity: 0; }
|
| 196 |
-
to { opacity: 1; }
|
| 197 |
-
}
|
| 198 |
-
|
| 199 |
-
.html-preview-modal {
|
| 200 |
-
width: 90vw;
|
| 201 |
-
height: 85vh;
|
| 202 |
-
background: var(--hy-bg);
|
| 203 |
-
border-radius: 12px;
|
| 204 |
-
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
|
| 205 |
-
display: flex;
|
| 206 |
-
flex-direction: column;
|
| 207 |
-
overflow: hidden;
|
| 208 |
-
animation: modalSlideUp 0.25s ease;
|
| 209 |
-
}
|
| 210 |
-
.dark .html-preview-modal {
|
| 211 |
-
background: var(--hy-bg-soft);
|
| 212 |
-
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
|
| 213 |
-
}
|
| 214 |
-
@keyframes modalSlideUp {
|
| 215 |
-
from { transform: translateY(30px); opacity: 0; }
|
| 216 |
-
to { transform: translateY(0); opacity: 1; }
|
| 217 |
-
}
|
| 218 |
-
|
| 219 |
-
.html-preview-header {
|
| 220 |
-
display: flex;
|
| 221 |
-
align-items: center;
|
| 222 |
-
justify-content: space-between;
|
| 223 |
-
padding: 12px 20px;
|
| 224 |
-
border-bottom: 1px solid var(--hy-border);
|
| 225 |
-
background: var(--hy-bg-soft);
|
| 226 |
-
flex-shrink: 0;
|
| 227 |
-
}
|
| 228 |
-
.dark .html-preview-header {
|
| 229 |
-
background: var(--hy-bg-muted);
|
| 230 |
-
}
|
| 231 |
-
|
| 232 |
-
.html-preview-title {
|
| 233 |
-
font-size: 14px;
|
| 234 |
-
font-weight: 600;
|
| 235 |
-
color: var(--hy-text);
|
| 236 |
-
display: flex;
|
| 237 |
-
align-items: center;
|
| 238 |
-
gap: 8px;
|
| 239 |
-
}
|
| 240 |
-
.html-preview-title::before {
|
| 241 |
-
content: "⬡";
|
| 242 |
-
color: var(--hy-accent);
|
| 243 |
-
}
|
| 244 |
-
|
| 245 |
-
.html-preview-close {
|
| 246 |
-
background: none;
|
| 247 |
-
border: none;
|
| 248 |
-
font-size: 20px;
|
| 249 |
-
color: var(--hy-text-muted);
|
| 250 |
-
cursor: pointer;
|
| 251 |
-
padding: 4px 8px;
|
| 252 |
-
border-radius: 6px;
|
| 253 |
-
line-height: 1;
|
| 254 |
-
transition: all 0.15s ease;
|
| 255 |
-
}
|
| 256 |
-
.html-preview-close:hover {
|
| 257 |
-
background: #fee2e2;
|
| 258 |
-
color: #dc2626;
|
| 259 |
-
}
|
| 260 |
-
|
| 261 |
-
.html-preview-iframe {
|
| 262 |
-
flex: 1;
|
| 263 |
-
border: none;
|
| 264 |
-
width: 100%;
|
| 265 |
-
background: var(--hy-bg);
|
| 266 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_perf.css
DELETED
|
@@ -1,50 +0,0 @@
|
|
| 1 |
-
/* ── Long-conversation rendering optimizations ─────────────────────────
|
| 2 |
-
*
|
| 3 |
-
* Three CSS optimizations have been tried on ``.message-row`` and all
|
| 4 |
-
* three were ULTIMATELY REMOVED because each caused a real, repeatable
|
| 5 |
-
* scroll-geometry bug:
|
| 6 |
-
*
|
| 7 |
-
* 1. ``contain: layout`` — when a child ``<details
|
| 8 |
-
* class="thinking-block">`` collapsed (either via
|
| 9 |
-
* ``markThinkingDone`` mid-stream OR via a user click), the row's
|
| 10 |
-
* contribution to ``#hy-chat``'s ``scrollHeight`` got stranded at
|
| 11 |
-
* the pre-collapse value on Chromium. The user would scroll up
|
| 12 |
-
* to read history, drag the scrollbar back to the bottom, and
|
| 13 |
-
* the thumb would hit the end of the track while the chat
|
| 14 |
-
* stopped many screens above the latest message; the wheel did
|
| 15 |
-
* nothing because they really were at ``scrollHeight -
|
| 16 |
-
* clientHeight``. Manually toggling the collapsed Thinking block
|
| 17 |
-
* open forced a relayout that fixed it — the diagnostic
|
| 18 |
-
* fingerprint.
|
| 19 |
-
*
|
| 20 |
-
* 2. ``contain: paint`` — the same symptom recurred under a
|
| 21 |
-
* narrower trigger: assistant turns containing wide elements
|
| 22 |
-
* (most commonly markdown tables, also ``katex-display`` blocks,
|
| 23 |
-
* and fenced code with long lines). ``paint`` containment makes
|
| 24 |
-
* the row a stacking context AND clips overflow at the contain
|
| 25 |
-
* box. Combined with the post-stream lazy-render passes
|
| 26 |
-
* (``hljs.highlightElement``, KaTeX re-render of the streaming
|
| 27 |
-
* tail, table column-width pass), the row's reported size in
|
| 28 |
-
* ``#hy-chat``'s scroll metrics drifted away from its real
|
| 29 |
-
* rendered size by hundreds-to-thousands of pixels. Toggling
|
| 30 |
-
* Thinking no longer fixed this case because the stranded value
|
| 31 |
-
* was on the post-table row, not the row containing Thinking.
|
| 32 |
-
*
|
| 33 |
-
* 3. ``content-visibility: auto`` — skipping render for off-screen
|
| 34 |
-
* rows. Row heights vary wildly (a "你好" reply is ~40px, a
|
| 35 |
-
* math derivation or table-heavy answer is 3000–5000px). With
|
| 36 |
-
* ``contain-intrinsic-size: auto 240px`` as the placeholder,
|
| 37 |
-
* scrolling up by a tiny amount caused off-screen rows to expand
|
| 38 |
-
* from 240px to their real size, growing ``scrollHeight`` by
|
| 39 |
-
* thousands of pixels in a single frame. Browser scroll
|
| 40 |
-
* anchoring did not reliably compensate, so the view jumped far
|
| 41 |
-
* up the conversation and felt broken.
|
| 42 |
-
*
|
| 43 |
-
* If we ever need any of these optimizations back, gate them behind a
|
| 44 |
-
* row-count threshold (only apply to rows older than the last N) and,
|
| 45 |
-
* for option 3, measure each row's real height before swapping it out
|
| 46 |
-
* so ``contain-intrinsic-size`` is per-row rather than a single
|
| 47 |
-
* global guess. For options 1 & 2, also wire a ``ResizeObserver`` on
|
| 48 |
-
* each row that re-dispatches ``hy-chat:updated`` whenever the row's
|
| 49 |
-
* height changes (the scroll-lock in ``static/app.js`` uses that
|
| 50 |
-
* event to re-evaluate / re-pin). */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_thinking.css
DELETED
|
@@ -1,35 +0,0 @@
|
|
| 1 |
-
/* ── thinking toggle ── */
|
| 2 |
-
#hy-chat .thinking-block {
|
| 3 |
-
background: none !important;
|
| 4 |
-
border: none !important;
|
| 5 |
-
padding: 0 !important;
|
| 6 |
-
margin: 6px 0 10px !important;
|
| 7 |
-
}
|
| 8 |
-
#hy-chat .thinking-block summary {
|
| 9 |
-
cursor: pointer;
|
| 10 |
-
font-size: 13px !important;
|
| 11 |
-
font-weight: 400 !important;
|
| 12 |
-
color: #8a8a8e !important;
|
| 13 |
-
padding: 0 !important;
|
| 14 |
-
list-style: none !important;
|
| 15 |
-
display: inline-flex;
|
| 16 |
-
align-items: center;
|
| 17 |
-
gap: 4px;
|
| 18 |
-
}
|
| 19 |
-
#hy-chat .thinking-block summary:hover { color: #666 !important; }
|
| 20 |
-
.dark #hy-chat .thinking-block summary { color: #808080 !important; }
|
| 21 |
-
.dark #hy-chat .thinking-block summary:hover { color: #aaa !important; }
|
| 22 |
-
#hy-chat .thinking-block summary::marker,
|
| 23 |
-
#hy-chat .thinking-block summary::-webkit-details-marker { display: none !important; }
|
| 24 |
-
#hy-chat .thinking-block summary::after { content: " ›" !important; font-size: 13px; color: #bbb; }
|
| 25 |
-
#hy-chat .thinking-block[open] summary::after { content: " ⌄" !important; }
|
| 26 |
-
#hy-chat .thinking-block[open] summary { margin-bottom: 8px !important; }
|
| 27 |
-
#hy-chat .thinking-block[open] > :not(summary) {
|
| 28 |
-
font-size: 13px; color: #666; line-height: 1.7;
|
| 29 |
-
padding: 12px 16px; background: #f8f8fa !important; border-radius: 8px;
|
| 30 |
-
max-height: 300px; overflow-y: auto; border-left: 2px solid #e5e5ea !important;
|
| 31 |
-
}
|
| 32 |
-
.dark #hy-chat .thinking-block[open] > :not(summary) {
|
| 33 |
-
color: #909090 !important; background: #1c1c1c !important;
|
| 34 |
-
border-left-color: #333 !important;
|
| 35 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_typing.css
DELETED
|
@@ -1,29 +0,0 @@
|
|
| 1 |
-
/* ── typing indicator (waiting for model response) ── */
|
| 2 |
-
.typing-indicator {
|
| 3 |
-
display: flex;
|
| 4 |
-
align-items: center;
|
| 5 |
-
gap: 5px;
|
| 6 |
-
padding: 4px 0;
|
| 7 |
-
height: 24px;
|
| 8 |
-
}
|
| 9 |
-
.typing-indicator span {
|
| 10 |
-
width: 8px;
|
| 11 |
-
height: 8px;
|
| 12 |
-
background: var(--body-text-color-subdued, #999);
|
| 13 |
-
border-radius: 50%;
|
| 14 |
-
animation: typing-bounce 1.4s infinite ease-in-out both;
|
| 15 |
-
}
|
| 16 |
-
.typing-indicator span:nth-child(1) { animation-delay: 0s; }
|
| 17 |
-
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
|
| 18 |
-
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
|
| 19 |
-
|
| 20 |
-
@keyframes typing-bounce {
|
| 21 |
-
0%, 80%, 100% {
|
| 22 |
-
transform: scale(0.5);
|
| 23 |
-
opacity: 0.35;
|
| 24 |
-
}
|
| 25 |
-
40% {
|
| 26 |
-
transform: scale(1);
|
| 27 |
-
opacity: 1;
|
| 28 |
-
}
|
| 29 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/css/_variables.css
DELETED
|
@@ -1,81 +0,0 @@
|
|
| 1 |
-
/* ─────────────────────────────────────────────────────────────────────────
|
| 2 |
-
* Design tokens (custom properties)
|
| 3 |
-
*
|
| 4 |
-
* Two layers:
|
| 5 |
-
* 1. ``--hy-*`` : our own palette — referenced from component CSS.
|
| 6 |
-
* 2. ``--*-*-*`` : Gradio's built-in tokens — overridden so Gradio's
|
| 7 |
-
* components match the rest of the UI.
|
| 8 |
-
*
|
| 9 |
-
* If you want to retheme HY3, change values here and (almost) nowhere else.
|
| 10 |
-
* ───────────────────────────────────────────────────────────────────────── */
|
| 11 |
-
|
| 12 |
-
:root, .gradio-container {
|
| 13 |
-
/* Hy3 palette (light) */
|
| 14 |
-
--hy-bg: #ffffff;
|
| 15 |
-
--hy-bg-soft: #fafafa;
|
| 16 |
-
--hy-bg-muted: #f5f5f7;
|
| 17 |
-
--hy-text: #222222;
|
| 18 |
-
--hy-text-strong: #111111;
|
| 19 |
-
--hy-text-muted: #666666;
|
| 20 |
-
--hy-border: #e5e7eb;
|
| 21 |
-
--hy-border-strong: #d1d1d6;
|
| 22 |
-
--hy-accent: #2563eb;
|
| 23 |
-
--hy-accent-hover: #1d4ed8;
|
| 24 |
-
--hy-accent-soft: #dbeafe;
|
| 25 |
-
--hy-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
| 26 |
-
|
| 27 |
-
/* Gradio framework overrides (light) */
|
| 28 |
-
--body-background-fill: var(--hy-bg) !important;
|
| 29 |
-
--block-background-fill: var(--hy-bg) !important;
|
| 30 |
-
--block-shadow: none !important;
|
| 31 |
-
--block-border-color: transparent !important;
|
| 32 |
-
--input-border-width: 1px !important;
|
| 33 |
-
--input-border-color: var(--hy-border) !important;
|
| 34 |
-
--color-accent: var(--hy-accent) !important;
|
| 35 |
-
--color-accent-soft: var(--hy-accent-soft) !important;
|
| 36 |
-
--button-primary-background-fill: var(--hy-accent) !important;
|
| 37 |
-
--button-primary-background-fill-hover: var(--hy-accent-hover) !important;
|
| 38 |
-
--button-primary-text-color: #ffffff !important;
|
| 39 |
-
--slider-color: var(--hy-accent) !important;
|
| 40 |
-
--neutral-200: var(--hy-border) !important;
|
| 41 |
-
}
|
| 42 |
-
|
| 43 |
-
/* Hy3 palette (dark) + matching Gradio overrides */
|
| 44 |
-
.dark {
|
| 45 |
-
--hy-bg: #171717;
|
| 46 |
-
--hy-bg-soft: #1f1f1f;
|
| 47 |
-
--hy-bg-muted: #2a2a2a;
|
| 48 |
-
--hy-text: #e8e8e8;
|
| 49 |
-
--hy-text-strong: #ffffff;
|
| 50 |
-
--hy-text-muted: #909090;
|
| 51 |
-
--hy-border: #2a2a2a;
|
| 52 |
-
--hy-border-strong: #3a3a3a;
|
| 53 |
-
--hy-accent: #6b9fff;
|
| 54 |
-
--hy-accent-hover: #4b8df8;
|
| 55 |
-
--hy-accent-soft: #1a2a3d;
|
| 56 |
-
--hy-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
|
| 57 |
-
|
| 58 |
-
--body-background-fill: var(--hy-bg) !important;
|
| 59 |
-
--block-background-fill: var(--hy-bg-soft) !important;
|
| 60 |
-
--block-shadow: none !important;
|
| 61 |
-
--block-border-color: var(--hy-border) !important;
|
| 62 |
-
--input-border-width: 1px !important;
|
| 63 |
-
--input-border-color: var(--hy-border-strong) !important;
|
| 64 |
-
--color-accent: var(--hy-accent) !important;
|
| 65 |
-
--color-accent-soft: var(--hy-accent-soft) !important;
|
| 66 |
-
--button-primary-background-fill: var(--hy-accent-hover) !important;
|
| 67 |
-
--button-primary-background-fill-hover: #3a7ce6 !important;
|
| 68 |
-
--button-primary-text-color: #ffffff !important;
|
| 69 |
-
--slider-color: var(--hy-accent) !important;
|
| 70 |
-
--neutral-200: var(--hy-border) !important;
|
| 71 |
-
--body-text-color: var(--hy-text) !important;
|
| 72 |
-
--block-label-text-color: #c0c0c0 !important;
|
| 73 |
-
--block-title-text-color: #e0e0e0 !important;
|
| 74 |
-
--input-background-fill: var(--hy-bg-muted) !important;
|
| 75 |
-
--background-fill-secondary: var(--hy-bg-soft) !important;
|
| 76 |
-
--background-fill-primary: var(--hy-bg) !important;
|
| 77 |
-
--border-color-primary: var(--hy-border) !important;
|
| 78 |
-
--panel-background-fill: var(--hy-bg-soft) !important;
|
| 79 |
-
--checkbox-background-color: var(--hy-bg-muted) !important;
|
| 80 |
-
--checkbox-label-background-fill: var(--hy-bg-soft) !important;
|
| 81 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/vendor/highlight/LICENSE
DELETED
|
@@ -1,29 +0,0 @@
|
|
| 1 |
-
BSD 3-Clause License
|
| 2 |
-
|
| 3 |
-
Copyright (c) 2006, Ivan Sagalaev.
|
| 4 |
-
All rights reserved.
|
| 5 |
-
|
| 6 |
-
Redistribution and use in source and binary forms, with or without
|
| 7 |
-
modification, are permitted provided that the following conditions are met:
|
| 8 |
-
|
| 9 |
-
* Redistributions of source code must retain the above copyright notice, this
|
| 10 |
-
list of conditions and the following disclaimer.
|
| 11 |
-
|
| 12 |
-
* Redistributions in binary form must reproduce the above copyright notice,
|
| 13 |
-
this list of conditions and the following disclaimer in the documentation
|
| 14 |
-
and/or other materials provided with the distribution.
|
| 15 |
-
|
| 16 |
-
* Neither the name of the copyright holder nor the names of its
|
| 17 |
-
contributors may be used to endorse or promote products derived from
|
| 18 |
-
this software without specific prior written permission.
|
| 19 |
-
|
| 20 |
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 21 |
-
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 22 |
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 23 |
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 24 |
-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 25 |
-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 26 |
-
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 27 |
-
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 28 |
-
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 29 |
-
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/vendor/highlight/github-dark.min.css
DELETED
|
@@ -1,10 +0,0 @@
|
|
| 1 |
-
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
|
| 2 |
-
Theme: GitHub Dark
|
| 3 |
-
Description: Dark theme as seen on github.com
|
| 4 |
-
Author: github.com
|
| 5 |
-
Maintainer: @Hirse
|
| 6 |
-
Updated: 2021-05-15
|
| 7 |
-
|
| 8 |
-
Outdated base version: https://github.com/primer/github-syntax-dark
|
| 9 |
-
Current colors taken from GitHub's CSS
|
| 10 |
-
*/.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/vendor/highlight/github.min.css
DELETED
|
@@ -1,18 +0,0 @@
|
|
| 1 |
-
/**
|
| 2 |
-
* Minified by jsDelivr using clean-css v5.3.3.
|
| 3 |
-
* Original file: /gh/highlightjs/cdn-release@11.10.0/build/styles/github.css
|
| 4 |
-
*
|
| 5 |
-
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
| 6 |
-
*/
|
| 7 |
-
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
|
| 8 |
-
Theme: GitHub
|
| 9 |
-
Description: Light theme as seen on github.com
|
| 10 |
-
Author: github.com
|
| 11 |
-
Maintainer: @Hirse
|
| 12 |
-
Updated: 2021-05-15
|
| 13 |
-
|
| 14 |
-
Outdated base version: https://github.com/primer/github-syntax-light
|
| 15 |
-
Current colors taken from GitHub's CSS
|
| 16 |
-
*/
|
| 17 |
-
.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}
|
| 18 |
-
/*# sourceMappingURL=/sm/4af24df1ef2dd5fc126923c27abd2503f82240131784ba83446a7a23be61ec0f.map */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/vendor/highlight/highlight.min.js
DELETED
|
The diff for this file is too large to render.
See raw diff
|
|
|
static/vendor/katex/LICENSE
DELETED
|
@@ -1,27 +0,0 @@
|
|
| 1 |
-
The MIT License (MIT)
|
| 2 |
-
|
| 3 |
-
Copyright (c) 2013-2020 Khan Academy and other contributors
|
| 4 |
-
|
| 5 |
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
-
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
-
in the Software without restriction, including without limitation the rights
|
| 8 |
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
-
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
-
furnished to do so, subject to the following conditions:
|
| 11 |
-
|
| 12 |
-
The above copyright notice and this permission notice shall be included in all
|
| 13 |
-
copies or substantial portions of the Software.
|
| 14 |
-
|
| 15 |
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
-
SOFTWARE.
|
| 22 |
-
|
| 23 |
-
----------------------------------------------------------------------
|
| 24 |
-
|
| 25 |
-
NOTE: The KaTeX font files (under ./fonts/) are NOT covered by this MIT
|
| 26 |
-
license. They are licensed separately under the SIL Open Font License,
|
| 27 |
-
Version 1.1 — see ./fonts/OFL.txt.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/vendor/katex/auto-render.min.js
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={757:function(t){t.exports=e}},n={};function r(e){var o=n[e];if(void 0!==o)return o.exports;var i=n[e]={exports:{}};return t[e](i,i.exports,r),i.exports}r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,{a:t}),t},r.d=function(e,t){for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)};var o={};r.d(o,{default:function(){return p}});var i=r(757),a=r.n(i);const l=function(e,t,n){let r=n,o=0;const i=e.length;for(;r<t.length;){const n=t[r];if(o<=0&&t.slice(r,r+i)===e)return r;"\\"===n?r++:"{"===n?o++:"}"===n&&o--,r++}return-1},s=/^\\begin{/;var d=function(e,t){let n;const r=[],o=new RegExp("("+t.map((e=>e.left.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"))).join("|")+")");for(;n=e.search(o),-1!==n;){n>0&&(r.push({type:"text",data:e.slice(0,n)}),e=e.slice(n));const o=t.findIndex((t=>e.startsWith(t.left)));if(n=l(t[o].right,e,t[o].left.length),-1===n)break;const i=e.slice(0,n+t[o].right.length),a=s.test(i)?i:e.slice(t[o].left.length,n);r.push({type:"math",data:a,rawData:i,display:t[o].display}),e=e.slice(n+t[o].right.length)}return""!==e&&r.push({type:"text",data:e}),r};const c=function(e,t){const n=d(e,t.delimiters);if(1===n.length&&"text"===n[0].type)return null;const r=document.createDocumentFragment();for(let e=0;e<n.length;e++)if("text"===n[e].type)r.appendChild(document.createTextNode(n[e].data));else{const o=document.createElement("span");let i=n[e].data;t.displayMode=n[e].display;try{t.preProcess&&(i=t.preProcess(i)),a().render(i,o,t)}catch(o){if(!(o instanceof a().ParseError))throw o;t.errorCallback("KaTeX auto-render: Failed to parse `"+n[e].data+"` with ",o),r.appendChild(document.createTextNode(n[e].rawData));continue}r.appendChild(o)}return r},f=function(e,t){for(let n=0;n<e.childNodes.length;n++){const r=e.childNodes[n];if(3===r.nodeType){let o=r.textContent,i=r.nextSibling,a=0;for(;i&&i.nodeType===Node.TEXT_NODE;)o+=i.textContent,i=i.nextSibling,a++;const l=c(o,t);if(l){for(let e=0;e<a;e++)r.nextSibling.remove();n+=l.childNodes.length-1,e.replaceChild(l,r)}else n+=a}else if(1===r.nodeType){const e=" "+r.className+" ";-1===t.ignoredTags.indexOf(r.nodeName.toLowerCase())&&t.ignoredClasses.every((t=>-1===e.indexOf(" "+t+" ")))&&f(r,t)}}};var p=function(e,t){if(!e)throw new Error("No element provided to render");const n={};for(const e in t)t.hasOwnProperty(e)&&(n[e]=t[e]);n.delimiters=n.delimiters||[{left:"$$",right:"$$",display:!0},{left:"\\(",right:"\\)",display:!1},{left:"\\begin{equation}",right:"\\end{equation}",display:!0},{left:"\\begin{align}",right:"\\end{align}",display:!0},{left:"\\begin{alignat}",right:"\\end{alignat}",display:!0},{left:"\\begin{gather}",right:"\\end{gather}",display:!0},{left:"\\begin{CD}",right:"\\end{CD}",display:!0},{left:"\\[",right:"\\]",display:!0}],n.ignoredTags=n.ignoredTags||["script","noscript","style","textarea","pre","code","option"],n.ignoredClasses=n.ignoredClasses||[],n.errorCallback=n.errorCallback||console.error,n.macros=n.macros||{},f(e,n)};return o=o.default}()}));
|
|
|
|
|
|
static/vendor/katex/fonts/KaTeX_AMS-Regular.woff2
DELETED
|
Binary file (28.1 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2
DELETED
|
Binary file (6.91 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2
DELETED
|
Binary file (6.91 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2
DELETED
|
Binary file (11.3 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2
DELETED
|
Binary file (11.3 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Main-Bold.woff2
DELETED
|
Binary file (25.3 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2
DELETED
|
Binary file (16.8 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Main-Italic.woff2
DELETED
|
Binary file (17 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Main-Regular.woff2
DELETED
|
Binary file (26.3 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2
DELETED
|
Binary file (16.4 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Math-Italic.woff2
DELETED
|
Binary file (16.4 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2
DELETED
|
Binary file (12.2 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2
DELETED
|
Binary file (12 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2
DELETED
|
Binary file (10.3 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Script-Regular.woff2
DELETED
|
Binary file (9.64 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Size1-Regular.woff2
DELETED
|
Binary file (5.47 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Size2-Regular.woff2
DELETED
|
Binary file (5.21 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Size3-Regular.woff2
DELETED
|
Binary file (3.62 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Size4-Regular.woff2
DELETED
|
Binary file (4.93 kB)
|
|
|
static/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2
DELETED
|
Binary file (13.6 kB)
|
|
|
static/vendor/katex/fonts/OFL.txt
DELETED
|
@@ -1,98 +0,0 @@
|
|
| 1 |
-
Copyright (c) 2009-2010, Design Science, Inc. (<www.mathjax.org>),
|
| 2 |
-
with Reserved Font Name STIX-Web, Asana-Math, STIX, XITS, Latin Modern.
|
| 3 |
-
|
| 4 |
-
Copyright (c) 2014-2020, Khan Academy (<www.khanacademy.org>),
|
| 5 |
-
with Reserved Font Name KaTeX_AMS, KaTeX_Caligraphic, KaTeX_Fraktur,
|
| 6 |
-
KaTeX_Main, KaTeX_Math, KaTeX_SansSerif, KaTeX_Script, KaTeX_Size1,
|
| 7 |
-
KaTeX_Size2, KaTeX_Size3, KaTeX_Size4, KaTeX_Typewriter.
|
| 8 |
-
|
| 9 |
-
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
| 10 |
-
This license is copied below, and is also available with a FAQ at:
|
| 11 |
-
https://openfontlicense.org
|
| 12 |
-
|
| 13 |
-
-----------------------------------------------------------
|
| 14 |
-
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
| 15 |
-
-----------------------------------------------------------
|
| 16 |
-
|
| 17 |
-
PREAMBLE
|
| 18 |
-
The goals of the Open Font License (OFL) are to stimulate worldwide
|
| 19 |
-
development of collaborative font projects, to support the font creation
|
| 20 |
-
efforts of academic and linguistic communities, and to provide a free and
|
| 21 |
-
open framework in which fonts may be shared and improved in partnership
|
| 22 |
-
with others.
|
| 23 |
-
|
| 24 |
-
The OFL allows the licensed fonts to be used, studied, modified and
|
| 25 |
-
redistributed freely as long as they are not sold by themselves. The
|
| 26 |
-
fonts, including any derivative works, can be bundled, embedded,
|
| 27 |
-
redistributed and/or sold with any software provided that any reserved
|
| 28 |
-
names are not used by derivative works. The fonts and derivatives,
|
| 29 |
-
however, cannot be released under any other type of license. The
|
| 30 |
-
requirement for fonts to remain under this license does not apply
|
| 31 |
-
to any document created using the fonts or their derivatives.
|
| 32 |
-
|
| 33 |
-
DEFINITIONS
|
| 34 |
-
"Font Software" refers to the set of files released by the Copyright
|
| 35 |
-
Holder(s) under this license and clearly marked as such. This may
|
| 36 |
-
include source files, build scripts and documentation.
|
| 37 |
-
|
| 38 |
-
"Reserved Font Name" refers to any names specified as such after the
|
| 39 |
-
copyright statement(s).
|
| 40 |
-
|
| 41 |
-
"Original Version" refers to the collection of Font Software components as
|
| 42 |
-
distributed by the Copyright Holder(s).
|
| 43 |
-
|
| 44 |
-
"Modified Version" refers to any derivative made by adding to, deleting,
|
| 45 |
-
or substituting -- in part or in whole -- any of the components of the
|
| 46 |
-
Original Version, by changing formats or by porting the Font Software to a
|
| 47 |
-
new environment.
|
| 48 |
-
|
| 49 |
-
"Author" refers to any designer, engineer, programmer, technical
|
| 50 |
-
writer or other person who contributed to the Font Software.
|
| 51 |
-
|
| 52 |
-
PERMISSION & CONDITIONS
|
| 53 |
-
Permission is hereby granted, free of charge, to any person obtaining
|
| 54 |
-
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
| 55 |
-
redistribute, and sell modified and unmodified copies of the Font
|
| 56 |
-
Software, subject to the following conditions:
|
| 57 |
-
|
| 58 |
-
1) Neither the Font Software nor any of its individual components,
|
| 59 |
-
in Original or Modified Versions, may be sold by itself.
|
| 60 |
-
|
| 61 |
-
2) Original or Modified Versions of the Font Software may be bundled,
|
| 62 |
-
redistributed and/or sold with any software, provided that each copy
|
| 63 |
-
contains the above copyright notice and this license. These can be
|
| 64 |
-
included either as stand-alone text files, human-readable headers or
|
| 65 |
-
in the appropriate machine-readable metadata fields within text or
|
| 66 |
-
binary files as long as those fields can be easily viewed by the user.
|
| 67 |
-
|
| 68 |
-
3) No Modified Version of the Font Software may use the Reserved Font
|
| 69 |
-
Name(s) unless explicit written permission is granted by the corresponding
|
| 70 |
-
Copyright Holder. This restriction only applies to the primary font name as
|
| 71 |
-
presented to the users.
|
| 72 |
-
|
| 73 |
-
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
| 74 |
-
Software shall not be used to promote, endorse or advertise any
|
| 75 |
-
Modified Version, except to acknowledge the contribution(s) of the
|
| 76 |
-
Copyright Holder(s) and the Author(s) or with their explicit written
|
| 77 |
-
permission.
|
| 78 |
-
|
| 79 |
-
5) The Font Software, modified or unmodified, in part or in whole,
|
| 80 |
-
must be distributed entirely under this license, and must not be
|
| 81 |
-
distributed under any other license. The requirement for fonts to
|
| 82 |
-
remain under this license does not apply to any document created
|
| 83 |
-
using the Font Software.
|
| 84 |
-
|
| 85 |
-
TERMINATION
|
| 86 |
-
This license becomes null and void if any of the above conditions are
|
| 87 |
-
not met.
|
| 88 |
-
|
| 89 |
-
DISCLAIMER
|
| 90 |
-
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| 91 |
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
| 92 |
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
| 93 |
-
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
| 94 |
-
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
| 95 |
-
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
| 96 |
-
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
| 97 |
-
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
| 98 |
-
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/vendor/katex/katex.min.css
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
@font-face{font-family:KaTeX_AMS;font-style:normal;font-weight:400;src:url(fonts/KaTeX_AMS-Regular.woff2) format("woff2"),url(fonts/KaTeX_AMS-Regular.woff) format("woff"),url(fonts/KaTeX_AMS-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Caligraphic;font-style:normal;font-weight:700;src:url(fonts/KaTeX_Caligraphic-Bold.woff2) format("woff2"),url(fonts/KaTeX_Caligraphic-Bold.woff) format("woff"),url(fonts/KaTeX_Caligraphic-Bold.ttf) format("truetype")}@font-face{font-family:KaTeX_Caligraphic;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Caligraphic-Regular.woff2) format("woff2"),url(fonts/KaTeX_Caligraphic-Regular.woff) format("woff"),url(fonts/KaTeX_Caligraphic-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Fraktur;font-style:normal;font-weight:700;src:url(fonts/KaTeX_Fraktur-Bold.woff2) format("woff2"),url(fonts/KaTeX_Fraktur-Bold.woff) format("woff"),url(fonts/KaTeX_Fraktur-Bold.ttf) format("truetype")}@font-face{font-family:KaTeX_Fraktur;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Fraktur-Regular.woff2) format("woff2"),url(fonts/KaTeX_Fraktur-Regular.woff) format("woff"),url(fonts/KaTeX_Fraktur-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:normal;font-weight:700;src:url(fonts/KaTeX_Main-Bold.woff2) format("woff2"),url(fonts/KaTeX_Main-Bold.woff) format("woff"),url(fonts/KaTeX_Main-Bold.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:italic;font-weight:700;src:url(fonts/KaTeX_Main-BoldItalic.woff2) format("woff2"),url(fonts/KaTeX_Main-BoldItalic.woff) format("woff"),url(fonts/KaTeX_Main-BoldItalic.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:italic;font-weight:400;src:url(fonts/KaTeX_Main-Italic.woff2) format("woff2"),url(fonts/KaTeX_Main-Italic.woff) format("woff"),url(fonts/KaTeX_Main-Italic.ttf) format("truetype")}@font-face{font-family:KaTeX_Main;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Main-Regular.woff2) format("woff2"),url(fonts/KaTeX_Main-Regular.woff) format("woff"),url(fonts/KaTeX_Main-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Math;font-style:italic;font-weight:700;src:url(fonts/KaTeX_Math-BoldItalic.woff2) format("woff2"),url(fonts/KaTeX_Math-BoldItalic.woff) format("woff"),url(fonts/KaTeX_Math-BoldItalic.ttf) format("truetype")}@font-face{font-family:KaTeX_Math;font-style:italic;font-weight:400;src:url(fonts/KaTeX_Math-Italic.woff2) format("woff2"),url(fonts/KaTeX_Math-Italic.woff) format("woff"),url(fonts/KaTeX_Math-Italic.ttf) format("truetype")}@font-face{font-family:"KaTeX_SansSerif";font-style:normal;font-weight:700;src:url(fonts/KaTeX_SansSerif-Bold.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Bold.woff) format("woff"),url(fonts/KaTeX_SansSerif-Bold.ttf) format("truetype")}@font-face{font-family:"KaTeX_SansSerif";font-style:italic;font-weight:400;src:url(fonts/KaTeX_SansSerif-Italic.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Italic.woff) format("woff"),url(fonts/KaTeX_SansSerif-Italic.ttf) format("truetype")}@font-face{font-family:"KaTeX_SansSerif";font-style:normal;font-weight:400;src:url(fonts/KaTeX_SansSerif-Regular.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Regular.woff) format("woff"),url(fonts/KaTeX_SansSerif-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Script;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Script-Regular.woff2) format("woff2"),url(fonts/KaTeX_Script-Regular.woff) format("woff"),url(fonts/KaTeX_Script-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Size1;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size1-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size1-Regular.woff) format("woff"),url(fonts/KaTeX_Size1-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Size2;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size2-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size2-Regular.woff) format("woff"),url(fonts/KaTeX_Size2-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Size3;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size3-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size3-Regular.woff) format("woff"),url(fonts/KaTeX_Size3-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Size4;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size4-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size4-Regular.woff) format("woff"),url(fonts/KaTeX_Size4-Regular.ttf) format("truetype")}@font-face{font-family:KaTeX_Typewriter;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Typewriter-Regular.woff2) format("woff2"),url(fonts/KaTeX_Typewriter-Regular.woff) format("woff"),url(fonts/KaTeX_Typewriter-Regular.ttf) format("truetype")}.katex{font:normal 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;text-indent:0;text-rendering:auto}.katex *{-ms-high-contrast-adjust:none!important;border-color:currentColor}.katex .katex-version:after{content:"0.16.21"}.katex .katex-mathml{clip:rect(1px,1px,1px,1px);border:0;height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:-webkit-min-content;width:-moz-min-content;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-style:italic;font-weight:700}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathboldfrak,.katex .textboldfrak{font-family:KaTeX_Fraktur;font-weight:700}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .mathsfit,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{border-collapse:collapse;display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;position:relative;vertical-align:bottom}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;font-size:1px;min-width:2px;vertical-align:bottom;width:2px}.katex .vbox{align-items:baseline;display:inline-flex;flex-direction:column}.katex .hbox{width:100%}.katex .hbox,.katex .thinbox{display:inline-flex;flex-direction:row}.katex .thinbox{max-width:0;width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .clap,.katex .llap,.katex .rlap{position:relative;width:0}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{border:0 solid;display:inline-block;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline{border-bottom-style:dashed;display:inline-block;width:100%}.katex .sqrt>.root{margin-left:.2777777778em;margin-right:-.5555555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.1666666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.6666666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.4566666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.1466666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.7142857143em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.8571428571em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.1428571429em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.2857142857em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.4285714286em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.7142857143em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.0571428571em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.4685714286em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.9628571429em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.5542857143em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.7777777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.8888888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.1111111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.3044444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.7644444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.5833333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.7283333333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.0733333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.4861111111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.4402777778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.7277777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.2893518519em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.4050925926em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.462962963em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.5208333333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.2002314815em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.4398148148em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.2410800386em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.2892960463em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.337512054em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.3857280617em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.4339440694em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.4821600771em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.5785920926em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.6943105111em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.8331726133em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.1996142719em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.2009646302em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.2411575563em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.2813504823em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.3215434084em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.3617363344em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.4019292605em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.4823151125em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.578778135em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.6945337621em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.8336012862em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist-t,.katex .op-limits>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{fill:currentColor;stroke:currentColor;fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:block;height:inherit;position:absolute;width:100%}.katex svg path{stroke:none}.katex img{border-style:none;max-height:none;max-width:none;min-height:0;min-width:0}.katex .stretchy{display:block;overflow:hidden;position:relative;width:100%}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{overflow:hidden;position:relative;width:100%}.katex .halfarrow-left{left:0;overflow:hidden;position:absolute;width:50.2%}.katex .halfarrow-right{overflow:hidden;position:absolute;right:0;width:50.2%}.katex .brace-left{left:0;overflow:hidden;position:absolute;width:25.1%}.katex .brace-center{left:25%;overflow:hidden;position:absolute;width:50%}.katex .brace-right{overflow:hidden;position:absolute;right:0;width:25.1%}.katex .x-arrow-pad{padding:0 .5em}.katex .cd-arrow-pad{padding:0 .55556em 0 .27778em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{border:.04em solid;box-sizing:border-box}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex .angl{border-right:.049em solid;border-top:.049em solid;box-sizing:border-box;margin-right:.03889em}.katex .anglpad{padding:0 .03889em}.katex .eqn-num:before{content:"(" counter(katexEqnNo) ")";counter-increment:katexEqnNo}.katex .mml-eqn-num:before{content:"(" counter(mmlEqnNo) ")";counter-increment:mmlEqnNo}.katex .mtr-glue{width:50%}.katex .cd-vert-arrow{display:inline-block;position:relative}.katex .cd-label-left{display:inline-block;position:absolute;right:calc(50% + .3em);text-align:left}.katex .cd-label-right{display:inline-block;left:calc(50% + .3em);position:absolute;text-align:right}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{padding-left:2em;text-align:left}body{counter-reset:katexEqnNo mmlEqnNo}
|
|
|
|
|
|
static/vendor/katex/katex.min.js
DELETED
|
The diff for this file is too large to render.
See raw diff
|
|
|
static/vendor/marked/LICENSE
DELETED
|
@@ -1,60 +0,0 @@
|
|
| 1 |
-
# License information
|
| 2 |
-
|
| 3 |
-
## Contribution License Agreement
|
| 4 |
-
|
| 5 |
-
If you contribute code to this project, you are implicitly allowing your code
|
| 6 |
-
to be distributed under the MIT license. You are also implicitly verifying that
|
| 7 |
-
all code is your original work.
|
| 8 |
-
|
| 9 |
-
## Marked
|
| 10 |
-
|
| 11 |
-
Copyright (c) 2018+, MarkedJS (https://github.com/markedjs/)
|
| 12 |
-
Copyright (c) 2011-2018, Christopher Jeffrey (https://github.com/chjj/)
|
| 13 |
-
|
| 14 |
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 15 |
-
of this software and associated documentation files (the "Software"), to deal
|
| 16 |
-
in the Software without restriction, including without limitation the rights
|
| 17 |
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 18 |
-
copies of the Software, and to permit persons to whom the Software is
|
| 19 |
-
furnished to do so, subject to the following conditions:
|
| 20 |
-
|
| 21 |
-
The above copyright notice and this permission notice shall be included in
|
| 22 |
-
all copies or substantial portions of the Software.
|
| 23 |
-
|
| 24 |
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 25 |
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 26 |
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 27 |
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 28 |
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 29 |
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
| 30 |
-
THE SOFTWARE.
|
| 31 |
-
|
| 32 |
-
## Markdown
|
| 33 |
-
|
| 34 |
-
Copyright (c) 2004, John Gruber
|
| 35 |
-
http://daringfireball.net/
|
| 36 |
-
All rights reserved.
|
| 37 |
-
|
| 38 |
-
Redistribution and use in source and binary forms, with or without
|
| 39 |
-
modification, are permitted provided that the following conditions are met:
|
| 40 |
-
|
| 41 |
-
* Redistributions of source code must retain the above copyright notice,
|
| 42 |
-
this list of conditions and the following disclaimer.
|
| 43 |
-
* Redistributions in binary form must reproduce the above copyright notice,
|
| 44 |
-
this list of conditions and the following disclaimer in the documentation
|
| 45 |
-
and/or other materials provided with the distribution.
|
| 46 |
-
* Neither the name "Markdown" nor the names of its contributors may be used
|
| 47 |
-
to endorse or promote products derived from this software without specific
|
| 48 |
-
prior written permission.
|
| 49 |
-
|
| 50 |
-
This software is provided by the copyright holders and contributors "as is"
|
| 51 |
-
and any express or implied warranties, including, but not limited to, the
|
| 52 |
-
implied warranties of merchantability and fitness for a particular purpose
|
| 53 |
-
are disclaimed. In no event shall the copyright owner or contributors be
|
| 54 |
-
liable for any direct, indirect, incidental, special, exemplary, or
|
| 55 |
-
consequential damages (including, but not limited to, procurement of
|
| 56 |
-
substitute goods or services; loss of use, data, or profits; or business
|
| 57 |
-
interruption) however caused and on any theory of liability, whether in
|
| 58 |
-
contract, strict liability, or tort (including negligence or otherwise)
|
| 59 |
-
arising in any way out of the use of this software, even if advised of the
|
| 60 |
-
possibility of such damage.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/vendor/marked/marked.min.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
| 1 |
-
/**
|
| 2 |
-
* Minified by jsDelivr using Terser v5.37.0.
|
| 3 |
-
* Original file: /npm/marked@15.0.7/lib/marked.umd.js
|
| 4 |
-
*
|
| 5 |
-
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
| 6 |
-
*/
|
| 7 |
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).marked={})}(this,(function(e){"use strict";function t(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}function n(t){e.defaults=t}e.defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};const s={exec:()=>null};function r(e,t=""){let n="string"==typeof e?e:e.source;const s={replace:(e,t)=>{let r="string"==typeof t?t:t.source;return r=r.replace(i.caret,"$1"),n=n.replace(e,r),s},getRegex:()=>new RegExp(n,t)};return s}const i={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceTabs:/^\t+/,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] /,listReplaceTask:/^\[[ xX]\] +/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,unescapeTest:/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:e=>new RegExp(`^( {0,3}${e})((?:[\t ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),hrRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}#`),htmlBeginRegex:e=>new RegExp(`^ {0,${Math.min(3,e-1)}}<(?:[a-z].*>|!--)`,"i")},l=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,o=/(?:[*+-]|\d{1,9}[.)])/,a=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,c=r(a).replace(/bull/g,o).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),h=r(a).replace(/bull/g,o).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),p=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,u=/(?!\s*\])(?:\\.|[^\[\]\\])+/,g=r(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",u).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),k=r(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,o).getRegex(),d="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",f=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,x=r("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$))","i").replace("comment",f).replace("tag",d).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),b=r(p).replace("hr",l).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",d).getRegex(),w={blockquote:r(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",b).getRegex(),code:/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,def:g,fences:/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,hr:l,html:x,lheading:c,list:k,newline:/^(?:[ \t]*(?:\n|$))+/,paragraph:b,table:s,text:/^[^\n]+/},m=r("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",l).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3}\t)[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",d).getRegex(),y={...w,lheading:h,table:m,paragraph:r(p).replace("hr",l).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",m).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",d).getRegex()},$={...w,html:r("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",f).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:s,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:r(p).replace("hr",l).replace("heading"," *#{1,6} *[^\n]").replace("lheading",c).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},R=/^( {2,}|\\)\n(?!\s*$)/,S=/[\p{P}\p{S}]/u,T=/[\s\p{P}\p{S}]/u,z=/[^\s\p{P}\p{S}]/u,A=r(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,T).getRegex(),_=/(?!~)[\p{P}\p{S}]/u,P=/^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/,I=r(P,"u").replace(/punct/g,S).getRegex(),L=r(P,"u").replace(/punct/g,_).getRegex(),B="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",C=r(B,"gu").replace(/notPunctSpace/g,z).replace(/punctSpace/g,T).replace(/punct/g,S).getRegex(),q=r(B,"gu").replace(/notPunctSpace/g,/(?:[^\s\p{P}\p{S}]|~)/u).replace(/punctSpace/g,/(?!~)[\s\p{P}\p{S}]/u).replace(/punct/g,_).getRegex(),E=r("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,z).replace(/punctSpace/g,T).replace(/punct/g,S).getRegex(),Z=r(/\\(punct)/,"gu").replace(/punct/g,S).getRegex(),v=r(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),D=r(f).replace("(?:--\x3e|$)","--\x3e").getRegex(),M=r("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",D).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),O=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Q=r(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",O).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),j=r(/^!?\[(label)\]\[(ref)\]/).replace("label",O).replace("ref",u).getRegex(),N=r(/^!?\[(ref)\](?:\[\])?/).replace("ref",u).getRegex(),G={_backpedal:s,anyPunctuation:Z,autolink:v,blockSkip:/\[[^[\]]*?\]\((?:\\.|[^\\\(\)]|\((?:\\.|[^\\\(\)])*\))*\)|`[^`]*?`|<[^<>]*?>/g,br:R,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,del:s,emStrongLDelim:I,emStrongRDelimAst:C,emStrongRDelimUnd:E,escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,link:Q,nolink:N,punctuation:A,reflink:j,reflinkSearch:r("reflink|nolink(?!\\()","g").replace("reflink",j).replace("nolink",N).getRegex(),tag:M,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,url:s},H={...G,link:r(/^!?\[(label)\]\((.*?)\)/).replace("label",O).getRegex(),reflink:r(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",O).getRegex()},X={...G,emStrongRDelimAst:q,emStrongLDelim:L,url:r(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,"i").replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/},F={...X,br:r(R).replace("{2,}","*").getRegex(),text:r(X.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},U={normal:w,gfm:y,pedantic:$},J={normal:G,gfm:X,breaks:F,pedantic:H},K={"&":"&","<":"<",">":">",'"':""","'":"'"},V=e=>K[e];function W(e,t){if(t){if(i.escapeTest.test(e))return e.replace(i.escapeReplace,V)}else if(i.escapeTestNoEncode.test(e))return e.replace(i.escapeReplaceNoEncode,V);return e}function Y(e){try{e=encodeURI(e).replace(i.percentDecode,"%")}catch{return null}return e}function ee(e,t){const n=e.replace(i.findPipe,((e,t,n)=>{let s=!1,r=t;for(;--r>=0&&"\\"===n[r];)s=!s;return s?"|":" |"})).split(i.splitPipe);let s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),t)if(n.length>t)n.splice(t);else for(;n.length<t;)n.push("");for(;s<n.length;s++)n[s]=n[s].trim().replace(i.slashPipe,"|");return n}function te(e,t,n){const s=e.length;if(0===s)return"";let r=0;for(;r<s;){if(e.charAt(s-r-1)!==t)break;r++}return e.slice(0,s-r)}function ne(e,t,n,s,r){const i=t.href,l=t.title||null,o=e[1].replace(r.other.outputLinkReplace,"$1");if("!"!==e[0].charAt(0)){s.state.inLink=!0;const e={type:"link",raw:n,href:i,title:l,text:o,tokens:s.inlineTokens(o)};return s.state.inLink=!1,e}return{type:"image",raw:n,href:i,title:l,text:o}}class se{options;rules;lexer;constructor(t){this.options=t||e.defaults}space(e){const t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:te(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],n=function(e,t,n){const s=e.match(n.other.indentCodeCompensation);if(null===s)return t;const r=s[1];return t.split("\n").map((e=>{const t=e.match(n.other.beginningSpace);if(null===t)return e;const[s]=t;return s.length>=r.length?e.slice(r.length):e})).join("\n")}(e,t[3]||"",this.rules);return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:n}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(this.rules.other.endingHash.test(e)){const t=te(e,"#");this.options.pedantic?e=t.trim():t&&!this.rules.other.endingSpaceChar.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:te(t[0],"\n")}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){let e=te(t[0],"\n").split("\n"),n="",s="";const r=[];for(;e.length>0;){let t=!1;const i=[];let l;for(l=0;l<e.length;l++)if(this.rules.other.blockquoteStart.test(e[l]))i.push(e[l]),t=!0;else{if(t)break;i.push(e[l])}e=e.slice(l);const o=i.join("\n"),a=o.replace(this.rules.other.blockquoteSetextReplace,"\n $1").replace(this.rules.other.blockquoteSetextReplace2,"");n=n?`${n}\n${o}`:o,s=s?`${s}\n${a}`:a;const c=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(a,r,!0),this.lexer.state.top=c,0===e.length)break;const h=r.at(-1);if("code"===h?.type)break;if("blockquote"===h?.type){const t=h,i=t.raw+"\n"+e.join("\n"),l=this.blockquote(i);r[r.length-1]=l,n=n.substring(0,n.length-t.raw.length)+l.raw,s=s.substring(0,s.length-t.text.length)+l.text;break}if("list"!==h?.type);else{const t=h,i=t.raw+"\n"+e.join("\n"),l=this.list(i);r[r.length-1]=l,n=n.substring(0,n.length-h.raw.length)+l.raw,s=s.substring(0,s.length-t.raw.length)+l.raw,e=i.substring(r.at(-1).raw.length).split("\n")}}return{type:"blockquote",raw:n,tokens:r,text:s}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim();const s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");const i=this.rules.other.listItemRegex(n);let l=!1;for(;e;){let n=!1,s="",o="";if(!(t=i.exec(e)))break;if(this.rules.block.hr.test(e))break;s=t[0],e=e.substring(s.length);let a=t[2].split("\n",1)[0].replace(this.rules.other.listReplaceTabs,(e=>" ".repeat(3*e.length))),c=e.split("\n",1)[0],h=!a.trim(),p=0;if(this.options.pedantic?(p=2,o=a.trimStart()):h?p=t[1].length+1:(p=t[2].search(this.rules.other.nonSpaceChar),p=p>4?1:p,o=a.slice(p),p+=t[1].length),h&&this.rules.other.blankLine.test(c)&&(s+=c+"\n",e=e.substring(c.length+1),n=!0),!n){const t=this.rules.other.nextBulletRegex(p),n=this.rules.other.hrRegex(p),r=this.rules.other.fencesBeginRegex(p),i=this.rules.other.headingBeginRegex(p),l=this.rules.other.htmlBeginRegex(p);for(;e;){const u=e.split("\n",1)[0];let g;if(c=u,this.options.pedantic?(c=c.replace(this.rules.other.listReplaceNesting," "),g=c):g=c.replace(this.rules.other.tabCharGlobal," "),r.test(c))break;if(i.test(c))break;if(l.test(c))break;if(t.test(c))break;if(n.test(c))break;if(g.search(this.rules.other.nonSpaceChar)>=p||!c.trim())o+="\n"+g.slice(p);else{if(h)break;if(a.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4)break;if(r.test(a))break;if(i.test(a))break;if(n.test(a))break;o+="\n"+c}h||c.trim()||(h=!0),s+=u+"\n",e=e.substring(u.length+1),a=g.slice(p)}}r.loose||(l?r.loose=!0:this.rules.other.doubleBlankLine.test(s)&&(l=!0));let u,g=null;this.options.gfm&&(g=this.rules.other.listIsTask.exec(o),g&&(u="[ ] "!==g[0],o=o.replace(this.rules.other.listReplaceTask,""))),r.items.push({type:"list_item",raw:s,task:!!g,checked:u,loose:!1,text:o,tokens:[]}),r.raw+=s}const o=r.items.at(-1);if(!o)return;o.raw=o.raw.trimEnd(),o.text=o.text.trimEnd(),r.raw=r.raw.trimEnd();for(let e=0;e<r.items.length;e++)if(this.lexer.state.top=!1,r.items[e].tokens=this.lexer.blockTokens(r.items[e].text,[]),!r.loose){const t=r.items[e].tokens.filter((e=>"space"===e.type)),n=t.length>0&&t.some((e=>this.rules.other.anyLine.test(e.raw)));r.loose=n}if(r.loose)for(let e=0;e<r.items.length;e++)r.items[e].loose=!0;return r}}html(e){const t=this.rules.block.html.exec(e);if(t){return{type:"html",block:!0,raw:t[0],pre:"pre"===t[1]||"script"===t[1]||"style"===t[1],text:t[0]}}}def(e){const t=this.rules.block.def.exec(e);if(t){const e=t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),n=t[2]?t[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",s=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return{type:"def",tag:e,raw:t[0],href:n,title:s}}}table(e){const t=this.rules.block.table.exec(e);if(!t)return;if(!this.rules.other.tableDelimiter.test(t[2]))return;const n=ee(t[1]),s=t[2].replace(this.rules.other.tableAlignChars,"").split("|"),r=t[3]?.trim()?t[3].replace(this.rules.other.tableRowBlankLine,"").split("\n"):[],i={type:"table",raw:t[0],header:[],align:[],rows:[]};if(n.length===s.length){for(const e of s)this.rules.other.tableAlignRight.test(e)?i.align.push("right"):this.rules.other.tableAlignCenter.test(e)?i.align.push("center"):this.rules.other.tableAlignLeft.test(e)?i.align.push("left"):i.align.push(null);for(let e=0;e<n.length;e++)i.header.push({text:n[e],tokens:this.lexer.inline(n[e]),header:!0,align:i.align[e]});for(const e of r)i.rows.push(ee(e,i.header.length).map(((e,t)=>({text:e,tokens:this.lexer.inline(e),header:!1,align:i.align[t]}))));return i}}lheading(e){const t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:"="===t[2].charAt(0)?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){const t=this.rules.block.paragraph.exec(e);if(t){const e="\n"===t[1].charAt(t[1].length-1)?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:e,tokens:this.lexer.inline(e)}}}text(e){const t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){const t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:t[1]}}tag(e){const t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){const t=this.rules.inline.link.exec(e);if(t){const e=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(e)){if(!this.rules.other.endAngleBracket.test(e))return;const t=te(e.slice(0,-1),"\\");if((e.length-t.length)%2==0)return}else{const e=function(e,t){if(-1===e.indexOf(t[1]))return-1;let n=0;for(let s=0;s<e.length;s++)if("\\"===e[s])s++;else if(e[s]===t[0])n++;else if(e[s]===t[1]&&(n--,n<0))return s;return-1}(t[2],"()");if(e>-1){const n=(0===t[0].indexOf("!")?5:4)+t[1].length+e;t[2]=t[2].substring(0,e),t[0]=t[0].substring(0,n).trim(),t[3]=""}}let n=t[2],s="";if(this.options.pedantic){const e=this.rules.other.pedanticHrefTitle.exec(n);e&&(n=e[1],s=e[3])}else s=t[3]?t[3].slice(1,-1):"";return n=n.trim(),this.rules.other.startAngleBracket.test(n)&&(n=this.options.pedantic&&!this.rules.other.endAngleBracket.test(e)?n.slice(1):n.slice(1,-1)),ne(t,{href:n?n.replace(this.rules.inline.anyPunctuation,"$1"):n,title:s?s.replace(this.rules.inline.anyPunctuation,"$1"):s},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){const e=t[(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," ").toLowerCase()];if(!e){const e=n[0].charAt(0);return{type:"text",raw:e,text:e}}return ne(n,e,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s)return;if(s[3]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){const n=[...s[0]].length-1;let r,i,l=n,o=0;const a="*"===s[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(a.lastIndex=0,t=t.slice(-1*e.length+n);null!=(s=a.exec(t));){if(r=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!r)continue;if(i=[...r].length,s[3]||s[4]){l+=i;continue}if((s[5]||s[6])&&n%3&&!((n+i)%3)){o+=i;continue}if(l-=i,l>0)continue;i=Math.min(i,i+l+o);const t=[...s[0]][0].length,a=e.slice(0,n+s.index+t+i);if(Math.min(n,i)%2){const e=a.slice(1,-1);return{type:"em",raw:a,text:e,tokens:this.lexer.inlineTokens(e)}}const c=a.slice(2,-2);return{type:"strong",raw:a,text:c,tokens:this.lexer.inlineTokens(c)}}}}codespan(e){const t=this.rules.inline.code.exec(e);if(t){let e=t[2].replace(this.rules.other.newLineCharGlobal," ");const n=this.rules.other.nonSpaceChar.test(e),s=this.rules.other.startingSpaceChar.test(e)&&this.rules.other.endingSpaceChar.test(e);return n&&s&&(e=e.substring(1,e.length-1)),{type:"codespan",raw:t[0],text:e}}}br(e){const t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){const t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){const t=this.rules.inline.autolink.exec(e);if(t){let e,n;return"@"===t[2]?(e=t[1],n="mailto:"+e):(e=t[1],n=e),{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let e,n;if("@"===t[2])e=t[0],n="mailto:"+e;else{let s;do{s=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??""}while(s!==t[0]);e=t[0],n="www."===t[1]?"http://"+t[0]:t[0]}return{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(e){const t=this.rules.inline.text.exec(e);if(t){const e=this.lexer.state.inRawBlock;return{type:"text",raw:t[0],text:t[0],escaped:e}}}}class re{tokens;options;state;tokenizer;inlineQueue;constructor(t){this.tokens=[],this.tokens.links=Object.create(null),this.options=t||e.defaults,this.options.tokenizer=this.options.tokenizer||new se,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};const n={other:i,block:U.normal,inline:J.normal};this.options.pedantic?(n.block=U.pedantic,n.inline=J.pedantic):this.options.gfm&&(n.block=U.gfm,this.options.breaks?n.inline=J.breaks:n.inline=J.gfm),this.tokenizer.rules=n}static get rules(){return{block:U,inline:J}}static lex(e,t){return new re(t).lex(e)}static lexInline(e,t){return new re(t).inlineTokens(e)}lex(e){e=e.replace(i.carriageReturn,"\n"),this.blockTokens(e,this.tokens);for(let e=0;e<this.inlineQueue.length;e++){const t=this.inlineQueue[e];this.inlineTokens(t.src,t.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(e,t=[],n=!1){for(this.options.pedantic&&(e=e.replace(i.tabCharGlobal," ").replace(i.spaceLine,""));e;){let s;if(this.options.extensions?.block?.some((n=>!!(s=n.call({lexer:this},e,t))&&(e=e.substring(s.raw.length),t.push(s),!0))))continue;if(s=this.tokenizer.space(e)){e=e.substring(s.raw.length);const n=t.at(-1);1===s.raw.length&&void 0!==n?n.raw+="\n":t.push(s);continue}if(s=this.tokenizer.code(e)){e=e.substring(s.raw.length);const n=t.at(-1);"paragraph"===n?.type||"text"===n?.type?(n.raw+="\n"+s.raw,n.text+="\n"+s.text,this.inlineQueue.at(-1).src=n.text):t.push(s);continue}if(s=this.tokenizer.fences(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.heading(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.hr(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.blockquote(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.list(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.html(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.def(e)){e=e.substring(s.raw.length);const n=t.at(-1);"paragraph"===n?.type||"text"===n?.type?(n.raw+="\n"+s.raw,n.text+="\n"+s.raw,this.inlineQueue.at(-1).src=n.text):this.tokens.links[s.tag]||(this.tokens.links[s.tag]={href:s.href,title:s.title});continue}if(s=this.tokenizer.table(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.lheading(e)){e=e.substring(s.raw.length),t.push(s);continue}let r=e;if(this.options.extensions?.startBlock){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startBlock.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(this.state.top&&(s=this.tokenizer.paragraph(r))){const i=t.at(-1);n&&"paragraph"===i?.type?(i.raw+="\n"+s.raw,i.text+="\n"+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=i.text):t.push(s),n=r.length!==e.length,e=e.substring(s.raw.length)}else if(s=this.tokenizer.text(e)){e=e.substring(s.raw.length);const n=t.at(-1);"text"===n?.type?(n.raw+="\n"+s.raw,n.text+="\n"+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=n.text):t.push(s)}else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n=e,s=null;if(this.tokens.links){const e=Object.keys(this.tokens.links);if(e.length>0)for(;null!=(s=this.tokenizer.rules.inline.reflinkSearch.exec(n));)e.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(s=this.tokenizer.rules.inline.blockSkip.exec(n));)n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(s=this.tokenizer.rules.inline.anyPunctuation.exec(n));)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);let r=!1,i="";for(;e;){let s;if(r||(i=""),r=!1,this.options.extensions?.inline?.some((n=>!!(s=n.call({lexer:this},e,t))&&(e=e.substring(s.raw.length),t.push(s),!0))))continue;if(s=this.tokenizer.escape(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.tag(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.link(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(s.raw.length);const n=t.at(-1);"text"===s.type&&"text"===n?.type?(n.raw+=s.raw,n.text+=s.text):t.push(s);continue}if(s=this.tokenizer.emStrong(e,n,i)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.codespan(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.br(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.del(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.autolink(e)){e=e.substring(s.raw.length),t.push(s);continue}if(!this.state.inLink&&(s=this.tokenizer.url(e))){e=e.substring(s.raw.length),t.push(s);continue}let l=e;if(this.options.extensions?.startInline){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startInline.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(l=e.substring(0,t+1))}if(s=this.tokenizer.inlineText(l)){e=e.substring(s.raw.length),"_"!==s.raw.slice(-1)&&(i=s.raw.slice(-1)),r=!0;const n=t.at(-1);"text"===n?.type?(n.raw+=s.raw,n.text+=s.text):t.push(s)}else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return t}}class ie{options;parser;constructor(t){this.options=t||e.defaults}space(e){return""}code({text:e,lang:t,escaped:n}){const s=(t||"").match(i.notSpaceStart)?.[0],r=e.replace(i.endingNewline,"")+"\n";return s?'<pre><code class="language-'+W(s)+'">'+(n?r:W(r,!0))+"</code></pre>\n":"<pre><code>"+(n?r:W(r,!0))+"</code></pre>\n"}blockquote({tokens:e}){return`<blockquote>\n${this.parser.parse(e)}</blockquote>\n`}html({text:e}){return e}heading({tokens:e,depth:t}){return`<h${t}>${this.parser.parseInline(e)}</h${t}>\n`}hr(e){return"<hr>\n"}list(e){const t=e.ordered,n=e.start;let s="";for(let t=0;t<e.items.length;t++){const n=e.items[t];s+=this.listitem(n)}const r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+s+"</"+r+">\n"}listitem(e){let t="";if(e.task){const n=this.checkbox({checked:!!e.checked});e.loose?"paragraph"===e.tokens[0]?.type?(e.tokens[0].text=n+" "+e.tokens[0].text,e.tokens[0].tokens&&e.tokens[0].tokens.length>0&&"text"===e.tokens[0].tokens[0].type&&(e.tokens[0].tokens[0].text=n+" "+W(e.tokens[0].tokens[0].text),e.tokens[0].tokens[0].escaped=!0)):e.tokens.unshift({type:"text",raw:n+" ",text:n+" ",escaped:!0}):t+=n+" "}return t+=this.parser.parse(e.tokens,!!e.loose),`<li>${t}</li>\n`}checkbox({checked:e}){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox">'}paragraph({tokens:e}){return`<p>${this.parser.parseInline(e)}</p>\n`}table(e){let t="",n="";for(let t=0;t<e.header.length;t++)n+=this.tablecell(e.header[t]);t+=this.tablerow({text:n});let s="";for(let t=0;t<e.rows.length;t++){const r=e.rows[t];n="";for(let e=0;e<r.length;e++)n+=this.tablecell(r[e]);s+=this.tablerow({text:n})}return s&&(s=`<tbody>${s}</tbody>`),"<table>\n<thead>\n"+t+"</thead>\n"+s+"</table>\n"}tablerow({text:e}){return`<tr>\n${e}</tr>\n`}tablecell(e){const t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`</${n}>\n`}strong({tokens:e}){return`<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return`<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return`<code>${W(e,!0)}</code>`}br(e){return"<br>"}del({tokens:e}){return`<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){const s=this.parser.parseInline(n),r=Y(e);if(null===r)return s;let i='<a href="'+(e=r)+'"';return t&&(i+=' title="'+W(t)+'"'),i+=">"+s+"</a>",i}image({href:e,title:t,text:n}){const s=Y(e);if(null===s)return W(n);let r=`<img src="${e=s}" alt="${n}"`;return t&&(r+=` title="${W(t)}"`),r+=">",r}text(e){return"tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:W(e.text)}}class le{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return""+e}image({text:e}){return""+e}br(){return""}}class oe{options;renderer;textRenderer;constructor(t){this.options=t||e.defaults,this.options.renderer=this.options.renderer||new ie,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new le}static parse(e,t){return new oe(t).parse(e)}static parseInline(e,t){return new oe(t).parseInline(e)}parse(e,t=!0){let n="";for(let s=0;s<e.length;s++){const r=e[s];if(this.options.extensions?.renderers?.[r.type]){const e=r,t=this.options.extensions.renderers[e.type].call({parser:this},e);if(!1!==t||!["space","hr","heading","code","table","blockquote","list","html","paragraph","text"].includes(e.type)){n+=t||"";continue}}const i=r;switch(i.type){case"space":n+=this.renderer.space(i);continue;case"hr":n+=this.renderer.hr(i);continue;case"heading":n+=this.renderer.heading(i);continue;case"code":n+=this.renderer.code(i);continue;case"table":n+=this.renderer.table(i);continue;case"blockquote":n+=this.renderer.blockquote(i);continue;case"list":n+=this.renderer.list(i);continue;case"html":n+=this.renderer.html(i);continue;case"paragraph":n+=this.renderer.paragraph(i);continue;case"text":{let r=i,l=this.renderer.text(r);for(;s+1<e.length&&"text"===e[s+1].type;)r=e[++s],l+="\n"+this.renderer.text(r);n+=t?this.renderer.paragraph({type:"paragraph",raw:l,text:l,tokens:[{type:"text",raw:l,text:l,escaped:!0}]}):l;continue}default:{const e='Token with "'+i.type+'" type was not found.';if(this.options.silent)return console.error(e),"";throw new Error(e)}}}return n}parseInline(e,t=this.renderer){let n="";for(let s=0;s<e.length;s++){const r=e[s];if(this.options.extensions?.renderers?.[r.type]){const e=this.options.extensions.renderers[r.type].call({parser:this},r);if(!1!==e||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(r.type)){n+=e||"";continue}}const i=r;switch(i.type){case"escape":case"text":n+=t.text(i);break;case"html":n+=t.html(i);break;case"link":n+=t.link(i);break;case"image":n+=t.image(i);break;case"strong":n+=t.strong(i);break;case"em":n+=t.em(i);break;case"codespan":n+=t.codespan(i);break;case"br":n+=t.br(i);break;case"del":n+=t.del(i);break;default:{const e='Token with "'+i.type+'" type was not found.';if(this.options.silent)return console.error(e),"";throw new Error(e)}}}return n}}class ae{options;block;constructor(t){this.options=t||e.defaults}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}provideLexer(){return this.block?re.lex:re.lexInline}provideParser(){return this.block?oe.parse:oe.parseInline}}class ce{defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};options=this.setOptions;parse=this.parseMarkdown(!0);parseInline=this.parseMarkdown(!1);Parser=oe;Renderer=ie;TextRenderer=le;Lexer=re;Tokenizer=se;Hooks=ae;constructor(...e){this.use(...e)}walkTokens(e,t){let n=[];for(const s of e)switch(n=n.concat(t.call(this,s)),s.type){case"table":{const e=s;for(const s of e.header)n=n.concat(this.walkTokens(s.tokens,t));for(const s of e.rows)for(const e of s)n=n.concat(this.walkTokens(e.tokens,t));break}case"list":{const e=s;n=n.concat(this.walkTokens(e.items,t));break}default:{const e=s;this.defaults.extensions?.childTokens?.[e.type]?this.defaults.extensions.childTokens[e.type].forEach((s=>{const r=e[s].flat(1/0);n=n.concat(this.walkTokens(r,t))})):e.tokens&&(n=n.concat(this.walkTokens(e.tokens,t)))}}return n}use(...e){const t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach((e=>{const n={...e};if(n.async=this.defaults.async||n.async||!1,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if("renderer"in e){const n=t.renderers[e.name];t.renderers[e.name]=n?function(...t){let s=e.renderer.apply(this,t);return!1===s&&(s=n.apply(this,t)),s}:e.renderer}if("tokenizer"in e){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");const n=t[e.level];n?n.unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}"childTokens"in e&&e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),n.extensions=t),e.renderer){const t=this.defaults.renderer||new ie(this.defaults);for(const n in e.renderer){if(!(n in t))throw new Error(`renderer '${n}' does not exist`);if(["options","parser"].includes(n))continue;const s=n,r=e.renderer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n||""}}n.renderer=t}if(e.tokenizer){const t=this.defaults.tokenizer||new se(this.defaults);for(const n in e.tokenizer){if(!(n in t))throw new Error(`tokenizer '${n}' does not exist`);if(["options","rules","lexer"].includes(n))continue;const s=n,r=e.tokenizer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.tokenizer=t}if(e.hooks){const t=this.defaults.hooks||new ae;for(const n in e.hooks){if(!(n in t))throw new Error(`hook '${n}' does not exist`);if(["options","block"].includes(n))continue;const s=n,r=e.hooks[s],i=t[s];ae.passThroughHooks.has(n)?t[s]=e=>{if(this.defaults.async)return Promise.resolve(r.call(t,e)).then((e=>i.call(t,e)));const n=r.call(t,e);return i.call(t,n)}:t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.hooks=t}if(e.walkTokens){const t=this.defaults.walkTokens,s=e.walkTokens;n.walkTokens=function(e){let n=[];return n.push(s.call(this,e)),t&&(n=n.concat(t.call(this,e))),n}}this.defaults={...this.defaults,...n}})),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return re.lex(e,t??this.defaults)}parser(e,t){return oe.parse(e,t??this.defaults)}parseMarkdown(e){return(t,n)=>{const s={...n},r={...this.defaults,...s},i=this.onError(!!r.silent,!!r.async);if(!0===this.defaults.async&&!1===s.async)return i(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(null==t)return i(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof t)return i(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(t)+", string expected"));r.hooks&&(r.hooks.options=r,r.hooks.block=e);const l=r.hooks?r.hooks.provideLexer():e?re.lex:re.lexInline,o=r.hooks?r.hooks.provideParser():e?oe.parse:oe.parseInline;if(r.async)return Promise.resolve(r.hooks?r.hooks.preprocess(t):t).then((e=>l(e,r))).then((e=>r.hooks?r.hooks.processAllTokens(e):e)).then((e=>r.walkTokens?Promise.all(this.walkTokens(e,r.walkTokens)).then((()=>e)):e)).then((e=>o(e,r))).then((e=>r.hooks?r.hooks.postprocess(e):e)).catch(i);try{r.hooks&&(t=r.hooks.preprocess(t));let e=l(t,r);r.hooks&&(e=r.hooks.processAllTokens(e)),r.walkTokens&&this.walkTokens(e,r.walkTokens);let n=o(e,r);return r.hooks&&(n=r.hooks.postprocess(n)),n}catch(e){return i(e)}}}onError(e,t){return n=>{if(n.message+="\nPlease report this to https://github.com/markedjs/marked.",e){const e="<p>An error occurred:</p><pre>"+W(n.message+"",!0)+"</pre>";return t?Promise.resolve(e):e}if(t)return Promise.reject(n);throw n}}}const he=new ce;function pe(e,t){return he.parse(e,t)}pe.options=pe.setOptions=function(e){return he.setOptions(e),pe.defaults=he.defaults,n(pe.defaults),pe},pe.getDefaults=t,pe.defaults=e.defaults,pe.use=function(...e){return he.use(...e),pe.defaults=he.defaults,n(pe.defaults),pe},pe.walkTokens=function(e,t){return he.walkTokens(e,t)},pe.parseInline=he.parseInline,pe.Parser=oe,pe.parser=oe.parse,pe.Renderer=ie,pe.TextRenderer=le,pe.Lexer=re,pe.lexer=re.lex,pe.Tokenizer=se,pe.Hooks=ae,pe.parse=pe;const ue=pe.options,ge=pe.setOptions,ke=pe.use,de=pe.walkTokens,fe=pe.parseInline,xe=pe,be=oe.parse,we=re.lex;e.Hooks=ae,e.Lexer=re,e.Marked=ce,e.Parser=oe,e.Renderer=ie,e.TextRenderer=le,e.Tokenizer=se,e.getDefaults=t,e.lexer=we,e.marked=pe,e.options=ue,e.parse=xe,e.parseInline=fe,e.parser=be,e.setOptions=ge,e.use=ke,e.walkTokens=de}));
|
| 8 |
-
//# sourceMappingURL=/sm/77bc6b5397c95683db705e4167297ec0b2a93706a155641f348e5685060f3b6e.map
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|