diff --git a/config.toml b/config.toml index 15f9fb97..0f41161e 100644 --- a/config.toml +++ b/config.toml @@ -2,7 +2,10 @@ baseURL = 'https://hive.apache.org' languageCode = 'en-us' title = 'Hive Site' theme = 'hive' + +# Site version for cache busting [params] + version = "1.1.0" hiveLogo = "/images/hive.svg" logo = "/images/asf_logo.png" apacheURL = 'https://www.apache.org' diff --git a/themes/hive/layouts/_default/index.json b/themes/hive/layouts/_default/index.json index 91f95c90..f8a7700e 100644 --- a/themes/hive/layouts/_default/index.json +++ b/themes/hive/layouts/_default/index.json @@ -3,14 +3,17 @@ {{- $sc := newScratch -}} {{- if isset .Params "description" -}} {{- $sc.Add "ct" .Description -}} +{{- $sc.Add "ct" ". " -}} {{- end -}} {{- if isset .Params "about" -}} {{- range .Params.About.about_item }} -{{- $sc.Add "ct" (print .title " " .subtitle " " .content) -}} +{{- $sc.Add "ct" (print .title " " .subtitle " " .content " ") -}} {{- end -}} {{- end -}} -{{- $sc.Add "ct" .Plain -}} +{{- $plainContent := .Plain -}} +{{- $plainContent = replaceRE "\\s{2,}" " " $plainContent -}} +{{- $sc.Add "ct" $plainContent -}} {{- $content := $sc.Get "ct" }} {{ $date:= .PublishDate.Format "02"}} diff --git a/themes/hive/layouts/_default/search.html b/themes/hive/layouts/_default/search.html index d9119472..2d0ce02a 100644 --- a/themes/hive/layouts/_default/search.html +++ b/themes/hive/layouts/_default/search.html @@ -1,19 +1,23 @@ {{ define "main" }} -
-
-
Loading...
+
+
+
+

Search Results

