1
0
mirror of https://github.com/minio/docs.git synced 2025-07-28 19:42:10 +03:00

Add search page (#687)

- Default Sphinx search page has been replaced with Algolia's 
- Enabled routing to sync the search results with URL

**Preview:**
<img width="1458" alt="Screenshot 2022-12-30 at 14 47 28"
src="https://user-images.githubusercontent.com/13393018/210061993-c906461e-87e2-426f-b956-462cfa77ed40.png">

**How to test:**
1. Click on a search result, navigate back using the browser back button
and check whether the search result modal is open and available.
2. Type a search keyword and press the enter key to navigate to the
search results page, where you can find all the results listed.

Note: You might need to start the local web server on the exact build
sub-directory to test the point number 2.
`build/[branch]/[platform]/html/` - ✔️
`build/` - 
This commit is contained in:
Rushan
2022-12-30 22:42:11 +04:00
committed by GitHub
parent 6d32ddcaa8
commit 376f37f69e
10 changed files with 454 additions and 242 deletions

View File

@ -8,6 +8,25 @@ window.addEventListener("DOMContentLoaded", () => {
.getElementsByTagName("meta")
["docsearch:platform"].getAttribute("content");
// Set search page title
// TODO: Do the right way
const pageName = document
.getElementsByTagName("meta")
["pagename"].getAttribute("content");
if (pageName === "search") {
document.title = "Search " + document.title;
}
// --------------------------------------------------
// Synchronize Search results with browser URL
// --------------------------------------------------
const searchParams = location.search.indexOf("%5D=") >= 0;
if (searchParams) {
searchModalEl.classList.add("search--active", "search--focused");
}
// SVG Icons
const icons = {
h1: `<svg width="14" height="9">
@ -80,6 +99,7 @@ window.addEventListener("DOMContentLoaded", () => {
const search = instantsearch({
indexName: "minio",
searchClient,
routing: true,
initialUiState: {
minio: {
refinementList: {
@ -166,16 +186,6 @@ window.addEventListener("DOMContentLoaded", () => {
item: function (data) {
var returnString;
var docUrl;
var refinedLenth =
search.renderState.minio.refinementList.platform.items.filter(
(x) => x.isRefined
).length;
if (refinedLenth !== 1) {
searchModalEl.classList.add("search--show-platform");
} else {
searchModalEl.classList.remove("search--show-platform");
}
// If the query is a full-match of a lvl1 title,
// display only the h1.
@ -188,8 +198,10 @@ window.addEventListener("DOMContentLoaded", () => {
<i class="search__hits__icon">
${icons.h1}
</i>
<div class="search__hits__title">${data._highlightResult.hierarchy.lvl1.value}</div>
<div class="search__hits__platform">${data.platform}</div>
<div class="search__hits__text">
<div class="search__hits__title">${data._highlightResult.hierarchy.lvl1.value}</div>
<div class="search__hits__platform">${data.platform}</div>
</div>
`;
}
// If the query is a full-match of a lvl2 title,
@ -203,10 +215,12 @@ window.addEventListener("DOMContentLoaded", () => {
<i class="search__hits__icon">
${icons.h2}
</i>
<div class="search__hits__title">${data._highlightResult.hierarchy.lvl2.value}</div>
<div class="search__hits__label">
<div class="search__hits__platform">${data.platform}</div>
${data.hierarchy.lvl1}
<div class="search__hits__text">
<div class="search__hits__title">${data._highlightResult.hierarchy.lvl2.value}</div>
<div class="search__hits__label">
<div class="search__hits__platform">${data.platform}</div>
${data.hierarchy.lvl1}
</div>
</div>
`;
}
@ -221,10 +235,12 @@ window.addEventListener("DOMContentLoaded", () => {
<i class="search__hits__icon">
${icons.h3}
</i>
<div class="search__hits__title">${data._highlightResult.hierarchy.lvl3.value}</div>
<div class="search__hits__label">
<div class="search__hits__platform">${data.platform}</div>
${data.hierarchy.lvl1}
<div class="search__hits__text">
<div class="search__hits__title">${data._highlightResult.hierarchy.lvl3.value}</div>
<div class="search__hits__label">
<div class="search__hits__platform">${data.platform}</div>
${data.hierarchy.lvl1}
</div>
</div>
`;
}
@ -240,31 +256,31 @@ window.addEventListener("DOMContentLoaded", () => {
<i class="search__hits__icon">
${icons.content}
</i>
<div class="search__hits__title">${
data._snippetResult.content.value
}</div>
<div class="search__hits__label">
<div class="search__hits__platform">${data.platform}</div>
<span>${data.hierarchy.lvl1}</span>
${
data.hierarchy.lvl2
? `${icons.chevron}` +
`<span>${data.hierarchy.lvl2}</span>`
: ""
}
${
data.hierarchy.lvl3
? `${icons.chevron}` +
`<span>${data.hierarchy.lvl3}</span>`
: ""
}
<div class="search__hits__text">
<div class="search__hits__title">${
data._snippetResult.content.value
}</div>
<div class="search__hits__label">
<div class="search__hits__platform">${data.platform}</div>
${data.hierarchy.lvl1}
${
data.hierarchy.lvl2
? `${icons.chevron}` + `${data.hierarchy.lvl2}`
: ""
}
${
data.hierarchy.lvl3
? `${icons.chevron}` + `${data.hierarchy.lvl3}`
: ""
}
</div>
</div>
`;
} else {
return false;
}
return `<a target="_blank" rel="noreferrer noopener" href="${docUrl}">
return `<a href="${docUrl}">
${returnString}
</a>`;
},
@ -319,19 +335,22 @@ window.addEventListener("DOMContentLoaded", () => {
});
// Clear the filters on x click
document.addEventListener("click", (e) => {
if(e.target.classList.contains("search__reset")) {
clearRefinements("btn");
}
}, false);
document.addEventListener(
"click",
(e) => {
if (e.target.classList.contains("search__reset")) {
clearRefinements("btn");
}
},
false
);
// Close the search modal on outside click
document.addEventListener("pointerdown", function (e) {
if (e.target.id === "search") {
closeSearchModal();
}
})
});
// Keyboard events
document.addEventListener(
@ -339,14 +358,37 @@ window.addEventListener("DOMContentLoaded", () => {
(e) => {
// Close the search on esc key press
if (e.key === "Escape") {
if(searchModalEl.classList.contains("search--focused")
|| searchModalEl.classList.contains("search--active")) {
if (
searchModalEl.classList.contains("search--focused") ||
searchModalEl.classList.contains("search--active")
) {
closeSearchModal();
}
}
// Navigate to search results page on enter key press
if (e.key === "Enter") {
const searchInputEl = document.querySelector(".search__input");
if (searchInputEl.value && document.activeElement === searchInputEl) {
var platform = "";
var environment = location.hostname === "localhost" || location.hostname === "127.0.0.1" ? "dev" : "prod";
var pathname = environment === "dev" ? "/search.html" : `/docs/minio/${platform}search.html`;
if (activePlatform === "kubernetes") {
platform = "kubernetes/upstream";
} else if (activePlatform === "openshift") {
platform = "kubernetes/openshift";
} else {
platform = activePlatform;
}
setTimeout(() => {
window.location.pathname = pathname;
}, 500);
}
}
// Focus the search input on "Meta + K" key press
const searchInputEl = document.querySelector(".search__input");
var metaKey = isMac() ? e.metaKey : e.ctrlKey;
if (metaKey && e.key === "k") {
if (root.classList.contains("read-mode")) {
@ -371,11 +413,14 @@ window.addEventListener("DOMContentLoaded", () => {
const searchEl = document.getElementById("search-box");
const searchToggleBtnEl = document.querySelector(".search-toggle--keyboard");
if (searchEl) {
if (searchEl && searchToggleBtnEl) {
var metaKey = isMac() ? "⌘K" : "Ctrl+K";
[searchEl, searchToggleBtnEl].forEach((item) => {
item.insertAdjacentHTML("beforeend", `<i class="search-meta-key">${metaKey}</i>`);
item.insertAdjacentHTML(
"beforeend",
`<i class="search-meta-key">${metaKey}</i>`
);
});
}
});

View File

@ -93,6 +93,7 @@
text-align: center;
color: $white;
margin: 3rem 1rem 0;
padding-bottom: 3rem;
}
#read-mode-toggle {

View File

@ -1,76 +1,68 @@
:root {
&:not(.read-mode) {
.search__dropdown {
position: absolute;
top: 100%;
left: 0;
width: 100%;
}
.search--focused {
z-index: 10;
&:before {
content: '';
position: fixed;
.header {
.search__dropdown {
position: absolute;
top: 100%;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: var(--is-container-background);
z-index: -1;
}
.search--focused {
z-index: 10;
&:before {
content: '';
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: var(--is-container-background);
z-index: -1;
}
}
}
}
&.read-mode {
#search {
position: fixed;
left: 0;
top: 0;
z-index: 10;
width: 100%;
height: 100%;
background-color: var(--is-container-background);
display: none;
padding: 3rem;
@include breakpoint-max(breakpoints(sm)) {
padding: 1rem;
}
&.search--active {
display: block;
}
.search-meta-key {
.header {
#search {
position: fixed;
left: 0;
top: 0;
z-index: 10;
width: 100%;
height: 100%;
background-color: var(--is-container-background);
display: none;
padding: 3rem;
@include breakpoint-max(breakpoints(sm)) {
padding: 1rem;
}
&.search--active {
display: block;
}
.search-meta-key {
display: none;
}
}
.search__input {
height: 3.1rem;
}
}
.search__input {
height: 3.1rem;
}
}
}
#search {
padding: 2rem 1rem 2.5rem;
display: flex;
--search-hits-item-padding: 0.5rem;
isolation: isolate;
position: relative;
.search-meta-key {
font-style: normal;
position: absolute;
top: 1rem;
right: 0.9rem;
pointer-events: none;
transition: opacity 300ms;
line-height: 1;
font-size: $font-size-xs;
color: var(--text-muted-color);
}
}
.search--active,
@ -80,61 +72,28 @@
}
}
.search--focused {
.search__dropdown {
display: flex;
}
.search__form {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.search-meta-key {
opacity: 0;
}
}
.search__inner {
max-width: 35rem;
width: 100%;
margin: 0 auto;
border-radius: $border-radius-lg;
position: relative;
}
.search__dropdown {
background-color: var(--is-dropdown-bg);
z-index: 10;
flex-direction: column;
border-radius: 0 0 $border-radius-lg $border-radius-lg;
display: none;
max-height: 23rem;
.search__form {
display: flex;
align-items: center;
border-radius: $border-radius;
}
.search__input {
background: transparent var(--is-search-icon) no-repeat center left 1rem;
background-size: 0.85rem;
border: 0;
appearance: none;
height: 2.75rem;
width: 100%;
padding: 0 1.5rem 0.05rem 2.5rem;
color: var(--text-color);
border-radius: $border-radius;
border: 0;
&::placeholder {
color: var(--text-muted-color);
}
}
.search__form {
display: flex;
align-items: center;
background-color: var(--is-search-bg);
border-radius: $border-radius;
}
.search__reset {
place-content: center;
width: 1.5rem;
@ -159,26 +118,61 @@
}
}
.search__filters {
background-color: var(--is-search-bg);
font-size: $font-size-sm;
#search-clear {
position: absolute;
z-index: -1;
opacity: 0;
pointer-events: none;
}
&:not(.search__filters--empty) {
.search__filters__list {
padding: 0.75rem 1.25rem 1rem;
.search__powered-by {
padding: 0.6rem 1rem;
display: inline-flex;
align-items: center;
color: var(--text-muted-color);
font-size: 0.65rem;
justify-content: flex-end;
transition: color 300ms;
float: right;
&:hover {
color: var(--text-color);
}
&:before {
content: "Search by";
white-space: nowrap;
}
& > a {
display: block;
}
svg {
margin-left: -3.2rem;
path {
fill: currentColor;
&:first-child {
display: none;
}
}
}
}
.search__filters {
font-size: $font-size-sm;
}
.search__filters__list {
list-style: none;
padding: 0;
padding: 0.75rem var(--content-padding) 1rem;
margin: 0;
gap: 0.35rem;
color: var(--text-muted-color);
white-space: nowrap;
overflow-y: auto;
text-align: center;
@include hide-scrollbars();
@ -215,18 +209,12 @@
display: none;
}
#search-results {
flex: 1;
overflow-y: auto;
position: relative;
height: 100%;
@extend .scrollbar;
.search__hits__text {
min-width: 0;
}
.search__hits__list {
list-style: none;
padding: 1rem;
margin: 0;
text-align: left;
}
@ -235,14 +223,12 @@
position: relative;
& > a {
display: block;
padding: 0 0.75rem 0 3.25rem;
display: flex;
align-items: center;
padding: var(--search-hits-item-padding);
border-radius: $border-radius;
min-height: 3rem;
margin-bottom: 0.3rem;
display: flex;
flex-direction: column;
justify-content: center;
&:focus,
&:hover {
@ -253,9 +239,10 @@
.search__hits__label,
.search__hits__title {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 100%;
}
.search__hits__title {
@ -272,16 +259,19 @@
}
.search__hits__label {
display: inline-block;
vertical-align: middle;
color: var(--text-muted-color);
font-size: 0.65rem;
display: flex;
align-items: center;
/* display: flex;
align-items: center; */
line-height: 1;
margin-top: 0.35rem;
//margin-top: 0.35rem;
min-height: 1rem;
padding-bottom: 0.1rem;
.search__hits__platform {
margin-top: 0;
margin-top: 0.2rem;
}
& > svg {
@ -290,18 +280,16 @@
stroke: var(--text-muted-color);
margin: 0 0.25rem;
position: relative;
top: 0.03rem;
top: 0.2rem;
flex-shrink: 0;
}
}
.search__hits__icon {
position: absolute;
height: 2.25rem;
width: 2.25rem;
top: 0;
left: 0.4rem;
bottom: 0;
margin: auto 0;
flex-shrink: 0;
margin-right: 0.75rem;
border-radius: $border-radius;
background-color: var(--is-search-bg);
display: grid;
@ -316,16 +304,11 @@
border: 1px solid var(--is-hit-platform-border-color);
border-radius: $border-radius-sm;
padding: 0.1rem 0.2rem;
display: none;
width: fit-content;
margin: 0.4rem 0.35rem 0 0;
display: inline-block;
}
.search--show-platform {
.search__hits__platform {
display: inline-block;
}
}
.search__hits--empty {
display: grid;
@ -350,52 +333,10 @@
padding: 2rem 1rem;
}
.search__powered-by {
padding: 0.75rem 1rem;
display: inline-flex;
align-items: center;
color: var(--text-muted-color);
font-size: 0.65rem;
justify-content: flex-end;
transition: color 300ms;
float: right;
&:hover {
color: var(--text-color);
}
&:before {
content: "Search by";
}
& > a {
display: block;
}
svg {
margin-left: -3.2rem;
path {
fill: currentColor;
&:first-child {
display: none;
}
}
}
}
#search-clear {
position: absolute;
z-index: -1;
opacity: 0;
pointer-events: none;
}
.search__loading {
position: absolute;
top: 0.75rem;
left: 1rem;
top: 0.75rem;
left: 1rem;
background-color: var(--is-search-bg);
svg {
@ -405,4 +346,147 @@
stroke: var(--is-loader-circle-stroke);
}
}
}
.header {
#search {
padding: 0 1rem 2.5rem;
display: flex;
.search-meta-key {
font-style: normal;
position: absolute;
top: 1rem;
right: 0.9rem;
pointer-events: none;
transition: opacity 300ms;
line-height: 1;
font-size: $font-size-xs;
color: var(--text-muted-color);
}
}
.search--focused {
.search__dropdown {
display: flex;
}
.search__form {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.search-meta-key {
opacity: 0;
}
}
.search__form {
background-color: var(--is-search-bg);
}
.search__inner {
max-width: 35rem;
width: 100%;
margin: 0 auto;
border-radius: $border-radius-lg;
position: relative;
}
.search__dropdown {
background-color: var(--is-dropdown-bg);
z-index: 10;
flex-direction: column;
border-radius: 0 0 $border-radius-lg $border-radius-lg;
display: none;
max-height: 24.5rem;
}
.search__filters {
background-color: var(--is-search-bg);
&:not(.search__filters--empty) {
.search__filters__list {
padding-inline: 1.25rem;
}
}
}
#search-results {
flex: 1;
overflow-y: auto;
position: relative;
height: 100%;
@extend .scrollbar;
}
.search__filters__list {
text-align: center;
}
.search__hits__list {
padding: 1rem;
}
}
#search-documentation {
#search {
--search-hits-item-padding: 0.7rem;
margin-top: 1rem;
}
.search__form {
border: 1px solid var(--is-search-border-color);
&:focus-within {
box-shadow: 0 0 0 3px var(--is-search-focus-box-shadow);
}
}
#search-powered-by {
position: absolute;
top: -2.25rem;
right: -0.85em;
}
#search-filters {
margin-inline: calc(var(--content-padding) * -1);
}
.search__hits {
margin: 2rem 0 0 -0.75rem;
&:not(.ais-Hits--empty) {
position: relative;
&:before {
content: "Search Results";
padding-left: 0.75rem;
font-size: $font-size-sm;
font-weight: $font-weight-medium;
display: inline-block;
background-color: var(--body-bg);
position: relative;
padding-right: 0.5rem;
z-index: 2;
padding-bottom: 0.5rem;
}
&:after {
content: "";
height: 1px;
position: absolute;
top: 1rem;
left: 0;
width: 100%;
z-index: 1;
background-color: var(--theme-light-bg);
}
}
}
.search__hits__icon {
--is-search-bg: var(--is-refine-list-border-color);
}
}

View File

@ -123,6 +123,8 @@ $theme-properties: (
--is-hit-platform-border-color: #c5cad0 $dark-300,
--is-loader-circle-stroke: #c2c8d1 $dark-300,
--is-meta-key-border-color: #c5cad0 $dark-400,
--is-search-border-color: $light-500 $dark-300,
--is-search-focus-box-shadow: rgba($light-500, 0.35) rgba($dark-100, 0.75),
);
// Activate dark/light themes

View File

@ -1,6 +1,7 @@
<!-- Algolia meta attrs -->
<meta name="docsearch:platform" content="{{ doc_platform }}"/>
<meta name="docsearch:version" content="{{ doc_platform }}"/>
<meta name="pagename" content="{{ pagename }}"/>
<!-- Preload fonts and scripts -->
<link rel="preload" href="{{ pathto('_static/fonts/inter/Inter-Regular.woff2', 1) }}" as="font" type="font/woff2" crossorigin>

View File

@ -47,6 +47,7 @@
<h2 class="header__title hidden-rm">Documentation</h2>
{%- if pagename != "search" %}
<div id="search">
<div class="search__inner">
<div id="search-box"></div>
@ -59,6 +60,7 @@
</div>
</div>
</div>
{%- endif %}
</div>
{%- include "platform-navigation.html" %}

View File

@ -83,7 +83,9 @@
<div class="content__main">
{% block body %} {% endblock %}
{%- include "footer.html" %}
{%- if pagename != "search-results" %}
{%- include "footer.html" %}
{%- endif %}
</div>
</div>
</section>

View File

@ -30,11 +30,13 @@
<img class="hidden-rm" src="{{ pathto('_static/img/icons/windows-inactive.svg',1) }}" alt="Windows" />
Windows
</a>
<button type="button" class="icon search-toggle search-toggle--keyboard visible-rm">
{%- include "icons/search.html" %}
Search
</button>
{%- if pagename != "search" %}
<button type="button" class="icon search-toggle search-toggle--keyboard visible-rm">
{%- include "icons/search.html" %}
Search
</button>
{%- endif %}
</nav>
</div>

View File

@ -0,0 +1,73 @@
{# Import the theme's layout. #}
{% extends "!layout.html" %}
{# Custom CSS overrides #}
{% block extrahead %}
{%- include "head.html" %}
{{ super() }}
{% endblock %}
{# Override content block #}
{%- macro miniosidebar() %}
{%- if render_sidebar %}
<nav
class="docs"
role="navigation"
>
{%- if sidebars != None %}
{#- new style sidebar: explicitly include/exclude templates #}
{%- for sidebartemplate in sidebars %}
{%- include sidebartemplate %}
{%- endfor %}
{%- endif %}
</nav>
{%- endif %}
{%- endmacro %}
{%- block header %}
{%- include "header.html" %}
{%- endblock %}
{%- block content %}
<section class="content">
<div class="container">
<div class="sidebar inactive scrollbar">
<div class="hide-aside visible-rm">
<button type="button" class="icon">
{%- include "icons/close.html" %}
Close Doc Navigation
</button>
</div>
<a class="sidebar__title" href="{{ pathto('index') }}">{{ shorttitle}}</a>
{{ miniosidebar() }}
</div>
{%- include "toc.html" %}
<div class="content__main" id="search-documentation">
{% block body %}
<div id="search">
<div class="search__inner">
<div id="search-box"></div>
<div class="search__dropdown">
<div id="search-filters"></div>
<div id="search-clear"></div>
<div id="search-results"></div>
<div id="search-powered-by"></div>
</div>
</div>
</div>
{% endblock %}
</div>
</div>
</section>
{%- endblock %}
{%- block footer %}
{%- include "cookie.html" %}
{%- endblock %}

View File

@ -1,13 +1,13 @@
<div class="content__toc scrollbar scrollbar--hover">
<button data-aside-toggle="doc" class="icon" type="button">
{%- include "icons/menu.html" %}
TOC Menu
</button>
<button data-aside-toggle="doc" class="icon" type="button">
{%- include "icons/menu.html" %} TOC Menu
</button>
<div id="content-toc"></div>
<div id="content-toc"></div>
<button class="icon search-toggle" type="button">
{%- include "icons/search.html" %}
Search
</button>
</div>
{%- if pagename != "search" %}
<button class="icon search-toggle" type="button">
{%- include "icons/search.html" %} Search
</button>
{%- endif %}
</div>