Skip to content

Commit

Permalink
Include highlighting in the guide search results
Browse files Browse the repository at this point in the history
  • Loading branch information
marko-bekhta authored and yrodiere committed Dec 4, 2023
1 parent 69cd396 commit 6f031c0
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 82 deletions.
20 changes: 12 additions & 8 deletions _includes/index-docs.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{% assign by_type = index.quarkus | map: "types" | first %}

<div id="guides-app"
data-url="{{ site.search.url }}"
data-search-api-server="{{ site.search.url }}"
data-initial-timeout="{{ site.search.initial-timeout }}"
data-more-timeout="{{ site.search.more-timeout }}"
data-min-chars="{{ site.search.min-chars }}"
Expand Down Expand Up @@ -51,11 +51,15 @@ <h1 class="title">{{ page.title }}</h1>
</div>
</Transition>
<div class="grid-wrapper">
<div v-for="card in cardHits"
v-html="card.innerHTML"
class="grid__item docs-card"
:class="Array.from(card.classList)">
{% raw %}
<div v-for="hit in searchHits" :class="`${hit.type}bkg grid__item docs-card`">
<h4><a :href="hit.url" :target="hit.url.startsWith('http') ? '_blank' : ''" v-html="hit.title"></a></h4>
<div class="description" v-html="hit.summary"></div>
<div class="content-highlights">
<p v-for="contentLine in hit.content" v-html="contentLine"></p>
</div>
</div>
{% endraw %}
<Transition name="fade-in">
<div v-if="loading" class="loading-placeholder">
Loading...
Expand Down Expand Up @@ -92,7 +96,7 @@ <h3 id="guide">How-to Guides</h3>
</div>
<div class="grid-wrapper">
{% for guide in values %}
{% include index-doc-item.html class="guidebkg" docversion=docversion
{% include index-doc-item.html class="howtobkg" docversion=docversion
title=guide.title url=guide.url summary=guide.summary
keywords=guide.keywords categories=guide.categories origin=guide.origin %}
{% endfor %}
Expand All @@ -108,7 +112,7 @@ <h3 id="concept">Concepts</h3>
</div>
<div class="grid-wrapper">
{% for guide in values %}
{% include index-doc-item.html class="conceptbkg" docversion=docversion
{% include index-doc-item.html class="conceptsbkg" docversion=docversion
title=guide.title url=guide.url summary=guide.summary
keywords=guide.keywords categories=guide.categories origin=guide.origin %}
{% endfor %}
Expand Down Expand Up @@ -147,7 +151,7 @@ <h3>General Guides</h3>
</div>
<div class="grid-wrapper">
{% for guide in values %}
{% include index-doc-item.html class="referencebkg" docversion=docversion
{% include index-doc-item.html class="guidebkg" docversion=docversion
title=guide.title url=guide.url summary=guide.summary
keywords=guide.keywords categories=guide.categories origin=guide.origin %}
{% endfor %}
Expand Down
122 changes: 61 additions & 61 deletions _includes/index-guides.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{% assign data_source = include.source %}

<div id="guides-app"
data-url="{{ site.search.url }}"
data-search-api-server="{{ site.search.url }}"
data-initial-timeout="{{ site.search.initial-timeout }}"
data-more-timeout="{{ site.search.more-timeout }}"
data-min-chars="{{ site.search.min-chars }}"
Expand All @@ -28,70 +28,70 @@
<div>
<h1 class="title">{{ page.title }}</h1>
</div>
<div v-if="hasInput" class="grid-wrapper guides results vuejs"
:class="{ empty: !loading && !hasHits, 'vuejs-enabled': true, loading: loading }">
<div class="grid__item width-12-12 click-cards">
<Transition name="fade-in">
<div v-if="!loading && !hasHits" class="empty-placeholder">
Sorry, no guides matched your search. Please try again.
</div>
</Transition>
<Transition name="fade-in">
<div v-if="!loading && !hasHits" class="empty-placeholder">
Sorry, no guides matched your search. Please try again.
</div>
</Transition>
<ul class="list">
<li>
<ul class="grid-wrapper list-item">
<li v-for="card in cardHits"
v-html="card.innerHTML"
class="card"
:class="Array.from(card.classList)">
</li>
<div class="grid-wrapper guides" id="docs">
<div :class="`grid__item width-6-12 width-12-12-m guide-categories callout-wrapper ${!loading && hasHits ? 'hidden' : ''}`">
<h3>View Category</h3>
<ul>
{% for item in site.data[data_source].categories %}
<li>
<a href="#{{ item.cat-id }}">{{ item.category }}</a>
</li>
{% endfor %}
</ul>
</li>
</ul>
<Transition name="fade-in">
<div v-if="loading" class="loading-placeholder">
Loading...
</div>

<div class="grid__item width-6-12 width-12-12-m callout-wrapper">
<div class="grid-wrapper callout">
<div class="grid__item width-12-12">
<h3>Quarkus Cheat Sheet</h3>
</div>
<div class="grid__item col">
<a href="https://lordofthejars.github.io/quarkus-cheat-sheet/" target="_blank">
<span class="col-icon"><i class="far fa-file-pdf"></i></span>
<span class="col-link">Download full cheatsheet as PDF</span>
</a>
</div>
<div class="grid__item col">
<a href="https://developers.redhat.com/search?t=quarkus&f=type%7Echeat_sheet" target="_blank">Get more cheatsheets on the Red Hat Developers website <i class="fas fa-external-link-alt"></i></a>
</div>
</div>
</Transition>
</div>
</div>
</div>
<div v-if="hasInput" class="grid__item width-12-12 click-cards vuejs"
:class="{ empty: !loading && !hasHits, 'vuejs-enabled': true, loading: loading }">
<Transition name="fade-in">
<div v-if="!loading && !hasHits" class="empty-placeholder">
Sorry, no guides matched your search. Please try again.
</div>
</Transition>
<ul class="list results">
<li>
<ul class="grid-wrapper list-item">
{% raw %}
<li class="card" v-for="hit in searchHits">
<a :href="hit.url" :target="hit.url.startsWith('http') ? '_blank' : ''"></a>
<p class="title" v-html="hit.title"></p>
<div class="description" v-html="hit.summary"></div>
<div class="content-highlights">
<p v-for="contentLine in hit.content" v-html="contentLine"></p>
</div>
<div class="origin" v-if="hit.url.startsWith('http')">
<img src="/assets/images/quarkiverse_icon_default.svg" width="25" height="25"/>
<span>Quarkiverse Hub</span>
</div>
</li>
{% endraw %}
</ul>
</li>
</ul>
<Transition name="fade-in">
<div v-if="loading" class="loading-placeholder">
Loading...
</div>
</Transition>
</div>
<!-- Static content displayed when there is no input in the search form or Javascript is disabled,
but also used as a source of data for cards displayed by the vue.js app. -->
<div v-else class="grid-wrapper guides" id="docs">

<div class="grid__item width-6-12 width-12-12-m guide-categories callout-wrapper">
<h3>View Category</h3>
<ul>
{% for item in site.data[data_source].categories %}
<li>
<a href="#{{ item.cat-id }}">{{ item.category }}</a>
</li>
{% endfor %}
</ul>
</div>

<div class="grid__item width-6-12 width-12-12-m callout-wrapper">
<div class="grid-wrapper callout">
<div class="grid__item width-12-12">
<h3>Quarkus Cheat Sheet</h3>
</div>
<div class="grid__item col">
<a href="https://lordofthejars.github.io/quarkus-cheat-sheet/" target="_blank">
<span class="col-icon"><i class="far fa-file-pdf"></i></span>
<span class="col-link">Download full cheatsheet as PDF</span>
</a>
</div>
<div class="grid__item col">
<a href="https://developers.redhat.com/search?t=quarkus&f=type%7Echeat_sheet" target="_blank">Get more cheatsheets on the Red Hat Developers website <i class="fas fa-external-link-alt"></i></a>
</div>
</div>
</div>

<div class="grid__item width-12-12 click-cards">
<div v-else class="grid__item width-12-12 click-cards">
<ul class="list">
{% for item in site.data[data_source].categories %}
<li>
Expand Down
12 changes: 12 additions & 0 deletions _sass/includes/whitecards.scss
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ grid-column: span 3;
line-height: 1.1rem;
}

span.highlighted {
font-weight: bold;
font-style: italic;
line-height: inherit;
}

.content-highlights p {
font-size: .7rem;
line-height: .8rem;
opacity: 0.8;
}

&:hover, &:focus {
background-color: $light-blue;
border:1px solid $light-blue;
Expand Down
23 changes: 22 additions & 1 deletion _sass/layouts/documentation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,16 @@ Styles for the documentation index page
}
}

.content-highlights {
margin: 1rem 0 0 90px;
p {
font-size: .7rem;
line-height: .8rem;
opacity: 0.8;
margin-bottom: .5rem;
}
}

&.quarkiverse .origin {
padding-left: 120px;
text-align: left;
Expand All @@ -267,6 +277,12 @@ Styles for the documentation index page
position: absolute;
left: 90px;
}

span.highlighted {
font-weight: bold;
color: inherit;
line-height: inherit;
}
}