+ +
+
+
diff --git a/themes/hive/layouts/partials/footer.html b/themes/hive/layouts/partials/footer.html index 2c05848c..fa10c6fc 100644 --- a/themes/hive/layouts/partials/footer.html +++ b/themes/hive/layouts/partials/footer.html @@ -52,4 +52,5 @@ - + + diff --git a/themes/hive/layouts/partials/head.html b/themes/hive/layouts/partials/head.html index 613e870d..c0e39703 100644 --- a/themes/hive/layouts/partials/head.html +++ b/themes/hive/layouts/partials/head.html @@ -24,12 +24,17 @@ + + + + {{ .Title }} - - - - + + + + + diff --git a/themes/hive/static/css/hive-theme.css b/themes/hive/static/css/hive-theme.css index 06c70f5e..0a718045 100644 --- a/themes/hive/static/css/hive-theme.css +++ b/themes/hive/static/css/hive-theme.css @@ -302,7 +302,7 @@ features { .search-button { border: none; - background: #17a2b8; + background: #007bff; color: #ffffff; padding: 0.5rem 0.75rem; cursor: pointer; @@ -310,7 +310,7 @@ features { } .search-button:hover { - background: #138496; + background: #0056b3; } .search-button i { @@ -2704,3 +2704,181 @@ features.container { } + +/* ====================================== + SEARCH RESULTS PAGE STYLES + ====================================== */ + +.search-page { + max-width: 1400px; + margin: 0 auto; + padding: 2rem 3rem; + min-height: 60vh; +} + +.search-results-header { + margin-bottom: 2.5rem; +} + +.search-results-header h1 { + font-size: 2.5rem; + font-weight: 600; + color: #1a202c; + margin: 0 0 1rem 0; +} + +.search-loading { + color: #206cd6; + font-size: 1rem; + padding: 1rem 0; + display: flex; + align-items: center; + gap: 0.75rem; +} + +.search-loading i { + font-size: 1.2rem; +} + +/* Search Results Empty State */ +.search-results-empty { + text-align: center; + padding: 3rem 2rem; + color: #6b7280; +} + +.search-results-empty i { + font-size: 3rem; + color: #cbd5e0; + margin-bottom: 1rem; +} + +/* Individual Search Result Item */ +.search-result-item { + background: white; + border: 1px solid #e2e8f0; + border-radius: 12px; + padding: 2rem 2.5rem; + margin-bottom: 2rem; + transition: all 0.3s ease; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); +} + +.search-result-item:hover { + border-color: #206cd6; + box-shadow: 0 8px 20px rgba(32, 108, 214, 0.12); + transform: translateY(-3px); +} + +.search-result-title { + font-size: 1.75rem; + font-weight: 600; + margin: 0 0 1rem 0; +} + +.search-result-title a { + color: #206cd6; + text-decoration: none; + transition: color 0.2s ease; +} + +.search-result-title a:hover { + color: #1a5ba8; + text-decoration: underline; +} + +.search-result-snippet { + color: #4a5568; + font-size: 1.05rem; + line-height: 1.7; + margin: 0 0 1.25rem 0; +} + +/* Highlight matched terms */ +.search-result-snippet mark { + background: #fef3c7; + color: #92400e; + padding: 0.1rem 0.2rem; + border-radius: 3px; + font-weight: 600; +} + +.search-result-meta { + display: flex; + align-items: center; + gap: 1rem; + flex-wrap: wrap; + font-size: 0.85rem; + color: #6b7280; +} + +.search-result-link { + color: #10b981; + font-family: 'Monaco', 'Courier New', monospace; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 400px; +} + +.search-result-tags { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.search-result-tags i { + color: #9ca3af; +} + +.search-result-tags a { + color: #206cd6; + text-decoration: none; + padding: 0.25rem 0.5rem; + background: #eff6ff; + border-radius: 4px; + transition: all 0.2s ease; +} + +.search-result-tags a:hover { + background: #dbeafe; + color: #1a5ba8; +} + +/* Search Result Count */ +.search-results-count { + padding: 1rem 0; + color: #6b7280; + font-size: 0.95rem; + margin-bottom: 1rem; + border-bottom: 1px solid #e2e8f0; +} + +/* Mobile Responsive */ +@media (max-width: 768px) { + .search-page { + padding: 1rem; + } + + .search-results-header h1 { + font-size: 1.75rem; + } + + .search-result-item { + padding: 1.25rem; + } + + .search-result-title { + font-size: 1.25rem; + } + + .search-result-link { + max-width: 200px; + } + + .search-result-meta { + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + } +} diff --git a/themes/hive/static/js/search.js b/themes/hive/static/js/search.js index 6d1595df..f14e3ca8 100644 --- a/themes/hive/static/js/search.js +++ b/themes/hive/static/js/search.js @@ -3,10 +3,13 @@ var fuseOptions = { shouldSort: true, includeMatches: true, includeScore: true, - tokenize: true, + threshold: 0.2, // Stricter matching - lower value = more exact matches required location: 0, - distance: 100, + distance: 1000, // Increased from 100 to search entire content minMatchCharLength: 1, + ignoreLocation: true, // Search entire string, not just near location + isCaseSensitive: false, // Case-insensitive search + findAllMatches: true, // Find all matching items keys: [ {name: "title", weight: 0.45}, {name: "contents", weight: 0.4}, @@ -70,23 +73,92 @@ function populateResults(results) { var snippet = ""; var snippetHighlights = []; + // Add both the full query and individual terms for highlighting snippetHighlights.push(searchQuery); - snippet = contents.substring(0, summaryInclude * 2) + '…'; - - //replace values - var tags = "" - if (value.item.tags) { - value.item.tags.forEach(function (element) { - tags = tags + "" + "#" + element + " " - }); + + // Find the best matching snippet - search for where query terms actually appear + var matchIndex = -1; + var bestSnippet = ""; + + // Split search query into words and find where they appear together + var searchTerms = searchQuery.toLowerCase().split(/\s+/).filter(function(term) { + return term.length > 2; // Ignore short words + }); + + // Add individual terms to highlights + searchTerms.forEach(function(term) { + snippetHighlights.push(term); + }); + + if (searchTerms.length > 0) { + var contentsLower = contents.toLowerCase(); + var bestScore = -1; + var bestPosition = -1; + + // Find the position where search terms are closest together + for (var i = 0; i < contents.length - 100; i += 50) { + var windowEnd = Math.min(i + 400, contents.length); + var window = contentsLower.substring(i, windowEnd); + var score = 0; + var foundTerms = 0; + + searchTerms.forEach(function(term) { + var termIndex = window.indexOf(term); + if (termIndex >= 0) { + foundTerms++; + // Prefer matches closer to the start of the window + score += (200 - termIndex); + } + }); + + // Boost score if multiple terms found in this window + score *= foundTerms; + + if (score > bestScore && foundTerms > 0) { + bestScore = score; + bestPosition = i; + } + } + + if (bestPosition >= 0) { + matchIndex = bestPosition; + + // Extract snippet centered on this position + var start = Math.max(0, matchIndex - summaryInclude / 2); + var end = Math.min(contents.length, matchIndex + summaryInclude * 1.5); + + // Try to find sentence boundaries + var sentenceStart = contents.lastIndexOf('. ', matchIndex); + if (sentenceStart > start && sentenceStart < matchIndex && (matchIndex - sentenceStart) < 100) { + start = sentenceStart + 2; + } + + var sentenceEnd = contents.indexOf('. ', end - 50); + if (sentenceEnd > matchIndex && sentenceEnd <= end && (sentenceEnd - matchIndex) < 200) { + end = sentenceEnd + 1; + } + + bestSnippet = contents.substring(start, end).trim(); + + // Add ellipsis + var needsStartEllipsis = start > 0; + var needsEndEllipsis = end < contents.length; + snippet = (needsStartEllipsis ? '… ' : '') + + bestSnippet + + (needsEndEllipsis ? ' …' : ''); + } + } + + // Fallback if no match found + if (!snippet) { + snippet = contents.substring(0, summaryInclude * 2).trim() + '…'; } + //replace values var output = render(templateDefinition, { key: key, title: value.item.title, link: value.item.permalink, - tags: tags, - categories: value.item.categories, snippet: snippet }); searchResults.innerHTML += output;