mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-19 19:51:20 -08:00
update
This commit is contained in:
1 parent
133a29ce6e
commit
f25f97b3ac
90 files changed
+2694
-1133
No files matched your search
@@ -1,64 +0,0 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import styles from './HomepageFeatures.module.css';
|
||||
|
||||
const FeatureList = [
|
||||
{
|
||||
title: 'Easy to Use',
|
||||
Svg: require('../../static/img/undraw_docusaurus_mountain.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Docusaurus was designed from the ground up to be easily installed and
|
||||
used to get your website up and running quickly.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Focus on What Matters',
|
||||
Svg: require('../../static/img/undraw_docusaurus_tree.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Docusaurus lets you focus on your docs, and we'll do the chores. Go
|
||||
ahead and move your docs into the <code>docs</code> directory.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Powered by React',
|
||||
Svg: require('../../static/img/undraw_docusaurus_react.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Extend or customize your website layout by reusing React. Docusaurus can
|
||||
be extended while reusing the same header and footer.
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
function Feature({Svg, title, description}) {
|
||||
return (
|
||||
<div className={clsx('col col--4')}>
|
||||
<div className="text--center">
|
||||
<Svg className={styles.featureSvg} alt={title} />
|
||||
</div>
|
||||
<div className="text--center padding-horiz--md">
|
||||
<h3>{title}</h3>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function HomepageFeatures() {
|
||||
return (
|
||||
<section className={styles.features}>
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
{FeatureList.map((props, idx) => (
|
||||
<Feature key={idx} {...props} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
.features {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 2rem 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.featureSvg {
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
/* stylelint-disable docusaurus/copyright-header */
|
||||
/**
|
||||
* Any CSS included here will be global. The classic template
|
||||
* bundles Infima by default. Infima is a CSS framework designed to
|
||||
@@ -23,6 +24,37 @@
|
||||
padding: 0 var(--ifm-pre-padding);
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .docusaurus-highlight-code-line {
|
||||
html[data-theme="dark"] .docusaurus-highlight-code-line {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
table {
|
||||
display: table;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
table th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table thead tr {
|
||||
border-bottom-width: 1px !important;
|
||||
}
|
||||
|
||||
table p {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.markdown li > p {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.markdown > p {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.navbar__search {
|
||||
padding-left: 1rem;
|
||||
padding-left: var(--ifm-navbar-padding-horizontal);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import Layout from '@theme/Layout';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import styles from './index.module.css';
|
||||
import HomepageFeatures from '../components/HomepageFeatures';
|
||||
|
||||
function HomepageHeader() {
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
return (
|
||||
<header className={clsx('hero hero--primary', styles.heroBanner)}>
|
||||
<div className="container">
|
||||
<h1 className="hero__title">{siteConfig.title}</h1>
|
||||
<p className="hero__subtitle">{siteConfig.tagline}</p>
|
||||
<div className={styles.buttons}>
|
||||
<Link
|
||||
className="button button--secondary button--lg"
|
||||
to="/docs/intro">
|
||||
Docusaurus Tutorial - 5min ⏱️
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
return (
|
||||
<Layout
|
||||
title={`Hello from ${siteConfig.title}`}
|
||||
description="Description will go into a meta tag in <head />">
|
||||
<HomepageHeader />
|
||||
<main>
|
||||
<HomepageFeatures />
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* CSS files with the .module.css suffix will be treated as CSS modules
|
||||
* and scoped locally.
|
||||
*/
|
||||
|
||||
.heroBanner {
|
||||
padding: 4rem 0;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 966px) {
|
||||
.heroBanner {
|
||||
padding: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Markdown page example
|
||||
---
|
||||
|
||||
# Markdown page example
|
||||
|
||||
You don't need React to write simple standalone pages.
|
||||
@@ -0,0 +1,36 @@
|
||||
const i18n = {
|
||||
English: "中文",
|
||||
};
|
||||
|
||||
function changeI18n() {
|
||||
const zh = window.location.pathname.startsWith("/zh-cn/");
|
||||
const links = Array.from(document.querySelectorAll(".navbar__link"));
|
||||
links.forEach((item) => {
|
||||
const text = item.textContent.trim();
|
||||
if (zh) {
|
||||
if (i18n[text]) {
|
||||
item.textContent = i18n[text];
|
||||
item.dataset.en = text;
|
||||
}
|
||||
} else {
|
||||
if (item.dataset.en && item.dataset.en !== text) {
|
||||
item.textContent = item.dataset.en;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
setTimeout(changeI18n, 300);
|
||||
document.addEventListener("click", (event) => {
|
||||
const { className } = event.target;
|
||||
if (!className || typeof className !== "string") return;
|
||||
if (
|
||||
className.includes("navbar__link") ||
|
||||
className.includes("dropdown__link") ||
|
||||
className.includes("navbar__title")
|
||||
) {
|
||||
setTimeout(changeI18n, 300);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
if (typeof window !== "undefined") {
|
||||
require("./bugfix");
|
||||
}
|
||||
@@ -0,0 +1,533 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* Bottom border of each suggestion */
|
||||
.algolia-docsearch-suggestion {
|
||||
border-bottom-color: #3a3dd1;
|
||||
}
|
||||
/* Main category headers */
|
||||
.algolia-docsearch-suggestion--category-header {
|
||||
background-color: #4b54de;
|
||||
}
|
||||
/* Highlighted search terms */
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
color: #3a33d1;
|
||||
}
|
||||
/* Highligted search terms in the main category headers */
|
||||
.algolia-docsearch-suggestion--category-header
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
background-color: #4d47d5;
|
||||
}
|
||||
/* Currently selected suggestion */
|
||||
.aa-cursor .algolia-docsearch-suggestion--content {
|
||||
color: #272296;
|
||||
}
|
||||
.aa-cursor .algolia-docsearch-suggestion {
|
||||
background: #ebebfb;
|
||||
}
|
||||
|
||||
/* For bigger screens, when displaying results in two columns */
|
||||
@media (min-width: 768px) {
|
||||
/* Bottom border of each suggestion */
|
||||
.algolia-docsearch-suggestion {
|
||||
border-bottom-color: #7671df;
|
||||
}
|
||||
/* Left column, with secondary category header */
|
||||
.algolia-docsearch-suggestion--subcategory-column {
|
||||
border-right-color: #7671df;
|
||||
color: #4e4726;
|
||||
}
|
||||
}
|
||||
|
||||
.searchbox {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 200px;
|
||||
height: 32px !important;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.searchbox .algolia-autocomplete {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.searchbox__wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 999;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.searchbox__input {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
-webkit-transition: box-shadow 0.4s ease, background 0.4s ease;
|
||||
transition: box-shadow 0.4s ease, background 0.4s ease;
|
||||
border: 0;
|
||||
border-radius: 16px;
|
||||
box-shadow: inset 0 0 0 1px #cccccc;
|
||||
background: #ffffff !important;
|
||||
padding: 0;
|
||||
padding-right: 26px;
|
||||
padding-left: 32px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
white-space: normal;
|
||||
font-size: 12px;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.searchbox__input::-webkit-search-decoration,
|
||||
.searchbox__input::-webkit-search-cancel-button,
|
||||
.searchbox__input::-webkit-search-results-button,
|
||||
.searchbox__input::-webkit-search-results-decoration {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.searchbox__input:hover {
|
||||
box-shadow: inset 0 0 0 1px #b3b3b3;
|
||||
}
|
||||
|
||||
.searchbox__input:focus,
|
||||
.searchbox__input:active {
|
||||
outline: 0;
|
||||
box-shadow: inset 0 0 0 1px #aaaaaa;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.searchbox__input::-webkit-input-placeholder {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.searchbox__input::-moz-placeholder {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.searchbox__input:-ms-input-placeholder {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.searchbox__input::placeholder {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.searchbox__submit {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
border-radius: 16px 0 0 16px;
|
||||
background-color: rgba(69, 142, 225, 0);
|
||||
padding: 0;
|
||||
width: 32px;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
font-size: inherit;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
right: inherit;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.searchbox__submit::before {
|
||||
display: inline-block;
|
||||
margin-right: -4px;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.searchbox__submit:hover,
|
||||
.searchbox__submit:active {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.searchbox__submit:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.searchbox__submit svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
vertical-align: middle;
|
||||
fill: #6d7e96;
|
||||
}
|
||||
|
||||
.searchbox__reset {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
font-size: inherit;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
fill: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.searchbox__reset.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.searchbox__reset:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.searchbox__reset svg {
|
||||
display: block;
|
||||
margin: 4px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.searchbox__input:valid ~ .searchbox__reset {
|
||||
display: block;
|
||||
-webkit-animation-name: sbx-reset-in;
|
||||
animation-name: sbx-reset-in;
|
||||
-webkit-animation-duration: 0.15s;
|
||||
animation-duration: 0.15s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes sbx-reset-in {
|
||||
0% {
|
||||
-webkit-transform: translate3d(-20%, 0, 0);
|
||||
transform: translate3d(-20%, 0, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sbx-reset-in {
|
||||
0% {
|
||||
-webkit-transform: translate3d(-20%, 0, 0);
|
||||
transform: translate3d(-20%, 0, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.algolia-autocomplete .ds-dropdown-menu:before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: #373940;
|
||||
z-index: 1000;
|
||||
top: -7px;
|
||||
border-top: 1px solid #373940;
|
||||
border-right: 1px solid #373940;
|
||||
-webkit-transform: rotate(-45deg);
|
||||
transform: rotate(-45deg);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .ds-dropdown-menu {
|
||||
box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2), 0 2px 3px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
@media (min-width: 601px) {
|
||||
.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu {
|
||||
right: 0 !important;
|
||||
left: inherit !important;
|
||||
}
|
||||
|
||||
.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu:before {
|
||||
right: 48px;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .ds-dropdown-menu {
|
||||
position: relative;
|
||||
top: -6px;
|
||||
border-radius: 4px;
|
||||
margin: 6px 0 0;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
height: auto;
|
||||
position: relative;
|
||||
background: transparent;
|
||||
border: none;
|
||||
z-index: 999;
|
||||
max-width: 600px;
|
||||
min-width: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.algolia-autocomplete .ds-dropdown-menu {
|
||||
z-index: 100;
|
||||
position: fixed !important;
|
||||
top: 50px !important;
|
||||
left: auto !important;
|
||||
right: 1rem !important;
|
||||
width: 600px;
|
||||
max-width: calc(100% - 2rem);
|
||||
max-height: calc(100% - 5rem);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .ds-dropdown-menu:before {
|
||||
right: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
.algolia-autocomplete .ds-dropdown-menu .ds-suggestions {
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .ds-dropdown-menu .ds-suggestion {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .ds-dropdown-menu [class^='ds-dataset-'] {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
padding: 0;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .ds-dropdown-menu * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .ds-cursor .algolia-docsearch-suggestion--wrapper {
|
||||
background: #f1f1f1;
|
||||
box-shadow: inset -2px 0 0 #61dafb;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--highlight {
|
||||
background: #ffe564;
|
||||
padding: 0.1em 0.05em;
|
||||
}
|
||||
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion--category-header
|
||||
.algolia-docsearch-suggestion--category-header-lvl0
|
||||
.algolia-docsearch-suggestion--highlight,
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion--category-header
|
||||
.algolia-docsearch-suggestion--category-header-lvl1
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
color: inherit;
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion--text
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
padding: 0 0 1px;
|
||||
background: inherit;
|
||||
box-shadow: inset 0 -2px 0 0 rgba(69, 142, 225, 0.8);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--content {
|
||||
display: block;
|
||||
float: right;
|
||||
width: 70%;
|
||||
position: relative;
|
||||
padding: 5.33333px 0 5.33333px 10.66667px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--content:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 1px;
|
||||
background: #ececec;
|
||||
left: -1px;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--category-header {
|
||||
position: relative;
|
||||
display: none;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0.08em;
|
||||
font-weight: 700;
|
||||
background-color: #373940;
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
margin: 0;
|
||||
padding: 5px 8px;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--wrapper {
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
float: left;
|
||||
padding: 8px 0 0 0;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column {
|
||||
float: left;
|
||||
width: 30%;
|
||||
display: none;
|
||||
padding-left: 0;
|
||||
text-align: right;
|
||||
position: relative;
|
||||
padding: 5.33333px 10.66667px;
|
||||
color: #777;
|
||||
font-size: 0.9em;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 1px;
|
||||
background: #ececec;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion.algolia-docsearch-suggestion__main
|
||||
.algolia-docsearch-suggestion--category-header,
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion--subcategory-column
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-inline {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--title {
|
||||
margin-bottom: 4px;
|
||||
color: #02060c;
|
||||
font-size: 0.9em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--text {
|
||||
display: block;
|
||||
line-height: 1.2em;
|
||||
font-size: 0.85em;
|
||||
color: #63676d;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--no-results {
|
||||
width: 100%;
|
||||
padding: 8px 0;
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
background-color: #373940;
|
||||
margin-top: -8px;
|
||||
}
|
||||
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion--no-results
|
||||
.algolia-docsearch-suggestion--text {
|
||||
color: #ffffff;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion--no-results::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-suggestion code {
|
||||
padding: 1px 5px;
|
||||
font-size: 90%;
|
||||
border: none;
|
||||
color: #222222;
|
||||
background-color: #ebebeb;
|
||||
border-radius: 3px;
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion
|
||||
code
|
||||
.algolia-docsearch-suggestion--highlight {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion.algolia-docsearch-suggestion__main
|
||||
.algolia-docsearch-suggestion--category-header {
|
||||
color: white;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary
|
||||
.algolia-docsearch-suggestion--subcategory-column {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-footer {
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
z-index: 2000;
|
||||
float: right;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.algolia-autocomplete .algolia-docsearch-footer--logo {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 130 18'%3E%3Cdefs%3E%3ClinearGradient id='a' x1='-36.87%25' x2='129.43%25' y1='134.94%25' y2='-27.7%25'%3E%3Cstop stop-color='%252300AEFF' offset='0%25'/%3E%3Cstop stop-color='%25233369E7' offset='100%25'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath fill='url(%2523a)' d='M59.4.02h13.3a2.37 2.37 0 0 1 2.38 2.37V15.6a2.37 2.37 0 0 1-2.38 2.36H59.4a2.37 2.37 0 0 1-2.38-2.36V2.38A2.37 2.37 0 0 1 59.4.02z'/%3E%3Cpath fill='%2523FFF' d='M66.26 4.56c-2.82 0-5.1 2.27-5.1 5.08 0 2.8 2.28 5.07 5.1 5.07 2.8 0 5.1-2.26 5.1-5.07 0-2.8-2.28-5.07-5.1-5.07zm0 8.65c-2 0-3.6-1.6-3.6-3.56 0-1.97 1.6-3.58 3.6-3.58 1.98 0 3.6 1.6 3.6 3.58a3.58 3.58 0 0 1-3.6 3.57zm0-6.4v2.66c0 .07.08.13.15.1l2.4-1.24c.04-.02.06-.1.03-.14a2.96 2.96 0 0 0-2.46-1.5c-.06 0-.1.05-.1.1zm-3.33-1.96l-.3-.3a.78.78 0 0 0-1.12 0l-.36.36a.77.77 0 0 0 0 1.1l.3.3c.05.05.13.04.17 0 .2-.25.4-.5.6-.7.23-.23.46-.43.7-.6.07-.04.07-.1.03-.16zm5-.8V3.4a.78.78 0 0 0-.78-.78h-1.83a.78.78 0 0 0-.78.78v.63c0 .07.06.12.14.1a5.74 5.74 0 0 1 1.58-.22c.52 0 1.04.07 1.54.2a.1.1 0 0 0 .13-.1z'/%3E%3Cpath fill='%2523182359' d='M102.16 13.76c0 1.46-.37 2.52-1.12 3.2-.75.67-1.9 1-3.44 1-.56 0-1.74-.1-2.67-.3l.34-1.7c.78.17 1.82.2 2.36.2.86 0 1.48-.16 1.84-.5.37-.36.55-.88.55-1.57v-.35a6.37 6.37 0 0 1-.84.3 4.15 4.15 0 0 1-1.2.17 4.5 4.5 0 0 1-1.6-.28 3.38 3.38 0 0 1-1.26-.82 3.74 3.74 0 0 1-.8-1.35c-.2-.54-.3-1.5-.3-2.2 0-.67.1-1.5.3-2.06a3.92 3.92 0 0 1 .9-1.43 4.12 4.12 0 0 1 1.45-.92 5.3 5.3 0 0 1 1.94-.37c.7 0 1.35.1 1.97.2a15.86 15.86 0 0 1 1.6.33v8.46zm-5.95-4.2c0 .9.2 1.88.6 2.3.4.4.9.62 1.53.62.34 0 .66-.05.96-.15a2.75 2.75 0 0 0 .73-.33V6.7a8.53 8.53 0 0 0-1.42-.17c-.76-.02-1.36.3-1.77.8-.4.5-.62 1.4-.62 2.23zm16.13 0c0 .72-.1 1.26-.32 1.85a4.4 4.4 0 0 1-.9 1.53c-.38.42-.85.75-1.4.98-.54.24-1.4.37-1.8.37-.43 0-1.27-.13-1.8-.36a4.1 4.1 0 0 1-1.4-.97 4.5 4.5 0 0 1-.92-1.52 5.04 5.04 0 0 1-.33-1.84c0-.72.1-1.4.32-2 .22-.6.53-1.1.92-1.5.4-.43.86-.75 1.4-.98a4.55 4.55 0 0 1 1.78-.34 4.7 4.7 0 0 1 1.8.34c.54.23 1 .55 1.4.97.38.42.68.92.9 1.5.23.6.35 1.3.35 2zm-2.2 0c0-.92-.2-1.7-.6-2.22-.38-.54-.94-.8-1.64-.8-.72 0-1.27.26-1.67.8-.4.54-.58 1.3-.58 2.22 0 .93.2 1.56.6 2.1.38.54.94.8 1.64.8s1.25-.26 1.65-.8c.4-.55.6-1.17.6-2.1zm6.97 4.7c-3.5.02-3.5-2.8-3.5-3.27L113.57.92l2.15-.34v10c0 .25 0 1.87 1.37 1.88v1.8zm3.77 0h-2.15v-9.2l2.15-.33v9.54zM119.8 3.74c.7 0 1.3-.58 1.3-1.3 0-.7-.58-1.3-1.3-1.3-.73 0-1.3.6-1.3 1.3 0 .72.58 1.3 1.3 1.3zm6.43 1c.7 0 1.3.1 1.78.27.5.18.88.42 1.17.73.28.3.5.74.6 1.18.13.46.2.95.2 1.5v5.47a25.24 25.24 0 0 1-1.5.25c-.67.1-1.42.15-2.25.15a6.83 6.83 0 0 1-1.52-.16 3.2 3.2 0 0 1-1.18-.5 2.46 2.46 0 0 1-.76-.9c-.18-.37-.27-.9-.27-1.44 0-.52.1-.85.3-1.2.2-.37.48-.67.83-.9a3.6 3.6 0 0 1 1.23-.5 7.07 7.07 0 0 1 2.2-.1l.83.16v-.35c0-.25-.03-.48-.1-.7a1.5 1.5 0 0 0-.3-.58c-.15-.18-.34-.3-.58-.4a2.54 2.54 0 0 0-.92-.17c-.5 0-.94.06-1.35.13-.4.08-.75.16-1 .25l-.27-1.74c.27-.1.67-.18 1.2-.28a9.34 9.34 0 0 1 1.65-.14zm.18 7.74c.66 0 1.15-.04 1.5-.1V10.2a5.1 5.1 0 0 0-2-.1c-.23.03-.45.1-.64.2a1.17 1.17 0 0 0-.47.38c-.13.17-.18.26-.18.52 0 .5.17.8.5.98.32.2.74.3 1.3.3zM84.1 4.8c.72 0 1.3.08 1.8.26.48.17.87.42 1.15.73.3.3.5.72.6 1.17.14.45.2.94.2 1.47v5.48a25.24 25.24 0 0 1-1.5.26c-.67.1-1.42.14-2.25.14a6.83 6.83 0 0 1-1.52-.16 3.2 3.2 0 0 1-1.18-.5 2.46 2.46 0 0 1-.76-.9c-.18-.38-.27-.9-.27-1.44 0-.53.1-.86.3-1.22.2-.36.5-.65.84-.88a3.6 3.6 0 0 1 1.24-.5 7.07 7.07 0 0 1 2.2-.1c.26.03.54.08.84.15v-.35c0-.24-.03-.48-.1-.7a1.5 1.5 0 0 0-.3-.58c-.15-.17-.34-.3-.58-.4a2.54 2.54 0 0 0-.9-.15c-.5 0-.96.05-1.37.12-.4.07-.75.15-1 .24l-.26-1.75c.27-.08.67-.17 1.18-.26a8.9 8.9 0 0 1 1.66-.15zm.2 7.73c.65 0 1.14-.04 1.48-.1v-2.17a5.1 5.1 0 0 0-1.98-.1c-.24.03-.46.1-.65.18a1.17 1.17 0 0 0-.47.4c-.12.17-.17.26-.17.52 0 .5.18.8.5.98.32.2.75.3 1.3.3zm8.68 1.74c-3.5 0-3.5-2.82-3.5-3.28L89.45.92 91.6.6v10c0 .25 0 1.87 1.38 1.88v1.8z'/%3E%3Cpath fill='%25231D3657' d='M5.03 11.03c0 .7-.26 1.24-.76 1.64-.5.4-1.2.6-2.1.6-.88 0-1.6-.14-2.17-.42v-1.2c.36.16.74.3 1.14.38.4.1.78.15 1.13.15.5 0 .88-.1 1.12-.3a.94.94 0 0 0 .35-.77.98.98 0 0 0-.33-.74c-.22-.2-.68-.44-1.37-.72-.72-.3-1.22-.62-1.52-1C.23 8.27.1 7.82.1 7.3c0-.65.22-1.17.7-1.55.46-.37 1.08-.56 1.86-.56.76 0 1.5.16 2.25.48l-.4 1.05c-.7-.3-1.32-.44-1.87-.44-.4 0-.73.08-.94.26a.9.9 0 0 0-.33.72c0 .2.04.38.12.52.08.15.22.3.42.4.2.14.55.3 1.06.52.58.24 1 .47 1.27.67.27.2.47.44.6.7.12.26.18.57.18.92zM9 13.27c-.92 0-1.64-.27-2.16-.8-.52-.55-.78-1.3-.78-2.24 0-.97.24-1.73.72-2.3.5-.54 1.15-.82 2-.82.78 0 1.4.25 1.85.72.46.48.7 1.14.7 1.97v.67H7.35c0 .58.17 1.02.46 1.33.3.3.7.47 1.24.47.36 0 .68-.04.98-.1a5.1 5.1 0 0 0 .98-.33v1.02a3.87 3.87 0 0 1-.94.32 5.72 5.72 0 0 1-1.08.1zm-.22-5.2c-.4 0-.73.12-.97.38s-.37.62-.42 1.1h2.7c0-.48-.13-.85-.36-1.1-.23-.26-.54-.38-.94-.38zm7.7 5.1l-.26-.84h-.05c-.28.36-.57.6-.86.74-.28.13-.65.2-1.1.2-.6 0-1.05-.16-1.38-.48-.32-.32-.5-.77-.5-1.34 0-.62.24-1.08.7-1.4.45-.3 Line truncated
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 100%;
|
||||
overflow: hidden;
|
||||
text-indent: -9000px;
|
||||
width: 110px;
|
||||
height: 100%;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: 5px;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React, { useRef, useCallback } from "react";
|
||||
import classnames from "classnames";
|
||||
import { useHistory } from "@docusaurus/router";
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import { usePluginData } from '@docusaurus/useGlobalData';
|
||||
const Search = props => {
|
||||
const initialized = useRef(false);
|
||||
const searchBarRef = useRef(null);
|
||||
const history = useHistory();
|
||||
const { siteConfig = {} } = useDocusaurusContext();
|
||||
const { baseUrl } = siteConfig;
|
||||
const initAlgolia = (searchDocs, searchIndex, DocSearch) => {
|
||||
new DocSearch({
|
||||
searchDocs,
|
||||
searchIndex,
|
||||
inputSelector: "#search_input_react",
|
||||
// Override algolia's default selection event, allowing us to do client-side
|
||||
// navigation and avoiding a full page refresh.
|
||||
handleSelected: (_input, _event, suggestion) => {
|
||||
const url = baseUrl + suggestion.url;
|
||||
// Use an anchor tag to parse the absolute url into a relative url
|
||||
// Alternatively, we can use new URL(suggestion.url) but its not supported in IE
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
// Algolia use closest parent element id #__docusaurus when a h1 page title does not have an id
|
||||
// So, we can safely remove it. See https://github.com/facebook/docusaurus/issues/1828 for more details.
|
||||
|
||||
history.push(url);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const pluginData = usePluginData('docusaurus-lunr-search');
|
||||
const getSearchDoc = () =>
|
||||
process.env.NODE_ENV === "production"
|
||||
? fetch(`${baseUrl}${pluginData.fileNames.searchDoc}`).then((content) => content.json())
|
||||
: Promise.resolve([]);
|
||||
|
||||
const getLunrIndex = () =>
|
||||
process.env.NODE_ENV === "production"
|
||||
? fetch(`${baseUrl}${pluginData.fileNames.lunrIndex}`).then((content) => content.json())
|
||||
: Promise.resolve([]);
|
||||
|
||||
const loadAlgolia = () => {
|
||||
if (!initialized.current) {
|
||||
Promise.all([
|
||||
getSearchDoc(),
|
||||
getLunrIndex(),
|
||||
import("./lib/DocSearch"),
|
||||
import("./algolia.css")
|
||||
]).then(([searchDocs, searchIndex, { default: DocSearch }]) => {
|
||||
if( searchDocs.length === 0) {
|
||||
return;
|
||||
}
|
||||
initAlgolia(searchDocs, searchIndex, DocSearch);
|
||||
});
|
||||
initialized.current = true;
|
||||
}
|
||||
};
|
||||
|
||||
const toggleSearchIconClick = useCallback(
|
||||
e => {
|
||||
if (!searchBarRef.current.contains(e.target)) {
|
||||
searchBarRef.current.focus();
|
||||
}
|
||||
props.handleSearchBarToggle && props.handleSearchBarToggle(!props.isSearchBarExpanded);
|
||||
},
|
||||
[props.isSearchBarExpanded]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="navbar__search" key="search-box">
|
||||
<span
|
||||
aria-label="expand searchbar"
|
||||
role="button"
|
||||
className={classnames("search-icon", {
|
||||
"search-icon-hidden": props.isSearchBarExpanded
|
||||
})}
|
||||
onClick={toggleSearchIconClick}
|
||||
onKeyDown={toggleSearchIconClick}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<input
|
||||
id="search_input_react"
|
||||
type="search"
|
||||
placeholder="Search"
|
||||
aria-label="Search"
|
||||
className={classnames(
|
||||
"navbar__search-input",
|
||||
{ "search-bar-expanded": props.isSearchBarExpanded },
|
||||
{ "search-bar": !props.isSearchBarExpanded }
|
||||
)}
|
||||
onClick={loadAlgolia}
|
||||
onMouseOver={loadAlgolia}
|
||||
onFocus={toggleSearchIconClick}
|
||||
onBlur={toggleSearchIconClick}
|
||||
ref={searchBarRef}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Search;
|
||||
@@ -0,0 +1,306 @@
|
||||
import Hogan from "hogan.js";
|
||||
import LunrSearchAdapter from "./lunar-search";
|
||||
import autocomplete from "autocomplete.js";
|
||||
import templates from "./templates";
|
||||
import utils from "./utils";
|
||||
import $ from "autocomplete.js/zepto";
|
||||
|
||||
/**
|
||||
* Adds an autocomplete dropdown to an input field
|
||||
* @function DocSearch
|
||||
* @param {Object} options.searchDocs Search Documents
|
||||
* @param {Object} options.searchIndex Lune searchIndexes
|
||||
* @param {string} options.inputSelector CSS selector that targets the input
|
||||
* value.
|
||||
* @param {Object} [options.autocompleteOptions] Options to pass to the underlying autocomplete instance
|
||||
* @return {Object}
|
||||
*/
|
||||
class DocSearch {
|
||||
constructor({
|
||||
searchDocs,
|
||||
searchIndex,
|
||||
inputSelector,
|
||||
debug = false,
|
||||
queryDataCallback = null,
|
||||
autocompleteOptions = {
|
||||
debug: false,
|
||||
hint: false,
|
||||
autoselect: true
|
||||
},
|
||||
transformData = false,
|
||||
queryHook = false,
|
||||
handleSelected = false,
|
||||
enhancedSearchInput = false,
|
||||
layout = "collumns"
|
||||
}) {
|
||||
this.input = DocSearch.getInputFromSelector(inputSelector);
|
||||
this.queryDataCallback = queryDataCallback || null;
|
||||
const autocompleteOptionsDebug =
|
||||
autocompleteOptions && autocompleteOptions.debug
|
||||
? autocompleteOptions.debug
|
||||
: false;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
autocompleteOptions.debug = debug || autocompleteOptionsDebug;
|
||||
this.autocompleteOptions = autocompleteOptions;
|
||||
this.autocompleteOptions.cssClasses =
|
||||
this.autocompleteOptions.cssClasses || {};
|
||||
this.autocompleteOptions.cssClasses.prefix =
|
||||
this.autocompleteOptions.cssClasses.prefix || "ds";
|
||||
const inputAriaLabel =
|
||||
this.input &&
|
||||
typeof this.input.attr === "function" &&
|
||||
this.input.attr("aria-label");
|
||||
this.autocompleteOptions.ariaLabel =
|
||||
this.autocompleteOptions.ariaLabel || inputAriaLabel || "search input";
|
||||
|
||||
this.isSimpleLayout = layout === "simple";
|
||||
|
||||
this.client = new LunrSearchAdapter(searchDocs, searchIndex);
|
||||
|
||||
if (enhancedSearchInput) {
|
||||
this.input = DocSearch.injectSearchBox(this.input);
|
||||
}
|
||||
this.autocomplete = autocomplete(this.input, autocompleteOptions, [
|
||||
{
|
||||
source: this.getAutocompleteSource(transformData, queryHook),
|
||||
templates: {
|
||||
suggestion: DocSearch.getSuggestionTemplate(this.isSimpleLayout),
|
||||
footer: templates.footer,
|
||||
empty: DocSearch.getEmptyTemplate()
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
const customHandleSelected = handleSelected;
|
||||
this.handleSelected = customHandleSelected || this.handleSelected;
|
||||
|
||||
// We prevent default link clicking if a custom handleSelected is defined
|
||||
if (customHandleSelected) {
|
||||
$(".algolia-autocomplete").on("click", ".ds-suggestions a", event => {
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
this.autocomplete.on(
|
||||
"autocomplete:selected",
|
||||
this.handleSelected.bind(null, this.autocomplete.autocomplete)
|
||||
);
|
||||
|
||||
this.autocomplete.on(
|
||||
"autocomplete:shown",
|
||||
this.handleShown.bind(null, this.input)
|
||||
);
|
||||
|
||||
if (enhancedSearchInput) {
|
||||
DocSearch.bindSearchBoxEvent();
|
||||
}
|
||||
}
|
||||
|
||||
static injectSearchBox(input) {
|
||||
input.before(templates.searchBox);
|
||||
const newInput = input
|
||||
.prev()
|
||||
.prev()
|
||||
.find("input");
|
||||
input.remove();
|
||||
return newInput;
|
||||
}
|
||||
|
||||
static bindSearchBoxEvent() {
|
||||
$('.searchbox [type="reset"]').on("click", function () {
|
||||
$("input#docsearch").focus();
|
||||
$(this).addClass("hide");
|
||||
autocomplete.autocomplete.setVal("");
|
||||
});
|
||||
|
||||
$("input#docsearch").on("keyup", () => {
|
||||
const searchbox = document.querySelector("input#docsearch");
|
||||
const reset = document.querySelector('.searchbox [type="reset"]');
|
||||
reset.className = "searchbox__reset";
|
||||
if (searchbox.value.length === 0) {
|
||||
reset.className += " hide";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the matching input from a CSS selector, null if none matches
|
||||
* @function getInputFromSelector
|
||||
* @param {string} selector CSS selector that matches the search
|
||||
* input of the page
|
||||
* @returns {void}
|
||||
*/
|
||||
static getInputFromSelector(selector) {
|
||||
const input = $(selector).filter("input");
|
||||
return input.length ? $(input[0]) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `source` method to be passed to autocomplete.js. It will query
|
||||
* the Algolia index and call the callbacks with the formatted hits.
|
||||
* @function getAutocompleteSource
|
||||
* @param {function} transformData An optional function to transform the hits
|
||||
* @param {function} queryHook An optional function to transform the query
|
||||
* @returns {function} Method to be passed as the `source` option of
|
||||
* autocomplete
|
||||
*/
|
||||
getAutocompleteSource(transformData, queryHook) {
|
||||
return (query, callback) => {
|
||||
if (queryHook) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
query = queryHook(query) || query;
|
||||
}
|
||||
this.client.search(query).then(hits => {
|
||||
if (
|
||||
this.queryDataCallback &&
|
||||
typeof this.queryDataCallback == "function"
|
||||
) {
|
||||
this.queryDataCallback(hits);
|
||||
}
|
||||
if (transformData) {
|
||||
hits = transformData(hits) || hits;
|
||||
}
|
||||
callback(DocSearch.formatHits(hits));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Given a list of hits returned by the API, will reformat them to be used in
|
||||
// a Hogan template
|
||||
static formatHits(receivedHits) {
|
||||
const clonedHits = utils.deepClone(receivedHits);
|
||||
const hits = clonedHits.map(hit => {
|
||||
if (hit._highlightResult) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
hit._highlightResult = utils.mergeKeyWithParent(
|
||||
hit._highlightResult,
|
||||
"hierarchy"
|
||||
);
|
||||
}
|
||||
return utils.mergeKeyWithParent(hit, "hierarchy");
|
||||
});
|
||||
|
||||
// Group hits by category / subcategory
|
||||
let groupedHits = utils.groupBy(hits, "lvl0");
|
||||
$.each(groupedHits, (level, collection) => {
|
||||
const groupedHitsByLvl1 = utils.groupBy(collection, "lvl1");
|
||||
const flattenedHits = utils.flattenAndFlagFirst(
|
||||
groupedHitsByLvl1,
|
||||
"isSubCategoryHeader"
|
||||
);
|
||||
groupedHits[level] = flattenedHits;
|
||||
});
|
||||
groupedHits = utils.flattenAndFlagFirst(groupedHits, "isCategoryHeader");
|
||||
|
||||
// Translate hits into smaller objects to be send to the template
|
||||
return groupedHits.map(hit => {
|
||||
const url = DocSearch.formatURL(hit);
|
||||
const category = utils.getHighlightedValue(hit, "lvl0");
|
||||
const subcategory = utils.getHighlightedValue(hit, "lvl1") || category;
|
||||
const displayTitle = utils
|
||||
.compact([
|
||||
utils.getHighlightedValue(hit, "lvl2") || subcategory,
|
||||
utils.getHighlightedValue(hit, "lvl3"),
|
||||
utils.getHighlightedValue(hit, "lvl4"),
|
||||
utils.getHighlightedValue(hit, "lvl5"),
|
||||
utils.getHighlightedValue(hit, "lvl6")
|
||||
])
|
||||
.join(
|
||||
'<span class="aa-suggestion-title-separator" aria-hidden="true"> › </span>'
|
||||
);
|
||||
const text = utils.getSnippetedValue(hit, "content");
|
||||
const isTextOrSubcategoryNonEmpty =
|
||||
(subcategory && subcategory !== "") ||
|
||||
(displayTitle && displayTitle !== "");
|
||||
const isLvl1EmptyOrDuplicate =
|
||||
!subcategory || subcategory === "" || subcategory === category;
|
||||
const isLvl2 =
|
||||
displayTitle && displayTitle !== "" && displayTitle !== subcategory;
|
||||
const isLvl1 =
|
||||
!isLvl2 &&
|
||||
(subcategory && subcategory !== "" && subcategory !== category);
|
||||
const isLvl0 = !isLvl1 && !isLvl2;
|
||||
|
||||
return {
|
||||
isLvl0,
|
||||
isLvl1,
|
||||
isLvl2,
|
||||
isLvl1EmptyOrDuplicate,
|
||||
isCategoryHeader: hit.isCategoryHeader,
|
||||
isSubCategoryHeader: hit.isSubCategoryHeader,
|
||||
isTextOrSubcategoryNonEmpty,
|
||||
category,
|
||||
subcategory,
|
||||
title: displayTitle,
|
||||
text,
|
||||
url
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
static formatURL(hit) {
|
||||
const { url, anchor } = hit;
|
||||
if (url) {
|
||||
const containsAnchor = url.indexOf("#") !== -1;
|
||||
if (containsAnchor) return url;
|
||||
else if (anchor) return `${hit.url}#${hit.anchor}`;
|
||||
return url;
|
||||
} else if (anchor) return `#${hit.anchor}`;
|
||||
/* eslint-disable */
|
||||
console.warn("no anchor nor url for : ", JSON.stringify(hit));
|
||||
/* eslint-enable */
|
||||
return null;
|
||||
}
|
||||
|
||||
static getEmptyTemplate() {
|
||||
return args => Hogan.compile(templates.empty).render(args);
|
||||
}
|
||||
|
||||
static getSuggestionTemplate(isSimpleLayout) {
|
||||
const stringTemplate = isSimpleLayout
|
||||
? templates.suggestionSimple
|
||||
: templates.suggestion;
|
||||
const template = Hogan.compile(stringTemplate);
|
||||
return suggestion => template.render(suggestion);
|
||||
}
|
||||
|
||||
handleSelected(input, event, suggestion, datasetNumber, context = {}) {
|
||||
// Do nothing if click on the suggestion, as it's already a <a href>, the
|
||||
// browser will take care of it. This allow Ctrl-Clicking on results and not
|
||||
// having the main window being redirected as well
|
||||
if (context.selectionMethod === "click") {
|
||||
return;
|
||||
}
|
||||
|
||||
input.setVal("");
|
||||
window.location.assign(suggestion.url);
|
||||
}
|
||||
|
||||
handleShown(input) {
|
||||
const middleOfInput = input.offset().left + input.width() / 2;
|
||||
let middleOfWindow = $(document).width() / 2;
|
||||
|
||||
if (isNaN(middleOfWindow)) {
|
||||
middleOfWindow = 900;
|
||||
}
|
||||
|
||||
const alignClass =
|
||||
middleOfInput - middleOfWindow >= 0
|
||||
? "algolia-autocomplete-right"
|
||||
: "algolia-autocomplete-left";
|
||||
const otherAlignClass =
|
||||
middleOfInput - middleOfWindow < 0
|
||||
? "algolia-autocomplete-right"
|
||||
: "algolia-autocomplete-left";
|
||||
const autocompleteWrapper = $(".algolia-autocomplete");
|
||||
if (!autocompleteWrapper.hasClass(alignClass)) {
|
||||
autocompleteWrapper.addClass(alignClass);
|
||||
}
|
||||
|
||||
if (autocompleteWrapper.hasClass(otherAlignClass)) {
|
||||
autocompleteWrapper.removeClass(otherAlignClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DocSearch;
|
||||
@@ -0,0 +1,146 @@
|
||||
import lunr from "@generated/lunr.client";
|
||||
lunr.tokenizer.separator = /[\s\-/]+/;
|
||||
|
||||
class LunrSearchAdapter {
|
||||
constructor(searchDocs, searchIndex) {
|
||||
this.searchDocs = searchDocs;
|
||||
this.lunrIndex = lunr.Index.load(searchIndex);
|
||||
}
|
||||
|
||||
getLunrResult(input) {
|
||||
return this.lunrIndex.query(function (query) {
|
||||
const tokens = lunr.tokenizer(input);
|
||||
query.term(tokens, {
|
||||
boost: 10
|
||||
});
|
||||
query.term(tokens, {
|
||||
wildcard: lunr.Query.wildcard.TRAILING
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getHit(doc, formattedTitle, formattedContent) {
|
||||
return {
|
||||
hierarchy: {
|
||||
lvl0: doc.pageTitle || doc.title,
|
||||
lvl1: doc.type === 0 ? null : doc.title
|
||||
},
|
||||
url: doc.url,
|
||||
_snippetResult: formattedContent ? {
|
||||
content: {
|
||||
value: formattedContent,
|
||||
matchLevel: "full"
|
||||
}
|
||||
} : null,
|
||||
_highlightResult: {
|
||||
hierarchy: {
|
||||
lvl0: {
|
||||
value: doc.type === 0 ? formattedTitle || doc.title : doc.pageTitle,
|
||||
},
|
||||
lvl1:
|
||||
doc.type === 0
|
||||
? null
|
||||
: {
|
||||
value: formattedTitle || doc.title
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
getTitleHit(doc, position, length) {
|
||||
const start = position[0];
|
||||
const end = position[0] + length;
|
||||
let formattedTitle = doc.title.substring(0, start) + '<span class="algolia-docsearch-suggestion--highlight">' + doc.title.substring(start, end) + '</span>' + doc.title.substring(end, doc.title.length);
|
||||
return this.getHit(doc, formattedTitle)
|
||||
}
|
||||
|
||||
getKeywordHit(doc, position, length) {
|
||||
const start = position[0];
|
||||
const end = position[0] + length;
|
||||
let formattedTitle = doc.title + '<br /><i>Keywords: ' + doc.keywords.substring(0, start) + '<span class="algolia-docsearch-suggestion--highlight">' + doc.keywords.substring(start, end) + '</span>' + doc.keywords.substring(end, doc.keywords.length) + '</i>'
|
||||
return this.getHit(doc, formattedTitle)
|
||||
}
|
||||
|
||||
getContentHit(doc, position) {
|
||||
const start = position[0];
|
||||
const end = position[0] + position[1];
|
||||
let previewStart = start;
|
||||
let previewEnd = end;
|
||||
let ellipsesBefore = true;
|
||||
let ellipsesAfter = true;
|
||||
for (let k = 0; k < 3; k++) {
|
||||
const nextSpace = doc.content.lastIndexOf(' ', previewStart - 2);
|
||||
const nextDot = doc.content.lastIndexOf('.', previewStart - 2);
|
||||
if ((nextDot > 0) && (nextDot > nextSpace)) {
|
||||
previewStart = nextDot + 1;
|
||||
ellipsesBefore = false;
|
||||
break;
|
||||
}
|
||||
if (nextSpace < 0) {
|
||||
previewStart = 0;
|
||||
ellipsesBefore = false;
|
||||
break;
|
||||
}
|
||||
previewStart = nextSpace + 1;
|
||||
}
|
||||
for (let k = 0; k < 10; k++) {
|
||||
const nextSpace = doc.content.indexOf(' ', previewEnd + 1);
|
||||
const nextDot = doc.content.indexOf('.', previewEnd + 1);
|
||||
if ((nextDot > 0) && (nextDot < nextSpace)) {
|
||||
previewEnd = nextDot;
|
||||
ellipsesAfter = false;
|
||||
break;
|
||||
}
|
||||
if (nextSpace < 0) {
|
||||
previewEnd = doc.content.length;
|
||||
ellipsesAfter = false;
|
||||
break;
|
||||
}
|
||||
previewEnd = nextSpace;
|
||||
}
|
||||
let preview = doc.content.substring(previewStart, start);
|
||||
if (ellipsesBefore) {
|
||||
preview = '... ' + preview;
|
||||
}
|
||||
preview += '<span class="algolia-docsearch-suggestion--highlight">' + doc.content.substring(start, end) + '</span>';
|
||||
preview += doc.content.substring(end, previewEnd);
|
||||
if (ellipsesAfter) {
|
||||
preview += ' ...';
|
||||
}
|
||||
return this.getHit(doc, null, preview);
|
||||
|
||||
}
|
||||
search(input) {
|
||||
return new Promise((resolve, rej) => {
|
||||
const results = this.getLunrResult(input);
|
||||
const hits = [];
|
||||
results.length > 5 && (results.length = 5);
|
||||
this.titleHitsRes = []
|
||||
this.contentHitsRes = []
|
||||
results.forEach(result => {
|
||||
const doc = this.searchDocs[result.ref];
|
||||
const { metadata } = result.matchData;
|
||||
for (let i in metadata) {
|
||||
if (metadata[i].title) {
|
||||
if (!this.titleHitsRes.includes(result.ref)) {
|
||||
const position = metadata[i].title.position[0]
|
||||
hits.push(this.getTitleHit(doc, position, input.length));
|
||||
this.titleHitsRes.push(result.ref);
|
||||
}
|
||||
} else if (metadata[i].content) {
|
||||
const position = metadata[i].content.position[0]
|
||||
hits.push(this.getContentHit(doc, position))
|
||||
} else if (metadata[i].keywords) {
|
||||
const position = metadata[i].keywords.position[0]
|
||||
hits.push(this.getKeywordHit(doc, position, input.length));
|
||||
this.titleHitsRes.push(result.ref);
|
||||
}
|
||||
}
|
||||
});
|
||||
hits.length > 5 && (hits.length = 5);
|
||||
resolve(hits);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default LunrSearchAdapter;
|
||||
@@ -0,0 +1,114 @@
|
||||
const prefix = 'algolia-docsearch';
|
||||
const suggestionPrefix = `${prefix}-suggestion`;
|
||||
const footerPrefix = `${prefix}-footer`;
|
||||
|
||||
/* eslint-disable max-len */
|
||||
|
||||
const templates = {
|
||||
suggestion: `
|
||||
<a class="${suggestionPrefix}
|
||||
{{#isCategoryHeader}}${suggestionPrefix}__main{{/isCategoryHeader}}
|
||||
{{#isSubCategoryHeader}}${suggestionPrefix}__secondary{{/isSubCategoryHeader}}
|
||||
"
|
||||
aria-label="Link to the result"
|
||||
href="{{{url}}}"
|
||||
>
|
||||
<div class="${suggestionPrefix}--category-header">
|
||||
<span class="${suggestionPrefix}--category-header-lvl0">{{{category}}}</span>
|
||||
</div>
|
||||
<div class="${suggestionPrefix}--wrapper">
|
||||
<div class="${suggestionPrefix}--subcategory-column">
|
||||
<span class="${suggestionPrefix}--subcategory-column-text">{{{subcategory}}}</span>
|
||||
</div>
|
||||
{{#isTextOrSubcategoryNonEmpty}}
|
||||
<div class="${suggestionPrefix}--content">
|
||||
<div class="${suggestionPrefix}--subcategory-inline">{{{subcategory}}}</div>
|
||||
<div class="${suggestionPrefix}--title">{{{title}}}</div>
|
||||
{{#text}}<div class="${suggestionPrefix}--text">{{{text}}}</div>{{/text}}
|
||||
</div>
|
||||
{{/isTextOrSubcategoryNonEmpty}}
|
||||
</div>
|
||||
</a>
|
||||
`,
|
||||
suggestionSimple: `
|
||||
<div class="${suggestionPrefix}
|
||||
{{#isCategoryHeader}}${suggestionPrefix}__main{{/isCategoryHeader}}
|
||||
{{#isSubCategoryHeader}}${suggestionPrefix}__secondary{{/isSubCategoryHeader}}
|
||||
suggestion-layout-simple
|
||||
">
|
||||
<div class="${suggestionPrefix}--category-header">
|
||||
{{^isLvl0}}
|
||||
<span class="${suggestionPrefix}--category-header-lvl0 ${suggestionPrefix}--category-header-item">{{{category}}}</span>
|
||||
{{^isLvl1}}
|
||||
{{^isLvl1EmptyOrDuplicate}}
|
||||
<span class="${suggestionPrefix}--category-header-lvl1 ${suggestionPrefix}--category-header-item">
|
||||
{{{subcategory}}}
|
||||
</span>
|
||||
{{/isLvl1EmptyOrDuplicate}}
|
||||
{{/isLvl1}}
|
||||
{{/isLvl0}}
|
||||
<div class="${suggestionPrefix}--title ${suggestionPrefix}--category-header-item">
|
||||
{{#isLvl2}}
|
||||
{{{title}}}
|
||||
{{/isLvl2}}
|
||||
{{#isLvl1}}
|
||||
{{{subcategory}}}
|
||||
{{/isLvl1}}
|
||||
{{#isLvl0}}
|
||||
{{{category}}}
|
||||
{{/isLvl0}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="${suggestionPrefix}--wrapper">
|
||||
{{#text}}
|
||||
<div class="${suggestionPrefix}--content">
|
||||
<div class="${suggestionPrefix}--text">{{{text}}}</div>
|
||||
</div>
|
||||
{{/text}}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
footer: `
|
||||
<div class="${footerPrefix}">
|
||||
</div>
|
||||
`,
|
||||
empty: `
|
||||
<div class="${suggestionPrefix}">
|
||||
<div class="${suggestionPrefix}--wrapper">
|
||||
<div class="${suggestionPrefix}--content ${suggestionPrefix}--no-results">
|
||||
<div class="${suggestionPrefix}--title">
|
||||
<div class="${suggestionPrefix}--text">
|
||||
No results found for query <b>"{{query}}"</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
searchBox: `
|
||||
<form novalidate="novalidate" onsubmit="return false;" class="searchbox">
|
||||
<div role="search" class="searchbox__wrapper">
|
||||
<input id="docsearch" type="search" name="search" placeholder="Search the docs" autocomplete="off" required="required" class="searchbox__input"/>
|
||||
<button type="submit" title="Submit your search query." class="searchbox__submit" >
|
||||
<svg width=12 height=12 role="img" aria-label="Search">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-search-13"></use>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="reset" title="Clear the search query." class="searchbox__reset hide">
|
||||
<svg width=12 height=12 role="img" aria-label="Reset">
|
||||
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#sbx-icon-clear-3"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="svg-icons" style="height: 0; width: 0; position: absolute; visibility: hidden">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<symbol id="sbx-icon-clear-3" viewBox="0 0 40 40"><path d="M16.228 20L1.886 5.657 0 3.772 3.772 0l1.885 1.886L20 16.228 34.343 1.886 36.228 0 40 3.772l-1.886 1.885L23.772 20l14.342 14.343L40 36.228 36.228 40l-1.885-1.886L20 23.772 5.657 38.114 3.772 40 0 36.228l1.886-1.885L16.228 20z" fill-rule="evenodd"></symbol>
|
||||
<symbol id="sbx-icon-search-13" viewBox="0 0 40 40"><path d="M26.806 29.012a16.312 16.312 0 0 1-10.427 3.746C7.332 32.758 0 25.425 0 16.378 0 7.334 7.333 0 16.38 0c9.045 0 16.378 7.333 16.378 16.38 0 3.96-1.406 7.593-3.746 10.426L39.547 37.34c.607.608.61 1.59-.004 2.203a1.56 1.56 0 0 1-2.202.004L26.807 29.012zm-10.427.627c7.322 0 13.26-5.938 13.26-13.26 0-7.324-5.938-13.26-13.26-13.26-7.324 0-13.26 5.936-13.26 13.26 0 7.322 5.936 13.26 13.26 13.26z" fill-rule="evenodd"></symbol>
|
||||
</svg>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
|
||||
export default templates;
|
||||
@@ -0,0 +1,270 @@
|
||||
import $ from "autocomplete.js/zepto";
|
||||
|
||||
const utils = {
|
||||
/*
|
||||
* Move the content of an object key one level higher.
|
||||
* eg.
|
||||
* {
|
||||
* name: 'My name',
|
||||
* hierarchy: {
|
||||
* lvl0: 'Foo',
|
||||
* lvl1: 'Bar'
|
||||
* }
|
||||
* }
|
||||
* Will be converted to
|
||||
* {
|
||||
* name: 'My name',
|
||||
* lvl0: 'Foo',
|
||||
* lvl1: 'Bar'
|
||||
* }
|
||||
* @param {Object} object Main object
|
||||
* @param {String} property Main object key to move up
|
||||
* @return {Object}
|
||||
* @throws Error when key is not an attribute of Object or is not an object itself
|
||||
*/
|
||||
mergeKeyWithParent(object, property) {
|
||||
if (object[property] === undefined) {
|
||||
return object;
|
||||
}
|
||||
if (typeof object[property] !== 'object') {
|
||||
return object;
|
||||
}
|
||||
const newObject = $.extend({}, object, object[property]);
|
||||
delete newObject[property];
|
||||
return newObject;
|
||||
},
|
||||
/*
|
||||
* Group all objects of a collection by the value of the specified attribute
|
||||
* If the attribute is a string, use the lowercase form.
|
||||
*
|
||||
* eg.
|
||||
* groupBy([
|
||||
* {name: 'Tim', category: 'dev'},
|
||||
* {name: 'Vincent', category: 'dev'},
|
||||
* {name: 'Ben', category: 'sales'},
|
||||
* {name: 'Jeremy', category: 'sales'},
|
||||
* {name: 'AlexS', category: 'dev'},
|
||||
* {name: 'AlexK', category: 'sales'}
|
||||
* ], 'category');
|
||||
* =>
|
||||
* {
|
||||
* 'devs': [
|
||||
* {name: 'Tim', category: 'dev'},
|
||||
* {name: 'Vincent', category: 'dev'},
|
||||
* {name: 'AlexS', category: 'dev'}
|
||||
* ],
|
||||
* 'sales': [
|
||||
* {name: 'Ben', category: 'sales'},
|
||||
* {name: 'Jeremy', category: 'sales'},
|
||||
* {name: 'AlexK', category: 'sales'}
|
||||
* ]
|
||||
* }
|
||||
* @param {array} collection Array of objects to group
|
||||
* @param {String} property The attribute on which apply the grouping
|
||||
* @return {array}
|
||||
* @throws Error when one of the element does not have the specified property
|
||||
*/
|
||||
groupBy(collection, property) {
|
||||
const newCollection = {};
|
||||
$.each(collection, (index, item) => {
|
||||
if (item[property] === undefined) {
|
||||
throw new Error(`[groupBy]: Object has no key ${property}`);
|
||||
}
|
||||
let key = item[property];
|
||||
if (typeof key === 'string') {
|
||||
key = key.toLowerCase();
|
||||
}
|
||||
// fix #171 the given data type of docsearch hits might be conflict with the properties of the native Object,
|
||||
// such as the constructor, so we need to do this check.
|
||||
if (!Object.prototype.hasOwnProperty.call(newCollection, key)) {
|
||||
newCollection[key] = [];
|
||||
}
|
||||
newCollection[key].push(item);
|
||||
});
|
||||
return newCollection;
|
||||
},
|
||||
/*
|
||||
* Return an array of all the values of the specified object
|
||||
* eg.
|
||||
* values({
|
||||
* foo: 42,
|
||||
* bar: true,
|
||||
* baz: 'yep'
|
||||
* })
|
||||
* =>
|
||||
* [42, true, yep]
|
||||
* @param {object} object Object to extract values from
|
||||
* @return {array}
|
||||
*/
|
||||
values(object) {
|
||||
return Object.keys(object).map(key => object[key]);
|
||||
},
|
||||
/*
|
||||
* Flattens an array
|
||||
* eg.
|
||||
* flatten([1, 2, [3, 4], [5, 6]])
|
||||
* =>
|
||||
* [1, 2, 3, 4, 5, 6]
|
||||
* @param {array} array Array to flatten
|
||||
* @return {array}
|
||||
*/
|
||||
flatten(array) {
|
||||
const results = [];
|
||||
array.forEach(value => {
|
||||
if (!Array.isArray(value)) {
|
||||
results.push(value);
|
||||
return;
|
||||
}
|
||||
value.forEach(subvalue => {
|
||||
results.push(subvalue);
|
||||
});
|
||||
});
|
||||
return results;
|
||||
},
|
||||
/*
|
||||
* Flatten all values of an object into an array, marking each first element of
|
||||
* each group with a specific flag
|
||||
* eg.
|
||||
* flattenAndFlagFirst({
|
||||
* 'devs': [
|
||||
* {name: 'Tim', category: 'dev'},
|
||||
* {name: 'Vincent', category: 'dev'},
|
||||
* {name: 'AlexS', category: 'dev'}
|
||||
* ],
|
||||
* 'sales': [
|
||||
* {name: 'Ben', category: 'sales'},
|
||||
* {name: 'Jeremy', category: 'sales'},
|
||||
* {name: 'AlexK', category: 'sales'}
|
||||
* ]
|
||||
* , 'isTop');
|
||||
* =>
|
||||
* [
|
||||
* {name: 'Tim', category: 'dev', isTop: true},
|
||||
* {name: 'Vincent', category: 'dev', isTop: false},
|
||||
* {name: 'AlexS', category: 'dev', isTop: false},
|
||||
* {name: 'Ben', category: 'sales', isTop: true},
|
||||
* {name: 'Jeremy', category: 'sales', isTop: false},
|
||||
* {name: 'AlexK', category: 'sales', isTop: false}
|
||||
* ]
|
||||
* @param {object} object Object to flatten
|
||||
* @param {string} flag Flag to set to true on first element of each group
|
||||
* @return {array}
|
||||
*/
|
||||
flattenAndFlagFirst(object, flag) {
|
||||
const values = this.values(object).map(collection =>
|
||||
collection.map((item, index) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item[flag] = index === 0;
|
||||
return item;
|
||||
})
|
||||
);
|
||||
return this.flatten(values);
|
||||
},
|
||||
/*
|
||||
* Removes all empty strings, null, false and undefined elements array
|
||||
* eg.
|
||||
* compact([42, false, null, undefined, '', [], 'foo']);
|
||||
* =>
|
||||
* [42, [], 'foo']
|
||||
* @param {array} array Array to compact
|
||||
* @return {array}
|
||||
*/
|
||||
compact(array) {
|
||||
const results = [];
|
||||
array.forEach(value => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
results.push(value);
|
||||
});
|
||||
return results;
|
||||
},
|
||||
/*
|
||||
* Returns the highlighted value of the specified key in the specified object.
|
||||
* If no highlighted value is available, will return the key value directly
|
||||
* eg.
|
||||
* getHighlightedValue({
|
||||
* _highlightResult: {
|
||||
* text: {
|
||||
* value: '<mark>foo</mark>'
|
||||
* }
|
||||
* },
|
||||
* text: 'foo'
|
||||
* }, 'text');
|
||||
* =>
|
||||
* '<mark>foo</mark>'
|
||||
* @param {object} object Hit object returned by the Algolia API
|
||||
* @param {string} property Object key to look for
|
||||
* @return {string}
|
||||
**/
|
||||
getHighlightedValue(object, property) {
|
||||
if (
|
||||
object._highlightResult &&
|
||||
object._highlightResult.hierarchy_camel &&
|
||||
object._highlightResult.hierarchy_camel[property] &&
|
||||
object._highlightResult.hierarchy_camel[property].matchLevel &&
|
||||
object._highlightResult.hierarchy_camel[property].matchLevel !== 'none' &&
|
||||
object._highlightResult.hierarchy_camel[property].value
|
||||
) {
|
||||
return object._highlightResult.hierarchy_camel[property].value;
|
||||
}
|
||||
if (
|
||||
object._highlightResult &&
|
||||
object._highlightResult &&
|
||||
object._highlightResult[property] &&
|
||||
object._highlightResult[property].value
|
||||
) {
|
||||
return object._highlightResult[property].value;
|
||||
}
|
||||
return object[property];
|
||||
},
|
||||
/*
|
||||
* Returns the snippeted value of the specified key in the specified object.
|
||||
* If no highlighted value is available, will return the key value directly.
|
||||
* Will add starting and ending ellipsis (…) if we detect that a sentence is
|
||||
* incomplete
|
||||
* eg.
|
||||
* getSnippetedValue({
|
||||
* _snippetResult: {
|
||||
* text: {
|
||||
* value: '<mark>This is an unfinished sentence</mark>'
|
||||
* }
|
||||
* },
|
||||
* text: 'This is an unfinished sentence'
|
||||
* }, 'text');
|
||||
* =>
|
||||
* '<mark>This is an unfinished sentence</mark>…'
|
||||
* @param {object} object Hit object returned by the Algolia API
|
||||
* @param {string} property Object key to look for
|
||||
* @return {string}
|
||||
**/
|
||||
getSnippetedValue(object, property) {
|
||||
if (
|
||||
!object._snippetResult ||
|
||||
!object._snippetResult[property] ||
|
||||
!object._snippetResult[property].value
|
||||
) {
|
||||
return object[property];
|
||||
}
|
||||
let snippet = object._snippetResult[property].value;
|
||||
|
||||
if (snippet[0] !== snippet[0].toUpperCase()) {
|
||||
snippet = `…${snippet}`;
|
||||
}
|
||||
if (['.', '!', '?'].indexOf(snippet[snippet.length - 1]) === -1) {
|
||||
snippet = `${snippet}…`;
|
||||
}
|
||||
return snippet;
|
||||
},
|
||||
/*
|
||||
* Deep clone an object.
|
||||
* Note: This will not clone functions and dates
|
||||
* @param {object} object Object to clone
|
||||
* @return {object}
|
||||
*/
|
||||
deepClone(object) {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
},
|
||||
};
|
||||
|
||||
export default utils;
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.search-icon {
|
||||
background-image: var(--ifm-navbar-search-input-icon);
|
||||
height: auto;
|
||||
width: 24px;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
line-height: 32px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-icon-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.search-bar {
|
||||
width: 0 !important;
|
||||
background: none !important;
|
||||
padding: 0 !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.search-bar-expanded {
|
||||
width: 9rem !important;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
display: inline;
|
||||
vertical-align: sub;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user