Spaces:
Running
Running
v1.3
Browse files- index.html +246 -43
index.html
CHANGED
|
@@ -175,9 +175,7 @@
|
|
| 175 |
transition: background .12s;
|
| 176 |
}
|
| 177 |
.dropdown-item:hover { background: var(--bg4); }
|
| 178 |
-
.dropdown-item-dot {
|
| 179 |
-
width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;
|
| 180 |
-
}
|
| 181 |
.dropdown-item-name { font-weight: 600; color: var(--text); font-family: 'Bricolage Grotesque', sans-serif; }
|
| 182 |
.dropdown-item-detail { font-size: 10px; color: var(--text3); font-family: 'JetBrains Mono', monospace; margin-left: auto; white-space: nowrap; }
|
| 183 |
/* βββ Icon Toggle Buttons ββββββββββββββββββββββββββββββ */
|
|
@@ -189,6 +187,36 @@
|
|
| 189 |
.icon-toggle-btn:hover { border-color: var(--border2); color: var(--text); }
|
| 190 |
.icon-toggle-btn.active { border-color: var(--accent); color: var(--accent); background: rgba(77,158,245,.1); }
|
| 191 |
.icon-toggle-btn svg { width: 16px; height: 16px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
/* βββ Main Split βββββββββββββββββββββββββββββββββββββββ */
|
| 193 |
main {
|
| 194 |
flex: 1; min-height: 0; overflow: hidden;
|
|
@@ -418,22 +446,124 @@
|
|
| 418 |
/* βββ Animations βββββββββββββββββββββββββββββββββββββββ */
|
| 419 |
@keyframes fadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
|
| 420 |
.fade-in { animation: fadeIn .2s ease forwards; }
|
| 421 |
-
/* βββ Responsive ββββββββββββββββββββ
|
| 422 |
-
@media (max-width:
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
header {
|
| 430 |
-
.
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
.searchbar-group {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 437 |
}
|
| 438 |
</style>
|
| 439 |
</head>
|
|
@@ -446,14 +576,14 @@
|
|
| 446 |
<div class="logo">
|
| 447 |
<div class="logo-hex">T</div>
|
| 448 |
<span class="logo-name">TokenLens</span>
|
| 449 |
-
<span class="logo-tag">v1.
|
| 450 |
</div>
|
| 451 |
<div class="header-divider"></div>
|
| 452 |
<div class="header-controls">
|
| 453 |
<!-- Search bar A -->
|
| 454 |
<div class="searchbar-group" id="search-group-0">
|
| 455 |
<span class="searchbar-label label-a">A</span>
|
| 456 |
-
<input class="searchbar-input" id="search-input-0" type="text" placeholder="HF
|
| 457 |
<button class="searchbar-dropdown-btn" id="dropdown-btn-0" title="Predefined models">
|
| 458 |
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 3.5L5 6.5L8 3.5"/></svg>
|
| 459 |
</button>
|
|
@@ -463,7 +593,7 @@
|
|
| 463 |
<!-- Search bar B -->
|
| 464 |
<div class="searchbar-group" id="search-group-1">
|
| 465 |
<span class="searchbar-label label-b">B</span>
|
| 466 |
-
<input class="searchbar-input" id="search-input-1" type="text" placeholder="HF
|
| 467 |
<button class="searchbar-dropdown-btn" id="dropdown-btn-1" title="Predefined models">
|
| 468 |
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 3.5L5 6.5L8 3.5"/></svg>
|
| 469 |
</button>
|
|
@@ -481,10 +611,16 @@
|
|
| 481 |
</button>
|
| 482 |
</div>
|
| 483 |
</header>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 484 |
<!-- Main -->
|
| 485 |
<main id="main-grid">
|
| 486 |
<!-- Left: Input -->
|
| 487 |
-
<div class="input-panel">
|
| 488 |
<div class="panel-header">
|
| 489 |
<div class="panel-title">
|
| 490 |
<div class="panel-title-icon">β</div>
|
|
@@ -679,22 +815,27 @@ const panels = [
|
|
| 679 |
{ tokenizer: null, modelId: null, view: 'text' },
|
| 680 |
{ tokenizer: null, modelId: null, view: 'text' },
|
| 681 |
];
|
| 682 |
-
let tokenizerCache
|
| 683 |
-
let panel1Visible
|
| 684 |
-
let debounceTimer
|
|
|
|
| 685 |
|
| 686 |
// ββ DOM References βββββββββββββββββββββββββββββββββββββββββ
|
| 687 |
-
const $overlay
|
| 688 |
-
const $loadTitle
|
| 689 |
-
const $loadSub
|
| 690 |
-
const $loadBar
|
| 691 |
-
const $loadFile
|
| 692 |
-
const $input
|
| 693 |
-
const $charCount
|
| 694 |
-
const $toast
|
| 695 |
-
const $mainGrid
|
| 696 |
-
const $panelToggle
|
| 697 |
-
const $themeToggle
|
|
|
|
|
|
|
|
|
|
|
|
|
| 698 |
|
| 699 |
// ββ Utilities ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 700 |
function showOverlay(title, sub) {
|
|
@@ -751,6 +892,65 @@ function decodeTokenString(raw) {
|
|
| 751 |
return s;
|
| 752 |
}
|
| 753 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 754 |
// ββ Tokenize for a specific panel βββββββββββββββββββββββββ
|
| 755 |
async function tokenizeForPanel(idx, text) {
|
| 756 |
const p = panels[idx];
|
|
@@ -785,7 +985,7 @@ async function tokenizeForPanel(idx, text) {
|
|
| 785 |
// ββ Render Views βββββββββββββββββββββββββββββββββββββββββββ
|
| 786 |
function renderView(idx, tokens) {
|
| 787 |
const view = panels[idx].view;
|
| 788 |
-
if (view === 'text')
|
| 789 |
else if (view === 'ids') renderIdView(idx, tokens);
|
| 790 |
else if (view === 'list') renderListView(idx, tokens);
|
| 791 |
}
|
|
@@ -1012,17 +1212,17 @@ document.querySelectorAll('.sample-btn').forEach(btn => {
|
|
| 1012 |
$panelToggle.addEventListener('click', () => {
|
| 1013 |
panel1Visible = !panel1Visible;
|
| 1014 |
$panelToggle.classList.toggle('active', panel1Visible);
|
| 1015 |
-
|
|
|
|
|
|
|
| 1016 |
const $searchGroup1 = document.getElementById('search-group-1');
|
|
|
|
| 1017 |
if (panel1Visible) {
|
| 1018 |
-
$panel1.style.display = '';
|
| 1019 |
-
$searchGroup1.style.display = '';
|
| 1020 |
$mainGrid.classList.remove('single-panel');
|
| 1021 |
} else {
|
| 1022 |
-
$panel1.style.display = 'none';
|
| 1023 |
-
$searchGroup1.style.display = 'none';
|
| 1024 |
$mainGrid.classList.add('single-panel');
|
| 1025 |
}
|
|
|
|
| 1026 |
runTokenize();
|
| 1027 |
});
|
| 1028 |
|
|
@@ -1054,6 +1254,9 @@ buildDropdowns();
|
|
| 1054 |
|
| 1055 |
setTheme('dark');
|
| 1056 |
|
|
|
|
|
|
|
|
|
|
| 1057 |
document.getElementById('search-input-0').value = MODELS[0].id;
|
| 1058 |
loadModel(0, MODELS[0].id);
|
| 1059 |
</script>
|
|
|
|
| 175 |
transition: background .12s;
|
| 176 |
}
|
| 177 |
.dropdown-item:hover { background: var(--bg4); }
|
| 178 |
+
.dropdown-item-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
|
|
|
|
|
|
|
| 179 |
.dropdown-item-name { font-weight: 600; color: var(--text); font-family: 'Bricolage Grotesque', sans-serif; }
|
| 180 |
.dropdown-item-detail { font-size: 10px; color: var(--text3); font-family: 'JetBrains Mono', monospace; margin-left: auto; white-space: nowrap; }
|
| 181 |
/* βββ Icon Toggle Buttons ββββββββββββββββββββββββββββββ */
|
|
|
|
| 187 |
.icon-toggle-btn:hover { border-color: var(--border2); color: var(--text); }
|
| 188 |
.icon-toggle-btn.active { border-color: var(--accent); color: var(--accent); background: rgba(77,158,245,.1); }
|
| 189 |
.icon-toggle-btn svg { width: 16px; height: 16px; }
|
| 190 |
+
/* βββ Mobile Tab Bar βββββββββββββββββββββββββββββββββββ */
|
| 191 |
+
.mobile-tab-bar {
|
| 192 |
+
display: none;
|
| 193 |
+
border-bottom: 1px solid var(--border);
|
| 194 |
+
flex-shrink: 0;
|
| 195 |
+
background: var(--bg2);
|
| 196 |
+
padding: 0 4px;
|
| 197 |
+
}
|
| 198 |
+
.mobile-tab {
|
| 199 |
+
flex: 1;
|
| 200 |
+
padding: 10px 4px;
|
| 201 |
+
border: none;
|
| 202 |
+
background: transparent;
|
| 203 |
+
color: var(--text2);
|
| 204 |
+
font-family: 'DM Sans', sans-serif;
|
| 205 |
+
font-size: 12px;
|
| 206 |
+
font-weight: 500;
|
| 207 |
+
cursor: pointer;
|
| 208 |
+
border-bottom: 2px solid transparent;
|
| 209 |
+
transition: all .15s;
|
| 210 |
+
text-align: center;
|
| 211 |
+
}
|
| 212 |
+
.mobile-tab.active {
|
| 213 |
+
color: var(--accent);
|
| 214 |
+
border-bottom-color: var(--accent);
|
| 215 |
+
}
|
| 216 |
+
.mobile-tab.tab-disabled {
|
| 217 |
+
opacity: 0.3;
|
| 218 |
+
pointer-events: none;
|
| 219 |
+
}
|
| 220 |
/* βββ Main Split βββββββββββββββββββββββββββββββββββββββ */
|
| 221 |
main {
|
| 222 |
flex: 1; min-height: 0; overflow: hidden;
|
|
|
|
| 446 |
/* βββ Animations βββββββββββββββββββββββββββββββββββββββ */
|
| 447 |
@keyframes fadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
|
| 448 |
.fade-in { animation: fadeIn .2s ease forwards; }
|
| 449 |
+
/* βββ Responsive: Tablet (600β900px) ββββββββββββββββββββ */
|
| 450 |
+
@media (min-width: 601px) and (max-width: 900px) {
|
| 451 |
+
header {
|
| 452 |
+
flex-wrap: wrap;
|
| 453 |
+
height: auto;
|
| 454 |
+
padding: 8px 12px;
|
| 455 |
+
gap: 8px;
|
| 456 |
+
}
|
| 457 |
+
.header-divider { display: none; }
|
| 458 |
+
.header-controls {
|
| 459 |
+
flex-basis: 100%;
|
| 460 |
+
display: flex;
|
| 461 |
+
flex-wrap: wrap;
|
| 462 |
+
gap: 8px;
|
| 463 |
+
}
|
| 464 |
+
.searchbar-group {
|
| 465 |
+
flex: 1 1 180px;
|
| 466 |
+
}
|
| 467 |
+
main {
|
| 468 |
+
grid-template-columns: 1fr;
|
| 469 |
+
grid-template-rows: auto 1fr 1fr;
|
| 470 |
+
}
|
| 471 |
+
main.single-panel {
|
| 472 |
+
grid-template-columns: 1fr;
|
| 473 |
+
grid-template-rows: auto 1fr;
|
| 474 |
+
}
|
| 475 |
+
.input-panel {
|
| 476 |
+
border-right: none;
|
| 477 |
+
border-bottom: 1px solid var(--border);
|
| 478 |
+
max-height: 25vh;
|
| 479 |
+
}
|
| 480 |
+
.output-panel {
|
| 481 |
+
border-left: none !important;
|
| 482 |
+
border-bottom: 1px solid var(--border);
|
| 483 |
+
}
|
| 484 |
+
.output-panel:last-child {
|
| 485 |
+
border-bottom: none;
|
| 486 |
+
}
|
| 487 |
+
.stat-card { padding: 7px 10px; }
|
| 488 |
+
.stat-value { font-size: 17px; }
|
| 489 |
+
.stat-sub { font-size: 8px; }
|
| 490 |
+
.stat-label { font-size: 8px; }
|
| 491 |
+
.output-panel-header { padding: 8px 10px; }
|
| 492 |
+
.view-toggle { padding: 6px 10px; }
|
| 493 |
+
}
|
| 494 |
+
/* βββ Responsive: Mobile (β€600px) ββββββββββββββββββββββ */
|
| 495 |
+
@media (max-width: 600px) {
|
| 496 |
+
header {
|
| 497 |
+
flex-wrap: wrap;
|
| 498 |
+
height: auto;
|
| 499 |
+
padding: 6px 10px;
|
| 500 |
+
gap: 6px;
|
| 501 |
+
}
|
| 502 |
+
.header-divider { display: none; }
|
| 503 |
+
.logo-tag { display: none; }
|
| 504 |
+
.header-controls {
|
| 505 |
+
flex-basis: 100%;
|
| 506 |
+
display: flex;
|
| 507 |
+
flex-wrap: wrap;
|
| 508 |
+
gap: 6px;
|
| 509 |
+
}
|
| 510 |
+
.searchbar-group {
|
| 511 |
+
flex: 1 1 100%;
|
| 512 |
+
}
|
| 513 |
+
.searchbar-label { display: none; }
|
| 514 |
+
.dropdown-menu {
|
| 515 |
+
left: 0 !important;
|
| 516 |
+
right: 0 !important;
|
| 517 |
+
min-width: unset;
|
| 518 |
+
}
|
| 519 |
+
.mobile-tab-bar {
|
| 520 |
+
display: flex;
|
| 521 |
+
}
|
| 522 |
+
main {
|
| 523 |
+
grid-template-columns: 1fr;
|
| 524 |
+
grid-template-rows: 1fr;
|
| 525 |
+
}
|
| 526 |
+
.input-panel,
|
| 527 |
+
.output-panel {
|
| 528 |
+
display: none;
|
| 529 |
+
}
|
| 530 |
+
.mobile-active {
|
| 531 |
+
display: flex !important;
|
| 532 |
+
}
|
| 533 |
+
.input-panel {
|
| 534 |
+
border-right: none;
|
| 535 |
+
border-bottom: none;
|
| 536 |
+
max-height: none;
|
| 537 |
+
}
|
| 538 |
+
.output-panel {
|
| 539 |
+
border-left: none !important;
|
| 540 |
+
border-bottom: none;
|
| 541 |
+
}
|
| 542 |
+
.panel-header {
|
| 543 |
+
flex-wrap: wrap;
|
| 544 |
+
gap: 6px;
|
| 545 |
+
padding: 10px 12px 8px;
|
| 546 |
+
}
|
| 547 |
+
.sample-btns { width: 100%; }
|
| 548 |
+
.sample-btn { font-size: 9px; padding: 3px 6px; }
|
| 549 |
+
.output-panel-header { padding: 6px 10px; }
|
| 550 |
+
.model-indicator { font-size: 10px; }
|
| 551 |
+
.stat-card { padding: 5px 8px; }
|
| 552 |
+
.stat-value { font-size: 16px; }
|
| 553 |
+
.stat-label { font-size: 7px; letter-spacing: .5px; margin-bottom: 2px; }
|
| 554 |
+
.stat-sub { font-size: 7px; }
|
| 555 |
+
.view-toggle { padding: 5px 10px; }
|
| 556 |
+
.toggle-btn { padding: 3px 8px; font-size: 10px; }
|
| 557 |
+
.token-display { padding: 10px; }
|
| 558 |
+
.token-text-view { font-size: 12px; line-height: 2; }
|
| 559 |
+
.tok-split-idx { width: 28px; font-size: 8px; }
|
| 560 |
+
.tok-split-text { font-size: 11px; }
|
| 561 |
+
.tok-split-id { font-size: 9px; }
|
| 562 |
+
footer {
|
| 563 |
+
padding: 6px 12px;
|
| 564 |
+
font-size: 9px;
|
| 565 |
+
}
|
| 566 |
+
footer span:last-child { display: none; }
|
| 567 |
}
|
| 568 |
</style>
|
| 569 |
</head>
|
|
|
|
| 576 |
<div class="logo">
|
| 577 |
<div class="logo-hex">T</div>
|
| 578 |
<span class="logo-name">TokenLens</span>
|
| 579 |
+
<span class="logo-tag">v1.3</span>
|
| 580 |
</div>
|
| 581 |
<div class="header-divider"></div>
|
| 582 |
<div class="header-controls">
|
| 583 |
<!-- Search bar A -->
|
| 584 |
<div class="searchbar-group" id="search-group-0">
|
| 585 |
<span class="searchbar-label label-a">A</span>
|
| 586 |
+
<input class="searchbar-input" id="search-input-0" type="text" placeholder="Model A: HF repo idβ¦" />
|
| 587 |
<button class="searchbar-dropdown-btn" id="dropdown-btn-0" title="Predefined models">
|
| 588 |
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 3.5L5 6.5L8 3.5"/></svg>
|
| 589 |
</button>
|
|
|
|
| 593 |
<!-- Search bar B -->
|
| 594 |
<div class="searchbar-group" id="search-group-1">
|
| 595 |
<span class="searchbar-label label-b">B</span>
|
| 596 |
+
<input class="searchbar-input" id="search-input-1" type="text" placeholder="Model B: HF repo idβ¦" />
|
| 597 |
<button class="searchbar-dropdown-btn" id="dropdown-btn-1" title="Predefined models">
|
| 598 |
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 3.5L5 6.5L8 3.5"/></svg>
|
| 599 |
</button>
|
|
|
|
| 611 |
</button>
|
| 612 |
</div>
|
| 613 |
</header>
|
| 614 |
+
<!-- Mobile Tab Bar -->
|
| 615 |
+
<div class="mobile-tab-bar" id="mobile-tab-bar">
|
| 616 |
+
<button class="mobile-tab active" data-tab="input">Input</button>
|
| 617 |
+
<button class="mobile-tab" data-tab="panel-0">Model A</button>
|
| 618 |
+
<button class="mobile-tab" data-tab="panel-1">Model B</button>
|
| 619 |
+
</div>
|
| 620 |
<!-- Main -->
|
| 621 |
<main id="main-grid">
|
| 622 |
<!-- Left: Input -->
|
| 623 |
+
<div class="input-panel mobile-active" id="input-panel">
|
| 624 |
<div class="panel-header">
|
| 625 |
<div class="panel-title">
|
| 626 |
<div class="panel-title-icon">β</div>
|
|
|
|
| 815 |
{ tokenizer: null, modelId: null, view: 'text' },
|
| 816 |
{ tokenizer: null, modelId: null, view: 'text' },
|
| 817 |
];
|
| 818 |
+
let tokenizerCache = {};
|
| 819 |
+
let panel1Visible = true;
|
| 820 |
+
let debounceTimer = null;
|
| 821 |
+
let mobileActiveTab = 'input';
|
| 822 |
|
| 823 |
// ββ DOM References βββββββββββββββββββββββββββββββββββββββββ
|
| 824 |
+
const $overlay = document.getElementById('loading-overlay');
|
| 825 |
+
const $loadTitle = document.getElementById('loading-title');
|
| 826 |
+
const $loadSub = document.getElementById('loading-sub');
|
| 827 |
+
const $loadBar = document.getElementById('loading-bar');
|
| 828 |
+
const $loadFile = document.getElementById('loading-file');
|
| 829 |
+
const $input = document.getElementById('input-area');
|
| 830 |
+
const $charCount = document.getElementById('char-count');
|
| 831 |
+
const $toast = document.getElementById('toast');
|
| 832 |
+
const $mainGrid = document.getElementById('main-grid');
|
| 833 |
+
const $panelToggle = document.getElementById('panel-toggle');
|
| 834 |
+
const $themeToggle = document.getElementById('theme-toggle');
|
| 835 |
+
const $inputPanel = document.getElementById('input-panel');
|
| 836 |
+
const $panel0 = document.getElementById('panel-0');
|
| 837 |
+
const $panel1 = document.getElementById('panel-1');
|
| 838 |
+
const $mobileTabs = document.querySelectorAll('.mobile-tab');
|
| 839 |
|
| 840 |
// ββ Utilities ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 841 |
function showOverlay(title, sub) {
|
|
|
|
| 892 |
return s;
|
| 893 |
}
|
| 894 |
|
| 895 |
+
// ββ Mobile Tab Handling ββββββββββββββββββββββββββββββββββββ
|
| 896 |
+
function isMobile() { return window.innerWidth <= 600; }
|
| 897 |
+
|
| 898 |
+
function applyMobileTab(tabId) {
|
| 899 |
+
mobileActiveTab = tabId;
|
| 900 |
+
$mobileTabs.forEach(t => t.classList.toggle('active', t.dataset.tab === tabId));
|
| 901 |
+
// Remove mobile-active from all panels
|
| 902 |
+
$inputPanel.classList.remove('mobile-active');
|
| 903 |
+
$panel0.classList.remove('mobile-active');
|
| 904 |
+
$panel1.classList.remove('mobile-active');
|
| 905 |
+
// Add to the target
|
| 906 |
+
if (tabId === 'input') $inputPanel.classList.add('mobile-active');
|
| 907 |
+
if (tabId === 'panel-0') $panel0.classList.add('mobile-active');
|
| 908 |
+
if (tabId === 'panel-1') $panel1.classList.add('mobile-active');
|
| 909 |
+
}
|
| 910 |
+
|
| 911 |
+
$mobileTabs.forEach(tab => {
|
| 912 |
+
tab.addEventListener('click', () => {
|
| 913 |
+
applyMobileTab(tab.dataset.tab);
|
| 914 |
+
});
|
| 915 |
+
});
|
| 916 |
+
|
| 917 |
+
// Handle resize: reset display properties when switching between mobile/desktop
|
| 918 |
+
function handleResize() {
|
| 919 |
+
if (!isMobile()) {
|
| 920 |
+
// Desktop/tablet: remove mobile-active, reset display for all panels
|
| 921 |
+
$inputPanel.classList.remove('mobile-active');
|
| 922 |
+
$panel0.classList.remove('mobile-active');
|
| 923 |
+
$panel1.classList.remove('mobile-active');
|
| 924 |
+
$inputPanel.style.display = '';
|
| 925 |
+
$panel0.style.display = '';
|
| 926 |
+
$panel1.style.display = panel1Visible ? '' : 'none';
|
| 927 |
+
} else {
|
| 928 |
+
// Mobile: apply mobile tab logic
|
| 929 |
+
$inputPanel.style.display = '';
|
| 930 |
+
$panel0.style.display = '';
|
| 931 |
+
$panel1.style.display = '';
|
| 932 |
+
applyMobileTab(mobileActiveTab);
|
| 933 |
+
}
|
| 934 |
+
updateMobileTabBState();
|
| 935 |
+
}
|
| 936 |
+
|
| 937 |
+
function updateMobileTabBState() {
|
| 938 |
+
const $tabB = document.querySelector('.mobile-tab[data-tab="panel-1"]');
|
| 939 |
+
if ($tabB) {
|
| 940 |
+
if (panel1Visible) {
|
| 941 |
+
$tabB.classList.remove('tab-disabled');
|
| 942 |
+
} else {
|
| 943 |
+
$tabB.classList.add('tab-disabled');
|
| 944 |
+
// If currently on tab B, switch away
|
| 945 |
+
if (mobileActiveTab === 'panel-1') {
|
| 946 |
+
applyMobileTab('panel-0');
|
| 947 |
+
}
|
| 948 |
+
}
|
| 949 |
+
}
|
| 950 |
+
}
|
| 951 |
+
|
| 952 |
+
window.addEventListener('resize', handleResize);
|
| 953 |
+
|
| 954 |
// ββ Tokenize for a specific panel βββββββββββββββββββββββββ
|
| 955 |
async function tokenizeForPanel(idx, text) {
|
| 956 |
const p = panels[idx];
|
|
|
|
| 985 |
// ββ Render Views βββββββββββββββββββββββββββββββββββββββββββ
|
| 986 |
function renderView(idx, tokens) {
|
| 987 |
const view = panels[idx].view;
|
| 988 |
+
if (view === 'text') renderTextView(idx, tokens);
|
| 989 |
else if (view === 'ids') renderIdView(idx, tokens);
|
| 990 |
else if (view === 'list') renderListView(idx, tokens);
|
| 991 |
}
|
|
|
|
| 1212 |
$panelToggle.addEventListener('click', () => {
|
| 1213 |
panel1Visible = !panel1Visible;
|
| 1214 |
$panelToggle.classList.toggle('active', panel1Visible);
|
| 1215 |
+
if (!isMobile()) {
|
| 1216 |
+
$panel1.style.display = panel1Visible ? '' : 'none';
|
| 1217 |
+
}
|
| 1218 |
const $searchGroup1 = document.getElementById('search-group-1');
|
| 1219 |
+
$searchGroup1.style.display = panel1Visible ? '' : 'none';
|
| 1220 |
if (panel1Visible) {
|
|
|
|
|
|
|
| 1221 |
$mainGrid.classList.remove('single-panel');
|
| 1222 |
} else {
|
|
|
|
|
|
|
| 1223 |
$mainGrid.classList.add('single-panel');
|
| 1224 |
}
|
| 1225 |
+
updateMobileTabBState();
|
| 1226 |
runTokenize();
|
| 1227 |
});
|
| 1228 |
|
|
|
|
| 1254 |
|
| 1255 |
setTheme('dark');
|
| 1256 |
|
| 1257 |
+
// Set initial mobile state
|
| 1258 |
+
handleResize();
|
| 1259 |
+
|
| 1260 |
document.getElementById('search-input-0').value = MODELS[0].id;
|
| 1261 |
loadModel(0, MODELS[0].id);
|
| 1262 |
</script>
|