mirror of
https://github.com/facebook/docusaurus.git
synced 2025-07-08 20:37:53 +02:00
feat(v2): headerlinks (#1074)
* feat(v2): headerlinks * fix test * nits * remove tictactoe: * headerIcon * nits * remove lang dropdown * fix failing test * search box * algolia search * use babel-eslint to resolve dynamic import * nits * favicon and title * Update .eslintignore
This commit is contained in:
parent
d4458b394c
commit
85336649d3
66 changed files with 1205 additions and 2292 deletions
|
@ -21,12 +21,16 @@ export default class BlogPage extends React.Component {
|
|||
blogMetadatas,
|
||||
language,
|
||||
children,
|
||||
siteConfig,
|
||||
siteConfig = {},
|
||||
} = this.props;
|
||||
const {posts} = metadata;
|
||||
|
||||
const {baseUrl, favicon} = siteConfig;
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<Helmet defaultTitle={siteConfig.title}>
|
||||
<Helmet>
|
||||
<title>{'Blog'}</title>
|
||||
{favicon && <link rel="shortcut icon" href={baseUrl + favicon} />}
|
||||
{language && <html lang={language} />}
|
||||
{language && <meta name="docsearch:language" content={language} />}
|
||||
</Helmet>
|
||||
|
|
|
@ -80,11 +80,14 @@ export default class BlogPost extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {metadata, children, siteConfig} = this.props;
|
||||
const {language} = metadata;
|
||||
const {metadata, children, siteConfig = {}} = this.props;
|
||||
const {baseUrl, favicon} = siteConfig;
|
||||
const {language, title} = metadata;
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<Helmet defaultTitle={siteConfig.title}>
|
||||
{title && <title>{title}</title>}
|
||||
{favicon && <link rel="shortcut icon" href={baseUrl + favicon} />}
|
||||
{language && <html lang={language} />}
|
||||
</Helmet>
|
||||
{this.renderPostHeader()}
|
||||
|
|
|
@ -22,22 +22,30 @@ class Doc extends React.Component {
|
|||
const {
|
||||
docsMetadatas,
|
||||
docsSidebars,
|
||||
env,
|
||||
location,
|
||||
metadata,
|
||||
pagesMetadatas,
|
||||
siteConfig,
|
||||
siteConfig = {},
|
||||
route,
|
||||
} = this.props;
|
||||
const {language, version} = metadata;
|
||||
const {baseUrl, favicon} = siteConfig;
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>{(metadata && metadata.title) || siteConfig.title}</title>
|
||||
{favicon && <link rel="shortcut icon" href={baseUrl + favicon} />}
|
||||
{language && <html lang={language} />}
|
||||
{language && <meta name="docsearch:language" content={language} />}
|
||||
{version && <meta name="docsearch:version" content={version} />}
|
||||
</Helmet>
|
||||
<Navbar docsMetadatas={docsMetadatas} />
|
||||
<Navbar
|
||||
docsMetadatas={docsMetadatas}
|
||||
env={env}
|
||||
metadata={metadata}
|
||||
siteConfig={siteConfig}
|
||||
/>
|
||||
<Sidebar
|
||||
docsMetadatas={docsMetadatas}
|
||||
docsSidebars={docsSidebars}
|
||||
|
|
|
@ -19,11 +19,19 @@ export default class Layout extends React.Component {
|
|||
children,
|
||||
pagesMetadatas = [],
|
||||
docsMetadatas = {},
|
||||
env,
|
||||
siteConfig,
|
||||
location,
|
||||
metadata,
|
||||
} = this.props;
|
||||
return (
|
||||
<div>
|
||||
<Navbar docsMetadatas={docsMetadatas} />
|
||||
<Navbar
|
||||
docsMetadatas={docsMetadatas}
|
||||
env={env}
|
||||
metadata={metadata}
|
||||
siteConfig={siteConfig}
|
||||
/>
|
||||
{children}
|
||||
<Footer
|
||||
docsMetadatas={docsMetadatas}
|
||||
|
|
|
@ -1,64 +1,112 @@
|
|||
/**
|
||||
* 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 from 'react';
|
||||
import {NavLink} from 'react-router-dom';
|
||||
|
||||
import Search from '@theme/Search';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
function Navbar() {
|
||||
function Navbar(props) {
|
||||
const {siteConfig = {}, env = {}, metadata = {}, docsMetadatas = {}} = props;
|
||||
const {baseUrl, headerLinks, headerIcon, algolia} = siteConfig;
|
||||
const {language: thisLanguage, version: thisVersion} = metadata;
|
||||
|
||||
const translationEnabled = env.translation.enabled;
|
||||
const versioningEnabled = env.versioning.enabled;
|
||||
|
||||
// function to generate each header link
|
||||
const makeLinks = link => {
|
||||
if (link.search && algolia) {
|
||||
// return algolia search bar
|
||||
return (
|
||||
<li className={styles.navListItem} key="search-box">
|
||||
<Search {...props} />
|
||||
</li>
|
||||
);
|
||||
}
|
||||
if (link.languages) {
|
||||
// TODO in the future for <LanguageDropdown /> like in v1
|
||||
return null;
|
||||
}
|
||||
if (link.doc) {
|
||||
// set link to document with current page's language/version
|
||||
const langPart = translationEnabled ? `${thisLanguage}-` : '';
|
||||
const versionPart =
|
||||
versioningEnabled && thisVersion !== 'next'
|
||||
? `version-${thisVersion || env.versioning.defaultVersion}-`
|
||||
: '';
|
||||
const id = langPart + versionPart + link.doc;
|
||||
if (!docsMetadatas[id]) {
|
||||
const errorStr = `We could not find the doc wih id: ${id}. Please check your headerLinks correctly\n`;
|
||||
throw new Error(errorStr);
|
||||
}
|
||||
return (
|
||||
<li key={link.doc} className={styles.navListItem}>
|
||||
<NavLink
|
||||
activeClassName={styles.navLinkActive}
|
||||
className={styles.navLink}
|
||||
to={docsMetadatas[id].permalink}>
|
||||
{link.label}
|
||||
</NavLink>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
if (link.page) {
|
||||
// set link to page with current page's language if appropriate
|
||||
const pageHref = `${baseUrl}${thisLanguage ? `${thisLanguage}/` : ''}${
|
||||
link.page
|
||||
}`;
|
||||
return (
|
||||
<li key={link.page} className={styles.navListItem}>
|
||||
<NavLink
|
||||
activeClassName={styles.navLinkActive}
|
||||
className={styles.navLink}
|
||||
to={pageHref}>
|
||||
{link.label}
|
||||
</NavLink>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
if (link.href) {
|
||||
// set link to specified href
|
||||
return (
|
||||
<li key={link.label} className={styles.navListItem}>
|
||||
<a href={link.href} className={styles.navLink}>
|
||||
{link.label}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
if (link.blog) {
|
||||
// set link to blog url
|
||||
const blogUrl = `${baseUrl}blog`;
|
||||
return (
|
||||
<li key="Blog" className={styles.navListItem}>
|
||||
<NavLink
|
||||
activeClassName={styles.navLinkActive}
|
||||
className={styles.navLink}
|
||||
to={blogUrl}>
|
||||
Blog
|
||||
</NavLink>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<nav className={styles.navbar}>
|
||||
<div className={styles.navbarInner}>
|
||||
<ul className={styles.navList}>
|
||||
<li className={styles.navListItem}>
|
||||
<li key="logo" className={styles.navListItem}>
|
||||
<NavLink className={styles.navBrand} to="/">
|
||||
<img
|
||||
alt="Docusaurus Logo"
|
||||
className={styles.navLogo}
|
||||
src="/img/docusaurus-logo.svg"
|
||||
src={baseUrl + headerIcon}
|
||||
/>
|
||||
<strong>Docusaurus</strong>
|
||||
</NavLink>
|
||||
</li>
|
||||
<li className={styles.navListItem}>
|
||||
<NavLink
|
||||
activeClassName={styles.navLinkActive}
|
||||
className={styles.navLink}
|
||||
to="/docs/installation">
|
||||
Docs
|
||||
</NavLink>
|
||||
</li>
|
||||
<li className={styles.navListItem}>
|
||||
<NavLink
|
||||
activeClassName={styles.navLinkActive}
|
||||
className={styles.navLink}
|
||||
to="/blog">
|
||||
Blog
|
||||
</NavLink>
|
||||
</li>
|
||||
<li className={styles.navListItem}>
|
||||
<NavLink
|
||||
activeClassName={styles.navLinkActive}
|
||||
className={styles.navLink}
|
||||
to="https://github.com/facebook/docusaurus">
|
||||
GitHub
|
||||
</NavLink>
|
||||
</li>
|
||||
{/* Object.values(props.docsMetadatas).map(metadata => (
|
||||
<li key={metadata.permalink} className={styles.navListItem}>
|
||||
<NavLink
|
||||
activeClassName={styles.navLinkActive}
|
||||
className={styles.navLink}
|
||||
to={metadata.permalink}>
|
||||
{metadata.title}
|
||||
</NavLink>
|
||||
</li>
|
||||
)) */}
|
||||
{headerLinks.map(makeLinks)}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
|
|
@ -11,7 +11,7 @@ import Layout from '@theme/Layout';
|
|||
export default class NotFound extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Layout>
|
||||
<Layout {...this.props}>
|
||||
<div>404 Page Not Found</div>
|
||||
<div>
|
||||
<img
|
||||
|
|
|
@ -13,11 +13,13 @@ import Layout from '@theme/Layout'; // eslint-disable-line
|
|||
|
||||
export default class Pages extends React.Component {
|
||||
render() {
|
||||
const {metadata, children, siteConfig} = this.props;
|
||||
const {metadata, children, siteConfig = {}} = this.props;
|
||||
const {baseUrl, favicon} = siteConfig;
|
||||
const {language} = metadata;
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<Helmet defaultTitle={siteConfig.title}>
|
||||
{favicon && <link rel="shortcut icon" href={baseUrl + favicon} />}
|
||||
{language && <html lang={language} />}
|
||||
{language && <meta name="docsearch:language" content={language} />}
|
||||
</Helmet>
|
||||
|
|
61
v2/lib/theme/Search/index.js
Normal file
61
v2/lib/theme/Search/index.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* 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 from 'react';
|
||||
|
||||
import './styles.css';
|
||||
|
||||
class Search extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
enabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {siteConfig = {}, metadata = {}} = this.props;
|
||||
const {version: thisVersion, language: thisLanguage} = metadata;
|
||||
const {algolia} = siteConfig;
|
||||
|
||||
// https://github.com/algolia/docsearch/issues/352
|
||||
const isClient = typeof window !== 'undefined';
|
||||
if (isClient) {
|
||||
import('docsearch.js').then(({default: docsearch}) => {
|
||||
docsearch({
|
||||
appId: algolia.appId,
|
||||
apiKey: algolia.apiKey,
|
||||
indexName: algolia.indexName,
|
||||
inputSelector: '#search_input_react',
|
||||
algoliaOptions: JSON.parse(
|
||||
JSON.stringify(algolia.algoliaOptions)
|
||||
.replace('VERSION', thisVersion)
|
||||
.replace('LANGUAGE', thisLanguage),
|
||||
),
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.warn('Search has failed to load and now is being disabled');
|
||||
this.setState({enabled: false});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {enabled} = this.state;
|
||||
|
||||
return enabled ? (
|
||||
<input
|
||||
id="search_input_react"
|
||||
type="search"
|
||||
placeholder="Search docs"
|
||||
aria-label="Search docs"
|
||||
/>
|
||||
) : null;
|
||||
}
|
||||
}
|
||||
|
||||
export default Search;
|
535
v2/lib/theme/Search/styles.css
Normal file
535
v2/lib/theme/Search/styles.css
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue