feat: opt-in Journal search page and JournalSearchBox
- journal.routes.search (off by default) registers journal-search, the results page for ?q= in the API's relevance order (no sort is sent), server-rendered with a Polish-aware result count. - JournalSearchBox: an icon button and a WAI-ARIA combobox with debounced ?fields=suggest suggestions, stale answers dropped, query words marked ignoring diacritics; a plain GET form without JS. - The module keeps the search path out of the route cache and the sitemap and marks it noindex, follow. - Client: suggestPosts and the fields option; useJournalLinks.searchLink.
This commit is contained in:
@@ -287,3 +287,187 @@
|
||||
margin-top: var(--journal-space-4);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* Search box (header). Outside .journal-layout, so it sets its own type. The
|
||||
panel is inline; an app turns it into a drop-down panel by positioning
|
||||
.journal-search__panel. Without JS the panel is always shown. */
|
||||
.journal-search {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--journal-space-2);
|
||||
font-family: var(--journal-font-body);
|
||||
color: var(--journal-color-text);
|
||||
}
|
||||
|
||||
.journal-search__toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--journal-space-2);
|
||||
border: 0;
|
||||
border-radius: var(--journal-radius-sm);
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.journal-search__toggle:focus-visible,
|
||||
.journal-search__input:focus-visible,
|
||||
.journal-search-page__input:focus-visible,
|
||||
.journal-search-page__submit:focus-visible {
|
||||
outline: 2px solid var(--journal-color-accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.journal-search--enhanced:not(.journal-search--open) .journal-search__panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.journal-search__panel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.journal-search__input,
|
||||
.journal-search-page__input {
|
||||
box-sizing: border-box;
|
||||
width: 16rem;
|
||||
max-width: 100%;
|
||||
padding: var(--journal-space-2) var(--journal-space-3);
|
||||
border: 1px solid var(--journal-color-border);
|
||||
border-radius: var(--journal-radius-sm);
|
||||
background: var(--journal-color-bg);
|
||||
color: var(--journal-color-text);
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.journal-search__dropdown {
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
top: calc(100% + var(--journal-space-1));
|
||||
left: 0; /* a right-aligned box sets left: auto; right: 0 */
|
||||
box-sizing: border-box;
|
||||
width: min(26rem, calc(100vw - 2 * var(--journal-space-3)));
|
||||
padding: var(--journal-space-2) 0;
|
||||
border: 1px solid var(--journal-color-border);
|
||||
border-radius: var(--journal-radius-md);
|
||||
background: var(--journal-color-bg);
|
||||
box-shadow: var(--journal-shadow-dropdown);
|
||||
}
|
||||
|
||||
.journal-search__list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.journal-search__link {
|
||||
display: flex;
|
||||
gap: var(--journal-space-3);
|
||||
padding: var(--journal-space-2) var(--journal-space-3);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.journal-search__option--active .journal-search__link {
|
||||
background: var(--journal-color-surface);
|
||||
}
|
||||
|
||||
.journal-search__thumb {
|
||||
flex: none;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border-radius: var(--journal-radius-sm);
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.journal-search__text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.journal-search__title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.journal-search__excerpt {
|
||||
color: var(--journal-color-muted);
|
||||
font-size: 0.875em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.journal-search mark,
|
||||
.journal-search-page mark {
|
||||
background: var(--journal-color-mark);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.journal-search__status {
|
||||
margin: 0;
|
||||
padding: var(--journal-space-2) var(--journal-space-3);
|
||||
color: var(--journal-color-muted);
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.journal-search__status--loading::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 0.8em;
|
||||
height: 0.8em;
|
||||
margin-right: var(--journal-space-2);
|
||||
border: 2px solid var(--journal-color-border);
|
||||
border-top-color: var(--journal-color-accent);
|
||||
border-radius: 50%;
|
||||
vertical-align: -0.1em;
|
||||
animation: journal-search-spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes journal-search-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.journal-search__status--loading::before {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
.journal-search__all {
|
||||
display: block;
|
||||
padding: var(--journal-space-2) var(--journal-space-3);
|
||||
border-top: 1px solid var(--journal-color-border);
|
||||
color: var(--journal-color-link);
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
/* Search page */
|
||||
.journal-search-page__form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--journal-space-2);
|
||||
margin-bottom: var(--journal-space-4);
|
||||
}
|
||||
|
||||
.journal-search-page__input {
|
||||
flex: 1 1 16rem;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.journal-search-page__submit {
|
||||
padding: var(--journal-space-2) var(--journal-space-4);
|
||||
border: 0;
|
||||
border-radius: var(--journal-radius-sm);
|
||||
background: var(--journal-color-accent);
|
||||
color: var(--journal-color-on-accent);
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.journal-search-page__count,
|
||||
.journal-search-page__message {
|
||||
margin: 0 0 var(--journal-space-4);
|
||||
color: var(--journal-color-muted);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
--journal-color-link-hover: #0550ae; /* hovered links */
|
||||
--journal-color-accent: #0969da; /* current page, focus ring */
|
||||
--journal-color-on-accent: #ffffff; /* text on the accent colour */
|
||||
--journal-color-mark: #fff8c5; /* search term highlight */
|
||||
--journal-shadow-dropdown: 0 8px 24px rgb(0 0 0 / 0.12); /* search suggestions */
|
||||
|
||||
/* Type */
|
||||
--journal-font-body: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; /* body copy */
|
||||
|
||||
Reference in New Issue
Block a user