Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 46 additions & 4 deletions blocks/header/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,27 @@ function decorateNav(section) {
});
}

/**
* Resolve the locale prefix from the current URL path.
* @returns {string} Locale path segment (e.g. en, fr)
*/
function getLocaleFromPath() {
const segment = window.location.pathname.split('/').filter(Boolean)[0];
if (segment && /^[a-z]{2}(-[a-z]{2})?$/i.test(segment)) {
return segment.split('-')[0].toLowerCase();
}
return 'en';
}

/**
* Whether the page includes a search results widget.
* @returns {boolean}
*/
function pageHasSearchWidget() {
return !!window.hlx?.searchWidgetOnPage
|| !!document.querySelector('.widget.search, .search.widget, .widget a[href*="/widgets/search/"]');
}

/**
* Builds a search form with an input and submit button inside the section.
* @param {Element} section - The search section element
Expand Down Expand Up @@ -205,14 +226,35 @@ function decorateSearch(section) {
section.textContent = '';
section.append(form);

const locale = getLocaleFromPath();
const searchResultsPath = `/${locale}/search`;

const params = new URLSearchParams(window.location.search);
if (params.get('search')) {
input.value = params.get('search');
}

form.addEventListener('submit', (e) => {
e.preventDefault();
const query = input.value.trim();
if (query) {
const q = encodeURIComponent(query);
const path = encodeURIComponent(window.location.pathname);
window.location.href = `/en/search/search-results.html?search=${q}&pagePath=${path}`;
if (!query) return;
if (pageHasSearchWidget()) {
input.dispatchEvent(new Event('input', { bubbles: true }));
return;
}
window.location.href = `${searchResultsPath}?search=${encodeURIComponent(query)}`;
});

document.dispatchEvent(new CustomEvent('header-search-ready', { detail: { input } }));
window.hlx = window.hlx || {};
window.hlx.headerSearch = input;

const searchModulePath = `${window.hlx?.codeBasePath || ''}/widgets/search/search.js`;
import(searchModulePath).then((mod) => {
mod.initHeaderSearch(input, {
anchor: section,
resultsPath: searchResultsPath,
});
});
}

Expand Down
133 changes: 133 additions & 0 deletions widgets/search/search.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/* container */
.search {
max-width: 1200px;
margin: 0 auto;
scroll-margin-top: calc(var(--nav-height) + 1em);
}

.search ol,
.search ul {
list-style: none;
margin: 0;
padding: 0;
}

/* results count */
.search .info {
margin: 0 0 1em;
padding-bottom: 1em;
border-bottom: 1px solid var(--color-border);
color: var(--color-text);
}

.search .info[hidden],
.search .search-prompt[hidden],
.search .no-results[hidden] {
display: none;
}

.search .search-prompt {
color: var(--color-muted);
}

/* results list */
.search .results {
display: flex;
flex-direction: column;
gap: 1em;
margin-bottom: 1.5em;
}

.search .result {
display: flex;
gap: 1em;
align-items: start;
position: relative;
border: 1px solid var(--color-border);
border-radius: 4px;
padding: 1.25em;
background: var(--color-bg);
transition: box-shadow 0.2s;
}

.search .result:hover {
box-shadow: var(--shadow-s);
}

.search .result .media-wrapper {
flex-shrink: 0;
width: 64px;
height: 64px;
overflow: hidden;
border-radius: var(--radius-s);
}

.search .result .media-wrapper picture,
.search .result .media-wrapper picture > img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}

.search .result .body-wrapper {
min-width: 0;
}

.search .result .title {
margin: 0 0 0.4em;
font-family: var(--heading-font-family);
font-size: var(--heading-s);
font-weight: 600;
line-height: 1.3;
}

.search .result .desc {
margin: 0;
color: var(--color-muted);
font-size: var(--text-s);
line-height: 1.5;
}

.search .result .link::before {
content: '';
position: absolute;
inset: 0;
}

/* highlight */
.search .results mark {
outline: 1px solid var(--color-brand);
background-color: var(--color-brand);
}

/* pagination */
.search .pagination {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 0.5em 1em;
}

.search .pagination[hidden] {
display: none;
}

.search .pagination .ellipsis {
display: flex;
align-items: center;
justify-content: center;
}

.search .pagination ol {
display: flex;
flex-wrap: wrap;
gap: 0.5em;
}

.search .pagination ol button[aria-current] {
border-color: var(--color-text);
background-color: var(--color-text);
color: var(--color-bg);
}
16 changes: 16 additions & 0 deletions widgets/search/search.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<p class="info" hidden>
<span id="results-start">0</span>-<span id="results-end">0</span>
<span data-copy="resultsFor">Results For</span>
"<strong id="results-query"></strong>"
</p>
<p class="search-prompt" data-copy="emptyStateIntro">Use the search box in the header to find content across the site.</p>
<section class="no-results" hidden>
<h2 data-copy="noResultsTitle">No results found</h2>
<p data-copy="noResultsText">Try different keywords or check your spelling.</p>
</section>
<ul class="results"></ul>
<nav class="pagination button-wrapper" hidden data-copy="paginationLabel" data-copy-target="aria-label" aria-label="Pagination">
<button type="button" class="button secondary" disabled data-copy="previous" data-copy-target="aria-label">Previous</button>
<ol class="button-wrapper"></ol>
<button type="button" class="button secondary" data-copy="next" data-copy-target="aria-label">Next</button>
</nav>
Loading