mirror of
https://github.com/squidfunk/mkdocs-material.git
synced 2024-06-14 11:52:32 +03:00
Added page grouping for search results
This commit is contained in:
parent
f72a88721e
commit
ba3565625d
@ -90,7 +90,7 @@ let args = yargs
|
|||||||
})
|
})
|
||||||
.option("optimize", {
|
.option("optimize", {
|
||||||
describe: chalk.grey("optimize and minify assets"),
|
describe: chalk.grey("optimize and minify assets"),
|
||||||
default: true,
|
default: false,
|
||||||
global: true
|
global: true
|
||||||
})
|
})
|
||||||
.option("revision", {
|
.option("revision", {
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
material/assets/stylesheets/application-b825c62f38.css
Normal file
1
material/assets/stylesheets/application-b825c62f38.css
Normal file
File diff suppressed because one or more lines are too long
@ -38,7 +38,7 @@
|
|||||||
<script src="{{ base_url }}/assets/javascripts/modernizr-56ade86843.js"></script>
|
<script src="{{ base_url }}/assets/javascripts/modernizr-56ade86843.js"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block styles %}
|
{% block styles %}
|
||||||
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-1d1da4857d.css">
|
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-b825c62f38.css">
|
||||||
{% if config.extra.palette %}
|
{% if config.extra.palette %}
|
||||||
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-66fa0d9bba.palette.css">
|
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-66fa0d9bba.palette.css">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -151,7 +151,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="{{ base_url }}/assets/javascripts/application-42beea1040.js"></script>
|
<script src="{{ base_url }}/assets/javascripts/application-095a104376.js"></script>
|
||||||
<script>app.initialize({url:{base:"{{ base_url }}"}})</script>
|
<script>app.initialize({url:{base:"{{ base_url }}"}})</script>
|
||||||
{% for path in extra_javascript %}
|
{% for path in extra_javascript %}
|
||||||
<script src="{{ path }}"></script>
|
<script src="{{ path }}"></script>
|
||||||
|
@ -107,51 +107,36 @@ export default class Result {
|
|||||||
/* eslint-enable no-invalid-this, lines-around-comment */
|
/* eslint-enable no-invalid-this, lines-around-comment */
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
/* Preprocess and index sections and documents */
|
||||||
* The MkDocs search index provides all pages as specified in the
|
this.docs_ = data.reduce((docs, doc) => {
|
||||||
* mkdocs.yml in order with an entry for the content of the whole
|
const [path, hash] = doc.location.split("#")
|
||||||
* page followed by separate entries for all subsections also in
|
|
||||||
* order of appearance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 1. Reduce docs so that useless entries are not included, using a
|
/* Associate section with parent document */
|
||||||
// quick spliting hack - only one test is necessary.
|
if (hash) {
|
||||||
const main = []
|
doc.parent = docs.get(path)
|
||||||
const reduced = data.reduce((docs, doc) => {
|
|
||||||
if (docs.length && doc.location.split(
|
|
||||||
`${docs[docs.length - 1].location}#`).length > 1)
|
|
||||||
main.push(docs.pop())
|
|
||||||
doc.main = main.length - 1 // main entry
|
|
||||||
return docs.concat(doc)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
// now we have the main pages.
|
/* Override page title with document title if first section */
|
||||||
|
if (doc.parent && !doc.parent.done) {
|
||||||
|
doc.parent.title = doc.title
|
||||||
|
doc.parent.text = doc.text
|
||||||
|
doc.parent.done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only return top-level pages
|
/* Some cleanup on the text */
|
||||||
// const reduced = data.reduce((docs, doc) => {
|
|
||||||
// if (!doc.location.match("#"))
|
|
||||||
// docs.push(doc)
|
|
||||||
// return docs
|
|
||||||
// }, [])
|
|
||||||
|
|
||||||
// 2. Trim texts
|
|
||||||
const trimmed = reduced.map(doc => {
|
|
||||||
doc.text = doc.text
|
doc.text = doc.text
|
||||||
.replace(/\n/g, " ") /* Remove newlines */
|
.replace(/\n/g, " ") /* Remove newlines */
|
||||||
.replace(/\s+/g, " ") /* Compact whitespace */
|
.replace(/\s+/g, " ") /* Compact whitespace */
|
||||||
.replace(/\s+([,.:;!?])/g, /* Correct punctuation */
|
.replace(/\s+([,.:;!?])/g, /* Correct punctuation */
|
||||||
(_, char) => char)
|
(_, char) => char)
|
||||||
return doc
|
|
||||||
})
|
|
||||||
|
|
||||||
const data2 = trimmed
|
/* Index sections and documents, but skip top-level headline */
|
||||||
|
if (!doc.parent || doc.parent.title !== doc.title) {
|
||||||
/* Index documents */
|
|
||||||
this.docs_ = data2.reduce((docs, doc) => {
|
|
||||||
this.index_.add(doc)
|
this.index_.add(doc)
|
||||||
docs[doc.location] = doc
|
docs.set(doc.location, doc)
|
||||||
|
}
|
||||||
return docs
|
return docs
|
||||||
}, {})
|
}, new Map)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize index after short timeout to account for transition */
|
/* Initialize index after short timeout to account for transition */
|
||||||
@ -171,57 +156,102 @@ export default class Result {
|
|||||||
while (this.list_.firstChild)
|
while (this.list_.firstChild)
|
||||||
this.list_.removeChild(this.list_.firstChild)
|
this.list_.removeChild(this.list_.firstChild)
|
||||||
|
|
||||||
/* Perform search on index and render documents */
|
/* Perform search on index and group sections by document */
|
||||||
const result = this.index_.search(target.value)
|
const result = this.index_
|
||||||
|
.search(target.value)
|
||||||
|
.reduce((items, item) => {
|
||||||
|
const doc = this.docs_.get(item.ref)
|
||||||
|
if (doc.parent) {
|
||||||
|
const ref = doc.parent.location
|
||||||
|
items.set(ref, (items.get(ref) || []).concat(item))
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}, new Map)
|
||||||
|
|
||||||
|
/* Assemble highlight regex from query string */
|
||||||
|
const match = new RegExp(
|
||||||
|
`\\b(${target.value.trim().replace(" ", "|")})`, "img")
|
||||||
|
|
||||||
|
/* Render results */
|
||||||
|
result.forEach((items, ref) => {
|
||||||
|
const doc = this.docs_.get(ref)
|
||||||
|
|
||||||
|
// TODO: unify teaser and stuff again and use modifier --document --section
|
||||||
|
// TODO: write a highlight function which receives a document --> can be abstracted later
|
||||||
|
|
||||||
|
/* Append search result */
|
||||||
|
this.list_.appendChild(
|
||||||
|
<li class="md-search-result__item">
|
||||||
|
<a href={doc.location} title={doc.title}
|
||||||
|
class="md-search-result__link">
|
||||||
|
<article class="md-search-result__article
|
||||||
|
md-search-result__article--document">
|
||||||
|
<h1 class="md-search-result__title">
|
||||||
|
{{ __html:
|
||||||
|
doc.title.replace(match, string => `<em>${string}</em>`)
|
||||||
|
}}
|
||||||
|
</h1>
|
||||||
|
<p class="md-search-result__teaser">
|
||||||
|
{{ __html:
|
||||||
|
doc.text.replace(match, string => `<em>${string}</em>`)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
</a>
|
||||||
|
{items.map(item => {
|
||||||
|
const section = this.docs_.get(item.ref)
|
||||||
|
return (
|
||||||
|
<a href={section.location} title={section.title}
|
||||||
|
class="md-search-result__link" data-md-rel="anchor">
|
||||||
|
<article class="md-search-result__article
|
||||||
|
md-search-result__article--section">
|
||||||
|
<h1 class="md-search-result__title">
|
||||||
|
{{ __html:
|
||||||
|
section.title.replace(match,
|
||||||
|
string => `<em>${string}</em>`)
|
||||||
|
}}
|
||||||
|
</h1>
|
||||||
|
<p class="md-search-result__teaser">
|
||||||
|
{{ __html:
|
||||||
|
section.text.replace(match,
|
||||||
|
string => `<em>${string}</em>`)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</li>
|
||||||
|
) /* {this.truncate_(doc.text, 140)} */
|
||||||
|
})
|
||||||
|
|
||||||
// process results!
|
// process results!
|
||||||
const re = new RegExp(`\\b${target.value}`, "img")
|
// const re = new RegExp(`\\b${target.value}`, "img")
|
||||||
// result.map(item => {
|
// result.map(item => {
|
||||||
// // console.time("someFunction")
|
// // console.time("someFunction")
|
||||||
// text = text.replace(re, "*XXX*") // do in parallel and collect!
|
// text = text.replace(re, "*XXX*") // do in parallel and collect!
|
||||||
// // console.timeEnd("someFunction")
|
// // console.timeEnd("someFunction")
|
||||||
// })
|
// })
|
||||||
|
|
||||||
result.forEach(item => {
|
// result.forEach(item => {
|
||||||
const doc = this.data_[item.ref]
|
// const doc = this.docs_[item.ref]
|
||||||
// console.log(item.score)
|
// // console.log(item.score)
|
||||||
|
//
|
||||||
/* Check if it's a anchor link on the current page */
|
// /* Check if it's a anchor link on the current page */
|
||||||
let [pathname] = doc.location.split("#")
|
// let [pathname] = doc.location.split("#")
|
||||||
pathname = pathname.replace(/^(\/?\.{2})+/g, "")
|
// pathname = pathname.replace(/^(\/?\.{2})+/g, "")
|
||||||
|
//
|
||||||
// TODO: match in children but show top level entry with merged
|
// // TODO: match in children but show top level entry with merged
|
||||||
// sentences split top level and main entries! index one top level,
|
// // sentences split top level and main entries! index one top level,
|
||||||
// when there is no child
|
// // when there is no child
|
||||||
|
//
|
||||||
let text = doc.text
|
// let text = doc.text
|
||||||
// const re = new RegExp(`\\b${ev.target.value}`, "img")
|
// // const re = new RegExp(`\\b${ev.target.value}`, "img")
|
||||||
// console.time("someFunction")
|
// // console.time("someFunction")
|
||||||
text = text.replace(re, string => {
|
// text = text.replace(re, string => {
|
||||||
return `<b style="color: red">${string}</b>`
|
// return `<b style="color: red">${string}</b>`
|
||||||
})
|
// })
|
||||||
// console.log(text)
|
// })
|
||||||
// console.timeEnd("someFunction")
|
|
||||||
|
|
||||||
/* Append search result */
|
|
||||||
this.list_.appendChild(
|
|
||||||
<li class="md-search-result__item">
|
|
||||||
<a href={doc.location} title={doc.title}
|
|
||||||
class="md-search-result__link" data-md-rel={
|
|
||||||
pathname === document.location.pathname
|
|
||||||
? "anchor" : ""}>
|
|
||||||
<article class="md-search-result__article">
|
|
||||||
<h1 class="md-search-result__title">
|
|
||||||
{doc.title}
|
|
||||||
</h1>
|
|
||||||
<p class="md-search-result__teaser">
|
|
||||||
{{ __html: text }}
|
|
||||||
</p>
|
|
||||||
</article>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
) /* {this.truncate_(doc.text, 140)} */
|
|
||||||
})
|
|
||||||
|
|
||||||
/* Bind click handlers for anchors */
|
/* Bind click handlers for anchors */
|
||||||
const anchors = this.list_.querySelectorAll("[data-md-rel=anchor]")
|
const anchors = this.list_.querySelectorAll("[data-md-rel=anchor]")
|
||||||
|
@ -346,6 +346,8 @@
|
|||||||
|
|
||||||
// Search result
|
// Search result
|
||||||
.md-search-result {
|
.md-search-result {
|
||||||
|
color: $md-color-black;
|
||||||
|
word-break: break-word;
|
||||||
|
|
||||||
// Search metadata
|
// Search metadata
|
||||||
&__meta {
|
&__meta {
|
||||||
@ -377,42 +379,75 @@
|
|||||||
// Link inside item
|
// Link inside item
|
||||||
&__link {
|
&__link {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 0 1.6rem;
|
|
||||||
transition: background 0.25s;
|
transition: background 0.25s;
|
||||||
overflow: auto;
|
overflow: hidden;
|
||||||
|
|
||||||
// Hovered link
|
// Hovered link
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: transparentize($md-color-accent, 0.9);
|
background-color: transparentize($md-color-accent, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a little spacing on the last link
|
||||||
|
&:last-child {
|
||||||
|
padding-bottom: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Article - document or section
|
||||||
|
&__article {
|
||||||
|
position: relative;
|
||||||
|
padding: 0 1.6rem;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
// [tablet landscape +]: Increase left indent
|
// [tablet landscape +]: Increase left indent
|
||||||
@include break-from-device(tablet landscape) {
|
@include break-from-device(tablet landscape) {
|
||||||
padding-left: 4.8rem;
|
padding-left: 4.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Document
|
||||||
|
&--document {
|
||||||
|
padding-left: 0;
|
||||||
|
|
||||||
|
// Icon
|
||||||
|
&::before {
|
||||||
|
@extend %md-icon, %md-icon__button;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
color: $md-color-black--light;
|
||||||
|
content: "find_in_page";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search result content
|
// Title
|
||||||
&__article {
|
.md-search-result__title {
|
||||||
margin: 1em 0;
|
margin: 1.3rem 0;
|
||||||
}
|
|
||||||
|
|
||||||
// Search result title
|
|
||||||
&__title {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
margin-bottom: 0;
|
|
||||||
color: $md-color-black;
|
|
||||||
font-size: ms(0);
|
font-size: ms(0);
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Search result teaser
|
// Title
|
||||||
|
&__title {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
font-size: ms(-1);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Teaser
|
||||||
&__teaser {
|
&__teaser {
|
||||||
margin: 0.5em 0;
|
margin: 0.5em 0;
|
||||||
color: $md-color-black--light;
|
color: $md-color-black--light;
|
||||||
font-size: ms(-1);
|
font-size: ms(-1);
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
word-break: break-word;
|
}
|
||||||
|
|
||||||
|
// Highlighting
|
||||||
|
em {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user