.tutorialbkg {
Expand All @@ -275,11 +291,16 @@ Styles for the documentation index page
}

.guidebkg {
background: url($baseurl + '/assets/images/documentation/docsicon-referencedocs.svg') no-repeat;
background-size: 80px 80px;
}

.howtobkg {
background: url($baseurl + '/assets/images/documentation/docsicon-guides.svg') no-repeat;
background-size: 80px 80px;
}

.conceptbkg {
.conceptsbkg {
background: url($baseurl + '/assets/images/documentation/docsicon-concepts.svg') no-repeat;
background-size: 80px 80px;
}
Expand Down
62 changes: 50 additions & 12 deletions assets/javascript/guides-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const appElement = document.querySelector(appSelector);

const app = createApp({
props: {
url: String,
searchApiServer: String,
initialTimeout: Number,
moreTimeout: Number,
minChars: Number,
Expand Down Expand Up @@ -85,8 +85,8 @@ const app = createApp({
hasHits() {
return this.search.result.hits.length > 0
},
cardHits() {
return this.search.result.hits.map(hit => this.guidesPathToCardHtmlElement.get(hit.id)).filter(e => e)
searchHits() {
return this.search.result.hits
}
},
mounted() {
Expand All @@ -101,7 +101,37 @@ const app = createApp({
cards = appElement.querySelectorAll(cardSelector)
}
this.guidesPathToCardHtmlElement = new Map(Array.from(cards)
.map(element => [new URL(element.querySelector('a').href).pathname, element]))
.map(element => {
const link = element.querySelector('h4 a')
if (link) {
// new versions:
const url = link.getAttribute('href');
return [
new URL(link.href).pathname,
{
url: url,
className: element.className,
title: link.innerHTML,
summary: element.querySelector('div .description').innerHTML,
keywords: element.querySelector('div .keywords').innerHTML,
categories: element.querySelector('div .categories').innerHTML,
origin: element.querySelector('div .origin')?.innerHTML
}];
} else {
// older Quarkus versions:
const url = element.querySelector('a').getAttribute('href')
return [
url,
{
url: url,
className: element.className,
title: element.querySelector('p.title').innerHTML,
summary: element.querySelector('div.description').innerHTML,
keywords: element.querySelector('div.keywords').innerHTML,
origin: element.querySelector('div.origin')?.innerHTML
}];
}
}))

// Load more results on scroll
document.addEventListener('scroll', e => {
Expand Down Expand Up @@ -157,11 +187,14 @@ const app = createApp({
}
const queryParams = {
page: this.search.page,
version: this.quarkusVersion
version: this.quarkusVersion,
contentSnippets: 2,
contentSnippetsLength: 120,
highlightCssClass: 'highlighted'
}
Object.assign(queryParams, this.search.input)
const result = await this._jsonFetch(controller, 'GET', queryParams, timeout)
this.search.result.hits = this.search.result.hits.concat(result.hits)
this.search.result.hits = this.search.result.hits.concat(this._processHits(result.hits))
this.search.result.hasMoreHits = result.hits.length > 0
}
catch(error) {
Expand All @@ -182,9 +215,15 @@ const app = createApp({
}
}
},
_processHits(serverHits) {
return serverHits.map(hit => {
hit.content = hit?.content.map(paragraph => `...${paragraph}...`)
return hit;
})
},
async _jsonFetch(controller, method, queryParams, timeout) {
const timeoutId = setTimeout(() => controller.abort(), timeout)
const response = await fetch(this.url + '?' + ( new URLSearchParams( queryParams ) ).toString(), {
const response = await fetch(`${this.searchApiServer}api/guides/search?${new URLSearchParams( queryParams )}`, {
method: method,
signal: controller.signal,
body: null
Expand All @@ -203,21 +242,20 @@ const app = createApp({

return Array.from(this.guidesPathToCardHtmlElement)
.filter(([path, card]) => this._javascriptFilter(card, terms, categories))
.map(([path, _]) => { return { id: path } })
.map(([_, card]) => card)
},
_javascriptFilter(card, terms, categories) {
let match = true
if (match && categories) {
const categoriesElem = card.getElementsByClassName('categories').item(0)
match = categoriesElem && this._containsAllCaseInsensitive(categoriesElem, categories)
match = this._containsAllCaseInsensitive(card.categories, categories)
}
if (match && terms) {
match = this._containsAllCaseInsensitive(card, terms)
match = this._containsAllCaseInsensitive(`${card.keywords}${card.summary}${card.title}${card.categories}`, terms)
}
return match
},
_containsAllCaseInsensitive(elem, terms) {
const text = (elem.textContent || elem.innerText || '').toLowerCase()
const text = (elem ? elem : '').toLowerCase();
for (let i in terms) {
if (text.indexOf(terms[i].toLowerCase()) < 0) {
return false
Expand Down

0 comments on commit 6f031c0

Please sign in to comment.