From 45fedcd35927406d98e9640f6e29970515398f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=20=D0=91=D1=80=D0=B0=D1=82=D1=81?= =?UTF-8?q?=D0=BA=D0=B8=D1=85?= Date: Sun, 28 Jun 2026 14:40:24 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=82=D1=8D=D0=B3=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=D0=B0=20=D0=B2=20=D0=B1=D0=BE?= =?UTF-8?q?=D0=BA=D0=BE=D0=B2=D0=BE=D0=BC=20=D0=BC=D0=B5=D0=BD=D1=8E,=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D1=81=D0=B2=D0=B5=D1=82=D0=BA=D0=B0=20=D0=BD?= =?UTF-8?q?=D0=B0=D0=B9=D0=B4=D0=B5=D0=BD=D0=BD=D1=8B=D1=85=20=D1=8D=D0=BB?= =?UTF-8?q?=D0=B5=D0=BC=D0=B5=D0=BD=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 15 +++++++ script.js | 116 ++++++++++++++++++++++++++++++++++++++++++++--------- styles.css | 57 ++++++++++++++++++++++++-- 3 files changed, 165 insertions(+), 23 deletions(-) diff --git a/index.html b/index.html index 396f3c2..25fd258 100644 --- a/index.html +++ b/index.html @@ -48,6 +48,13 @@ +
@@ -95,6 +102,14 @@ + +
Акцент `; sectionNode.append(sectionSummary); @@ -414,7 +452,7 @@ function renderNavigationTree() { groupSummary.innerHTML = ` `; groupNode.append(groupSummary); @@ -427,7 +465,7 @@ function renderNavigationTree() { itemButton.type = "button"; itemButton.className = "tree-node tree-file"; itemButton.dataset.focusTarget = getItemId(item); - itemButton.innerHTML = `${item.title}${serviceMeta[item.type]?.label || item.type}`; + itemButton.innerHTML = `${highlightText(item.title, query)}${highlightText(item.tags.join(", "), query)}`; itemList.append(itemButton); }); @@ -528,10 +566,16 @@ function applyPreferences(nextPreferences) { document.documentElement.dataset.theme = nextPreferences.theme; document.documentElement.dataset.accent = nextPreferences.accent; + document.documentElement.style.setProperty( + "--sidebar-width", + `${clamp(Number(nextPreferences.sidebarWidth) || defaultPreferences.sidebarWidth, 260, 560)}px`, + ); catalog.classList.remove("cards-view", "list-view", "compact-cards-view", "compact-list-view"); catalog.classList.add(`${nextPreferences.view}-view`); document.documentElement.dataset.showNumbers = String(Boolean(nextPreferences.showNumbers)); + document.documentElement.dataset.showTreeTags = String(Boolean(nextPreferences.showTreeTags)); showNumbersInput.checked = Boolean(nextPreferences.showNumbers); + showTreeTagsInput.checked = Boolean(nextPreferences.showTreeTags); setActiveButton(themeButtons, "theme", nextPreferences.theme); setActiveButton(viewButtons, "view", nextPreferences.view); setActiveButton(accentButtons, "accent", nextPreferences.accent); @@ -549,6 +593,38 @@ function normalize(value) { return value.toLowerCase().replaceAll("ё", "е").trim(); } +function highlightText(value, query) { + const text = String(value); + const normalizedQuery = normalize(query); + + if (!normalizedQuery) { + return escapeHTML(text); + } + + const normalizedText = normalize(text); + let cursor = 0; + let result = ""; + let matchIndex = normalizedText.indexOf(normalizedQuery, cursor); + + while (matchIndex !== -1) { + result += escapeHTML(text.slice(cursor, matchIndex)); + result += `${escapeHTML(text.slice(matchIndex, matchIndex + normalizedQuery.length))}`; + cursor = matchIndex + normalizedQuery.length; + matchIndex = normalizedText.indexOf(normalizedQuery, cursor); + } + + return result + escapeHTML(text.slice(cursor)); +} + +function escapeHTML(value) { + return String(value) + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll('"', """) + .replaceAll("'", "'"); +} + function getSectionId(section) { return `section-${section.id}`; } diff --git a/styles.css b/styles.css index 7dcf7aa..bfa5f2f 100644 --- a/styles.css +++ b/styles.css @@ -14,6 +14,7 @@ --accent-rgb: 139, 92, 246; --card-x: 50%; --card-y: 50%; + --sidebar-width: 390px; } html[data-theme="light"] { @@ -109,11 +110,42 @@ a { .app-layout { display: grid; - grid-template-columns: minmax(320px, 390px) minmax(0, 1fr); - gap: 12px; + grid-template-columns: var(--sidebar-width) 8px minmax(0, 1fr); + gap: 8px; align-items: start; } +.sidebar-resizer { + position: sticky; + top: 20px; + width: 8px; + height: calc(100vh - 40px); + border-radius: 999px; + cursor: col-resize; + background: transparent; + transition: background 160ms ease; +} + +.sidebar-resizer::before { + content: ""; + display: block; + width: 2px; + height: 100%; + margin: 0 auto; + border-radius: inherit; + background: var(--border); +} + +.sidebar-resizer:hover::before, +body.is-resizing-sidebar .sidebar-resizer::before { + background: var(--accent); +} + +body.is-resizing-sidebar { + cursor: col-resize; + user-select: none; +} + .side-panel { position: sticky; top: 20px; @@ -187,6 +219,17 @@ html:not([data-show-numbers="true"]) .item-number { display: none; } +html[data-show-tree-tags="false"] .tree-node small { + display: none; +} + +.search-mark { + border-radius: 4px; + padding: 0 2px; + color: white; + background: linear-gradient(135deg, var(--accent), var(--accent-2)); +} + .control-panel { position: fixed; z-index: 1001; @@ -604,6 +647,10 @@ html:not([data-show-numbers="true"]) .item-number { } .tree-node small { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; color: var(--accent); font-size: 0.68rem; font-weight: 800; @@ -1024,7 +1071,7 @@ html:not([data-show-numbers="true"]) .item-number { @media (max-width: 1120px) { .app-layout { - grid-template-columns: minmax(240px, 300px) minmax(0, 1fr); + grid-template-columns: minmax(240px, min(var(--sidebar-width), 320px)) 8px minmax(0, 1fr); } .items-grid { @@ -1046,6 +1093,10 @@ html:not([data-show-numbers="true"]) .item-number { grid-template-columns: 1fr; } + .sidebar-resizer { + display: none; + } + .side-panel { position: static; }