Skip to content

Commit 2fb3f17

Browse files
committed
Do not use highlights, show initial paragraph
1 parent 9a129ff commit 2fb3f17

File tree

4 files changed

+58
-118
lines changed

4 files changed

+58
-118
lines changed

src/hexdocs/data/model.gleam

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub type Model {
5959
autocomplete_search_focused: AutocompleteFocused,
6060
/// Keeps the results from TypeSense.
6161
/// `#(Page, List(Results))`.
62-
search_result: Option(#(Int, List(hexdocs.TypeSense))),
62+
search_result: Option(#(Int, List(hexdocs.Document))),
6363
/// Stores the current value of the search bar on top of the search page.
6464
search_input: String,
6565
/// Stores the current state of the different previews opened in
@@ -388,7 +388,7 @@ pub fn get_selected_package_filter_name(model: Model) {
388388

389389
pub fn set_search_results(
390390
model: Model,
391-
search_result: #(Int, List(hexdocs.TypeSense)),
391+
search_result: #(Int, List(hexdocs.Document)),
392392
) -> Model {
393393
let search_result = Some(search_result)
394394
Model(..model, search_result:)

src/hexdocs/services/hex.gleam

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,6 @@ pub fn package_versions(name: String) {
2626
})
2727
}
2828

29-
pub fn go_to_link(document: hexdocs.Document) {
30-
case string.split(document.package, on: "-") {
31-
[name, version, ..rest] -> {
32-
let version = string.join([version, ..rest], with: "-")
33-
[config.hexdocs_url(), name, version, document.ref]
34-
|> string.join(with: "/")
35-
|> Ok
36-
}
37-
_ -> Error(Nil)
38-
}
39-
}
40-
4129
pub fn preview_link(document: hexdocs.Document, theme: String) {
4230
let assert [name, vsn] = string.split(document.package, on: "-")
4331
[config.hexdocs_url(), name, vsn, document.ref]

src/hexdocs/services/hexdocs.gleam

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,14 @@ import gleam/http/request
55
import gleam/int
66
import gleam/javascript/promise
77
import gleam/list
8-
import gleam/option.{type Option, None, Some}
8+
import gleam/option.{Some}
99
import gleam/result
1010
import gleam/string
1111
import gleam/uri
1212
import hexdocs/config
1313
import hexdocs/endpoints
1414
import hexdocs/loss
1515

16-
pub type TypeSense {
17-
TypeSense(document: Document, highlight: Highlights)
18-
}
19-
2016
pub type Document {
2117
Document(
2218
doc: String,
@@ -29,14 +25,6 @@ pub type Document {
2925
)
3026
}
3127

32-
pub type Highlights {
33-
Highlights(doc: Option(Highlight), title: Option(Highlight))
34-
}
35-
36-
pub type Highlight {
37-
Highlight(matched_tokens: List(String), snippet: String)
38-
}
39-
4028
pub fn packages() {
4129
let endpoint = endpoints.packages()
4230
let assert Ok(request) = request.from_uri(endpoint)
@@ -73,13 +61,7 @@ pub fn typesense_decoder() {
7361
Document(doc:, id:, package:, proglang:, ref:, title:, type_:)
7462
|> decode.success
7563
})
76-
use highlight <- decode.field("highlight", {
77-
let highlight = highlight_decoder() |> decode.map(Some)
78-
use doc <- decode.optional_field("doc", None, highlight)
79-
use title <- decode.optional_field("title", None, highlight)
80-
decode.success(Highlights(doc:, title:))
81-
})
82-
decode.success(TypeSense(document:, highlight:))
64+
decode.success(document)
8365
})
8466
})
8567
decode.success(#(found, hits))
@@ -96,6 +78,7 @@ fn new_search_query_params(
9678
|> list.key_set("query_by_weights", "3,1,1")
9779
|> list.key_set("page", int.to_string(page))
9880
|> list.key_set("per_page", int.to_string(config.per_page()))
81+
|> list.key_set("highlight_fields", "none")
9982
|> add_filter_by_packages_param(packages)
10083
|> uri.query_to_string
10184
}
@@ -112,10 +95,32 @@ fn add_filter_by_packages_param(
11295
|> list.key_set(query, "filter_by", _)
11396
}
11497

115-
fn highlight_decoder() {
116-
let matched_tokens = decode.list(decode.string)
117-
use matched_tokens <- decode.field("matched_tokens", matched_tokens)
118-
use snippet <- decode.field("snippet", decode.string)
119-
Highlight(matched_tokens:, snippet:)
120-
|> decode.success
98+
pub fn snippet(doc: String, search_input: String) -> String {
99+
// Extract first paragraph
100+
let first_paragraph = case string.split(doc, on: "\r\n\r\n") {
101+
[single] ->
102+
case string.split(single, on: "\n\n") {
103+
[first, ..] -> first
104+
[] -> doc
105+
}
106+
[first, ..] -> first
107+
[] -> doc
108+
}
109+
110+
// Truncate to reasonable length (around 200 characters)
111+
let truncated = case string.length(first_paragraph) > 200 {
112+
True -> string.slice(first_paragraph, 0, 200) <> "..."
113+
False -> first_paragraph
114+
}
115+
116+
// Highlight search terms
117+
case string.trim(search_input) {
118+
"" -> truncated
119+
search_term ->
120+
string.replace(
121+
truncated,
122+
search_term,
123+
"<strong>" <> search_term <> "</strong>",
124+
)
125+
}
121126
}

src/hexdocs/view/search.gleam

Lines changed: 25 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,8 @@ pub fn search(model: Model) {
316316
True -> "Found "
317317
False ->
318318
"Showing first "
319-
|> string.append(int.to_string(config.per_page()))
320-
|> string.append(" out of ")
319+
<> int.to_string(config.per_page())
320+
<> " out of "
321321
}
322322
|> string.append(int.to_string(count))
323323
|> string.append(" results")
@@ -467,68 +467,38 @@ fn trash_button(filter: #(String, String)) {
467467
])
468468
}
469469

470-
fn result_card(model: Model, result: hexdocs.TypeSense) {
470+
fn result_card(model: Model, document: hexdocs.Document) {
471+
let display_url =
472+
"/" <> string.replace(document.package, "-", "/") <> "/" <> document.ref
473+
let link_url = config.hexdocs_url() <> display_url
474+
471475
html.div([class("w-full bg-slate-100 dark:bg-slate-800 rounded-2xl p-4")], [
472-
html.div([class("text-slate-700 dark:text-slate-300 text-sm")], [
473-
html.text(result.document.package),
474-
]),
475-
html.h3(
476+
html.a(
476477
[
477-
class(
478-
"text-slate-950 dark:text-slate-50 text-xl font-semibold leading-loose mt-1",
479-
),
478+
attribute.href(link_url),
479+
class("text-green-700 dark:text-green-400 text-sm hover:underline"),
480480
],
481-
[html.text(result.document.title)],
481+
[html.text(display_url)],
482482
),
483-
// element.unsafe_raw_html(
484-
// "",
485-
// "p",
486-
// [
487-
// class(
488-
// "mt-4 text-slate-800 dark:text-slate-300 leading-normal line-clamp-2 overflow-hidden",
489-
// ),
490-
// ],
491-
// result.document.doc,
492-
// ),
493-
html.div(
483+
html.a(
494484
[
485+
attribute.href(link_url),
495486
class(
496-
"mt-2 inline-flex px-3 py-0.5 bg-slate-300 dark:bg-slate-700 rounded-full",
487+
"text-blue-700 dark:text-blue-300 text-xl font-normal leading-tight mt-1 hover:underline block",
497488
),
498489
],
499-
[
500-
html.span([class("text-blue-600 dark:text-blue-400 text-sm")], [
501-
html.text(result.document.ref),
502-
]),
503-
],
490+
[html.text(document.title)],
491+
),
492+
element.unsafe_raw_html(
493+
"",
494+
"p",
495+
[class("text-slate-800 dark:text-slate-300 leading-normal mt-2")],
496+
hexdocs.snippet(document.doc, model.search_input),
504497
),
505-
case result.highlight {
506-
hexdocs.Highlights(doc: Some(doc), ..) -> {
507-
element.unsafe_raw_html(
508-
"",
509-
"p",
510-
[
511-
class(
512-
"mt-4 text-slate-800 dark:text-slate-300 leading-normal line-clamp-2 overflow-hidden",
513-
),
514-
],
515-
doc.snippet,
516-
)
517-
// html.text("Channels are a really good abstraction"),
518-
// html.span(
519-
// [class("bg-slate-950 text-slate-100 px-1 rounded")],
520-
// [html.text("for")],
521-
// ),
522-
// html.text(
523-
// "real-time communication. They are bi-directional and persistent connections between the browser and server...",
524-
// )
525-
}
526-
_ -> element.none()
527-
},
528498
html.div([class("mt-4 flex flex-wrap gap-3")], [
529499
html.button(
530500
[
531-
event.on_click(msg.UserToggledPreview(result.document.id)),
501+
event.on_click(msg.UserToggledPreview(document.id)),
532502
class(
533503
"h-10 px-4 py-2.5 bg-slate-100 dark:bg-slate-700 rounded-lg border border-slate-300 dark:border-slate-600 flex items-center justify-center",
534504
),
@@ -541,35 +511,12 @@ fn result_card(model: Model, result: hexdocs.TypeSense) {
541511
card_icon("ri-arrow-down-s-line"),
542512
],
543513
),
544-
case hex.go_to_link(result.document) {
545-
Error(_) -> element.none()
546-
Ok(link) ->
547-
html.a(
548-
[
549-
attribute.href(link),
550-
class(
551-
"h-10 px-4 py-2.5 bg-slate-100 dark:bg-slate-700 rounded-lg border border-slate-300 dark:border-slate-600 flex items-center justify-center",
552-
),
553-
],
554-
[
555-
html.span(
556-
[
557-
class(
558-
"text-slate-800 dark:text-slate-200 text-sm font-semibold",
559-
),
560-
],
561-
[html.text("Go to Page")],
562-
),
563-
card_icon("ri-external-link-line"),
564-
],
565-
)
566-
},
567514
]),
568-
case dict.get(model.search_opened_previews, result.document.id) {
515+
case dict.get(model.search_opened_previews, document.id) {
569516
Ok(False) | Error(_) -> element.none()
570517
Ok(True) -> {
571518
case
572-
hex.preview_link(result.document, case model.dark_mode.mode {
519+
hex.preview_link(document, case model.dark_mode.mode {
573520
msg.Dark -> "dark"
574521
msg.Light -> "light"
575522
})
@@ -581,7 +528,7 @@ fn result_card(model: Model, result: hexdocs.TypeSense) {
581528
[
582529
iframe.iframe([
583530
iframe.to(link),
584-
iframe.title(result.document.package),
531+
iframe.title(document.package),
585532
]),
586533
],
587534
)

0 commit comments

Comments
 (0)