Search: Elasticsearch-style highlighted match snippets (results + typeahead)
- SearchHighlight.Snippet: extracts a ±70-char window around the first matching term and marks it (with ellipses) — the ES "highlight" fragment. - Result cards (shift/job/talent) now show that snippet from the matched description/tags when a query is present, so you SEE where the term hit (e.g. «…دارای مدرک <mark>mmt</mark>…») instead of just the role. - Typeahead suggestions gain a highlighted "sub" line (talent→tags, shift→city·specialty, job→facility·city) so matches show in the dropdown too. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -24,4 +24,33 @@ public static class SearchHighlight
|
||||
var marked = Regex.Replace(encoded, pattern, m => $"<mark>{m.Value}</mark>", RegexOptions.IgnoreCase);
|
||||
return new HtmlString(marked);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elasticsearch-style highlight fragment: finds the first matching term in <paramref name="text"/>,
|
||||
/// returns a window of ±<paramref name="radius"/> chars around it with the terms marked and ellipses
|
||||
/// at the cut points. Empty when nothing matches (so callers can hide the line).
|
||||
/// </summary>
|
||||
public static HtmlString Snippet(string? text, string? query, int radius = 70)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(query)) return HtmlString.Empty;
|
||||
var terms = query.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Where(t => t.Length >= 2).ToList();
|
||||
if (terms.Count == 0) return HtmlString.Empty;
|
||||
|
||||
var flat = Regex.Replace(text, @"\s+", " ").Trim();
|
||||
int idx = -1, matchLen = 0;
|
||||
foreach (var t in terms)
|
||||
{
|
||||
var i = flat.IndexOf(t, StringComparison.OrdinalIgnoreCase);
|
||||
if (i >= 0 && (idx < 0 || i < idx)) { idx = i; matchLen = t.Length; }
|
||||
}
|
||||
if (idx < 0) return HtmlString.Empty;
|
||||
|
||||
var start = Math.Max(0, idx - radius);
|
||||
var end = Math.Min(flat.Length, idx + matchLen + radius);
|
||||
var slice = flat.Substring(start, end - start).Trim();
|
||||
var prefix = start > 0 ? "…" : "";
|
||||
var suffix = end < flat.Length ? "…" : "";
|
||||
return new HtmlString(prefix + Mark(slice, query).Value + suffix);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user