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; }