Minor website fixes (#11974) [ci skip]

This commit is contained in:
Marcus Blättermann 2022-12-20 17:41:38 +01:00 committed by GitHub
parent de2e3747cc
commit fba63f5f09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 844 additions and 1250 deletions

View File

@ -78,6 +78,7 @@ bit of time.
```yaml ```yaml
├── docs # the actual markdown content ├── docs # the actual markdown content
├── meta # JSON-formatted site metadata ├── meta # JSON-formatted site metadata
| ├── dynamicMeta.js # At build time generated meta data
| ├── languages.json # supported languages and statistical models | ├── languages.json # supported languages and statistical models
| ├── sidebars.json # sidebar navigations for different sections | ├── sidebars.json # sidebar navigations for different sections
| ├── site.json # general site metadata | ├── site.json # general site metadata

View File

@ -105,11 +105,11 @@ representation.
## Attributes {#attributes} ## Attributes {#attributes}
| Name | Description | | Name | Description |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------- | | ------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `FEATURE_SEP` | The [FEATS](https://universaldependencies.org/format.html#morphological-annotation) feature separator. Default is ` | `. ~~str~~ | | `FEATURE_SEP` | The [FEATS](https://universaldependencies.org/format.html#morphological-annotation) feature separator. Default is `\|`. ~~str~~ |
| `FIELD_SEP` | The [FEATS](https://universaldependencies.org/format.html#morphological-annotation) field separator. Default is `=`. ~~str~~ | | `FIELD_SEP` | The [FEATS](https://universaldependencies.org/format.html#morphological-annotation) field separator. Default is `=`. ~~str~~ |
| `VALUE_SEP` | The [FEATS](https://universaldependencies.org/format.html#morphological-annotation) value separator. Default is `,`. ~~str~~ | | `VALUE_SEP` | The [FEATS](https://universaldependencies.org/format.html#morphological-annotation) value separator. Default is `,`. ~~str~~ |
## MorphAnalysis {#morphanalysis tag="class" source="spacy/tokens/morphanalysis.pyx"} ## MorphAnalysis {#morphanalysis tag="class" source="spacy/tokens/morphanalysis.pyx"}

View File

@ -38,8 +38,8 @@ how the component should be configured. You can override its settings via the
> ``` > ```
| Setting | Description | | Setting | Description |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `punct_chars` | Optional custom list of punctuation characters that mark sentence ends. See below for defaults if not set. Defaults to `None`. ~~Optional[List[str]]~~ | `None` | | `punct_chars` | Optional custom list of punctuation characters that mark sentence ends. See below for defaults if not set. Defaults to `None`. ~~Optional[List[str]]~~ |
| `overwrite` <Tag variant="new">3.2</Tag> | Whether existing annotation is overwritten. Defaults to `False`. ~~bool~~ | | `overwrite` <Tag variant="new">3.2</Tag> | Whether existing annotation is overwritten. Defaults to `False`. ~~bool~~ |
| `scorer` <Tag variant="new">3.2</Tag> | The scoring method. Defaults to [`Scorer.score_spans`](/api/scorer#score_spans) for the attribute `"sents"` ~~Optional[Callable]~~ | | `scorer` <Tag variant="new">3.2</Tag> | The scoring method. Defaults to [`Scorer.score_spans`](/api/scorer#score_spans) for the attribute `"sents"` ~~Optional[Callable]~~ |

View File

@ -101,7 +101,7 @@ Check whether an extension has been registered on the `Token` class.
| `name` | Name of the extension to check. ~~str~~ | | `name` | Name of the extension to check. ~~str~~ |
| **RETURNS** | Whether the extension has been registered. ~~bool~~ | | **RETURNS** | Whether the extension has been registered. ~~bool~~ |
## Token.remove_extension {#remove_extension tag="classmethod" new=""2.0.11""} ## Token.remove_extension {#remove_extension tag="classmethod" new="2.0.11"}
Remove a previously registered extension. Remove a previously registered extension.

View File

@ -65,16 +65,7 @@ import { Colors, Patterns } from 'widgets/styleguide'
## Typography {#typography} ## Typography {#typography}
import { import { H1, H2, H3, H4, H5, Label, InlineList } from 'components/typography'
H1,
H2,
H3,
H4,
H5,
Label,
InlineList,
Comment,
} from 'components/typography'
> #### Markdown > #### Markdown
> >

View File

@ -13,16 +13,11 @@ const codeBlocksPlugin = require('./src/plugins/remark-code-blocks.js')
// Import metadata // Import metadata
const site = require('./meta/site.json') const site = require('./meta/site.json')
const sidebars = require('./meta/sidebars.json') const { domain, nightly: isNightly, legacy: isLegacy } = site
const models = require('./meta/languages.json') const { siteUrl } = require('./meta/dynamicMeta')
const universe = require('./meta/universe.json')
const DEFAULT_TEMPLATE = path.resolve('./src/templates/index.js') const DEFAULT_TEMPLATE = path.resolve('./src/templates/index.js')
const domain = process.env.BRANCH || site.domain
const siteUrl = `https://${domain}`
const isNightly = site.nightlyBranches.includes(domain)
const isLegacy = site.legacy || !!+process.env.SPACY_LEGACY
const favicon = `src/images/icon${isNightly ? '_nightly' : isLegacy ? '_legacy' : ''}.png` const favicon = `src/images/icon${isNightly ? '_nightly' : isLegacy ? '_legacy' : ''}.png`
const branch = isNightly ? 'develop' : 'master' const branch = isNightly ? 'develop' : 'master'
@ -34,30 +29,11 @@ const replacements = {
SPACY_PKG_FLAGS: isNightly ? ' --pre' : '', SPACY_PKG_FLAGS: isNightly ? ' --pre' : '',
} }
/**
* Compute the overall total counts of models and languages
*/
function getCounts(langs = []) {
return {
langs: langs.length,
modelLangs: langs.filter(({ models }) => models && !!models.length).length,
models: langs.map(({ models }) => (models ? models.length : 0)).reduce((a, b) => a + b, 0),
}
}
module.exports = { module.exports = {
siteMetadata: { siteMetadata: {
...site, ...site,
sidebars,
...models,
counts: getCounts(models.languages),
universe,
nightly: isNightly,
legacy: isLegacy,
binderBranch: domain,
siteUrl, siteUrl,
}, },
plugins: [ plugins: [
{ {
resolve: `gatsby-plugin-sass`, resolve: `gatsby-plugin-sass`,

View File

@ -4,6 +4,9 @@ const { createFilePath } = require('gatsby-source-filesystem')
const DEFAULT_TEMPLATE = path.resolve('./src/templates/index.js') const DEFAULT_TEMPLATE = path.resolve('./src/templates/index.js')
const BASE_PATH = 'docs' const BASE_PATH = 'docs'
const PAGE_EXTENSIONS = ['.md', '.mdx'] const PAGE_EXTENSIONS = ['.md', '.mdx']
const siteMetadata = require('./meta/site.json')
const universe = require('./meta/universe.json')
const models = require('./meta/languages.json')
function replacePath(pagePath) { function replacePath(pagePath) {
return pagePath === `/` ? pagePath : pagePath.replace(/\/$/, ``) return pagePath === `/` ? pagePath : pagePath.replace(/\/$/, ``)
@ -26,37 +29,6 @@ exports.createPages = ({ graphql, actions }) => {
graphql( graphql(
` `
{ {
site {
siteMetadata {
sections {
id
title
theme
}
languages {
code
name
models
example
has_examples
}
universe {
resources {
id
title
slogan
}
categories {
label
items {
id
title
description
}
}
}
}
}
allFile(filter: { ext: { in: [".md", ".mdx"] } }) { allFile(filter: { ext: { in: [".md", ".mdx"] } }) {
edges { edges {
node { node {
@ -107,8 +79,10 @@ exports.createPages = ({ graphql, actions }) => {
reject(result.errors) reject(result.errors)
} }
const sectionData = result.data.site.siteMetadata.sections const sections = Object.assign(
const sections = Object.assign({}, ...sectionData.map((s) => ({ [s.id]: s }))) {},
...siteMetadata.sections.map((s) => ({ [s.id]: s }))
)
/* Regular pages */ /* Regular pages */
@ -183,8 +157,8 @@ exports.createPages = ({ graphql, actions }) => {
}, },
}) })
const universe = result.data.site.siteMetadata.universe.resources const universeResources = universe.resources
universe.forEach((page) => { universeResources.forEach((page) => {
const slug = `/universe/project/${page.id}` const slug = `/universe/project/${page.id}`
createPage({ createPage({
@ -202,7 +176,7 @@ exports.createPages = ({ graphql, actions }) => {
}) })
}) })
const universeCategories = result.data.site.siteMetadata.universe.categories const universeCategories = universe.categories
const categories = [].concat.apply( const categories = [].concat.apply(
[], [],
universeCategories.map((cat) => cat.items) universeCategories.map((cat) => cat.items)
@ -227,7 +201,7 @@ exports.createPages = ({ graphql, actions }) => {
/* Models */ /* Models */
const langs = result.data.site.siteMetadata.languages const langs = models.languages
const modelLangs = langs.filter(({ models }) => models && models.length) const modelLangs = langs.filter(({ models }) => models && models.length)
modelLangs.forEach(({ code, name, models, example, has_examples }, i) => { modelLangs.forEach(({ code, name, models, example, has_examples }, i) => {
const slug = `/models/${code}` const slug = `/models/${code}`

View File

@ -0,0 +1,11 @@
const site = require('./site.json')
const domain = process.env.BRANCH || site.domain
module.exports = {
domain,
siteUrl: `https://${domain}`,
nightly: site.nightlyBranches.includes(domain),
legacy: site.legacy || !!+process.env.SPACY_LEGACY,
binderBranch: domain,
}

View File

@ -27,7 +27,6 @@
"indexName": "spacy" "indexName": "spacy"
}, },
"binderUrl": "explosion/spacy-io-binder", "binderUrl": "explosion/spacy-io-binder",
"binderBranch": "spacy.io",
"binderVersion": "3.4", "binderVersion": "3.4",
"sections": [ "sections": [
{ "id": "usage", "title": "Usage Documentation", "theme": "blue" }, { "id": "usage", "title": "Usage Documentation", "theme": "blue" },

View File

@ -1 +1 @@
3.7 3.8

View File

@ -17,7 +17,7 @@ export default function Accordion({ title, id, expanded = false, spaced = false,
[classes.hidden]: isExpanded, [classes.hidden]: isExpanded,
}) })
// Make sure accordion is expanded if JS is disabled // Make sure accordion is expanded if JS is disabled
useEffect(() => setIsExpanded(expanded), []) useEffect(() => setIsExpanded(expanded), [expanded])
return ( return (
<section className="accordion" id={id}> <section className="accordion" id={id}>
<div className={rootClassNames}> <div className={rootClassNames}>

View File

@ -4,7 +4,6 @@ import classNames from 'classnames'
import highlightCode from 'gatsby-remark-prismjs/highlight-code.js' import highlightCode from 'gatsby-remark-prismjs/highlight-code.js'
import 'prismjs-bibtex' import 'prismjs-bibtex'
import rangeParser from 'parse-numeric-range' import rangeParser from 'parse-numeric-range'
import { StaticQuery, graphql } from 'gatsby'
import { window } from 'browser-monads' import { window } from 'browser-monads'
import CUSTOM_TYPES from '../../meta/type-annotations.json' import CUSTOM_TYPES from '../../meta/type-annotations.json'
@ -12,16 +11,20 @@ import { isString, htmlToReact } from './util'
import Link, { OptionalLink } from './link' import Link, { OptionalLink } from './link'
import GitHubCode from './github' import GitHubCode from './github'
import classes from '../styles/code.module.sass' import classes from '../styles/code.module.sass'
import siteMetadata from '../../meta/site.json'
import { binderBranch } from '../../meta/dynamicMeta'
const WRAP_THRESHOLD = 30 const WRAP_THRESHOLD = 30
const CLI_GROUPS = ['init', 'debug', 'project', 'ray', 'huggingface-hub'] const CLI_GROUPS = ['init', 'debug', 'project', 'ray', 'huggingface-hub']
export default (props) => ( const CodeBlock = (props) => (
<Pre> <Pre>
<Code {...props} /> <Code {...props} />
</Pre> </Pre>
) )
export default CodeBlock
export const Pre = (props) => { export const Pre = (props) => {
return <pre className={classes.pre}>{props.children}</pre> return <pre className={classes.pre}>{props.children}</pre>
} }
@ -172,7 +175,7 @@ function formatCode(html, lang, prompt) {
.split(' | ') .split(' | ')
.map((l, i) => convertLine(l, i)) .map((l, i) => convertLine(l, i))
.map((l, j) => ( .map((l, j) => (
<Fragment> <Fragment key={j}>
{j !== 0 && <span> | </span>} {j !== 0 && <span> | </span>}
{l} {l}
</Fragment> </Fragment>
@ -268,51 +271,34 @@ export class Code extends React.Component {
} }
} }
const JuniperWrapper = ({ Juniper, title, lang, children }) => ( const JuniperWrapper = ({ Juniper, title, lang, children }) => {
<StaticQuery const { binderUrl, binderVersion } = siteMetadata
query={query} const juniperTitle = title || 'Editable Code'
render={(data) => { return (
const { binderUrl, binderBranch, binderVersion } = data.site.siteMetadata <div className={classes.juniperWrapper}>
const juniperTitle = title || 'Editable Code' <h4 className={classes.juniperTitle}>
return ( {juniperTitle}
<div className={classes.juniperWrapper}> <span className={classes.juniperMeta}>
<h4 className={classes.juniperTitle}> spaCy v{binderVersion} &middot; Python 3 &middot; via{' '}
{juniperTitle} <Link to="https://mybinder.org/" hidden>
<span className={classes.juniperMeta}> Binder
spaCy v{binderVersion} &middot; Python 3 &middot; via{' '} </Link>
<Link to="https://mybinder.org/" hidden> </span>
Binder </h4>
</Link>
</span>
</h4>
<Juniper <Juniper
repo={binderUrl} repo={binderUrl}
branch={binderBranch} branch={binderBranch}
lang={lang} lang={lang}
classNames={{ classNames={{
cell: classes.juniperCell, cell: classes.juniperCell,
input: classes.juniperInput, input: classes.juniperInput,
button: classes.juniperButton, button: classes.juniperButton,
output: classes.juniperOutput, output: classes.juniperOutput,
}} }}
> >
{children} {children}
</Juniper> </Juniper>
</div> </div>
) )
}} }
/>
)
const query = graphql`
query JuniperQuery {
site {
siteMetadata {
binderUrl
binderBranch
binderVersion
}
}
}
`

View File

@ -1,6 +1,5 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { StaticQuery, graphql } from 'gatsby'
import classNames from 'classnames' import classNames from 'classnames'
import Link from './link' import Link from './link'
@ -8,89 +7,55 @@ import Grid from './grid'
import Newsletter from './newsletter' import Newsletter from './newsletter'
import ExplosionLogo from '-!svg-react-loader!../images/explosion.svg' import ExplosionLogo from '-!svg-react-loader!../images/explosion.svg'
import classes from '../styles/footer.module.sass' import classes from '../styles/footer.module.sass'
import siteMetadata from '../../meta/site.json'
export default function Footer({ wide = false }) { export default function Footer({ wide = false }) {
const { companyUrl, company, footer, newsletter } = siteMetadata
return ( return (
<StaticQuery <footer className={classes.root}>
query={query} <Grid cols={wide ? 4 : 3} narrow className={classes.content}>
render={(data) => { {footer.map(({ label, items }, i) => (
const { companyUrl, company, footer, newsletter } = data.site.siteMetadata <section key={i}>
return ( <ul className={classes.column}>
<footer className={classes.root}> <li className={classes.label}>{label}</li>
<Grid cols={wide ? 4 : 3} narrow className={classes.content}> {items.map(({ text, url }, j) => (
{footer.map(({ label, items }, i) => ( <li key={j}>
<section key={i}> <Link to={url} hidden>
<ul className={classes.column}> {text}
<li className={classes.label}>{label}</li> </Link>
{items.map(({ text, url }, j) => ( </li>
<li key={j}>
<Link to={url} hidden>
{text}
</Link>
</li>
))}
</ul>
</section>
))} ))}
<section className={wide ? null : classes.full}> </ul>
<ul className={classes.column}> </section>
<li className={classes.label}>Stay in the loop!</li> ))}
<li>Receive updates about new releases, tutorials and more.</li> <section className={wide ? null : classes.full}>
<li> <ul className={classes.column}>
<Newsletter {...newsletter} /> <li className={classes.label}>Stay in the loop!</li>
</li> <li>Receive updates about new releases, tutorials and more.</li>
</ul> <li>
</section> <Newsletter {...newsletter} />
</Grid> </li>
<div className={classNames(classes.content, classes.copy)}> </ul>
<span> </section>
&copy; 2016-{new Date().getFullYear()}{' '} </Grid>
<Link to={companyUrl} hidden> <div className={classNames(classes.content, classes.copy)}>
{company} <span>
</Link> &copy; 2016-{new Date().getFullYear()}{' '}
</span> <Link to={companyUrl} hidden>
<Link {company}
to={companyUrl} </Link>
aria-label={company} </span>
hidden <Link to={companyUrl} aria-label={company} hidden className={classes.logo}>
className={classes.logo} <ExplosionLogo width={45} height={45} />
> </Link>
<ExplosionLogo width={45} height={45} /> <Link to={`${companyUrl}/legal`} hidden>
</Link> Legal / Imprint
<Link to={`${companyUrl}/legal`} hidden> </Link>
Legal / Imprint </div>
</Link> </footer>
</div>
</footer>
)
}}
/>
) )
} }
Footer.propTypes = { Footer.propTypes = {
wide: PropTypes.bool, wide: PropTypes.bool,
} }
const query = graphql`
query FooterQuery {
site {
siteMetadata {
company
companyUrl
footer {
label
items {
text
url
}
}
newsletter {
user
id
list
}
}
}
}
`

View File

@ -29,7 +29,7 @@ export default function Infobox({
{variant !== 'default' && !emoji && ( {variant !== 'default' && !emoji && (
<Icon width={18} name={variant} inline className={classes.icon} /> <Icon width={18} name={variant} inline className={classes.icon} />
)} )}
<span className={classes.titleText}> <span>
{emoji && ( {emoji && (
<span className={classes.emoji} aria-hidden="true"> <span className={classes.emoji} aria-hidden="true">
{emoji} {emoji}

View File

@ -53,7 +53,7 @@ export const LandingGrid = ({ cols = 3, blocks = false, style, children }) => (
</Content> </Content>
) )
export const LandingCol = ({ children }) => <div className={classes.col}>{children}</div> export const LandingCol = ({ children }) => <div>{children}</div>
export const LandingCard = ({ title, button, url, children }) => ( export const LandingCard = ({ title, button, url, children }) => (
<div className={classes.card}> <div className={classes.card}>

View File

@ -78,10 +78,10 @@ export default function Link({
) )
} }
const isInternal = internalRegex.test(dest) const isInternal = internalRegex.test(dest)
const rel = isInternal ? null : 'noopener nofollow noreferrer' const relTarget = isInternal ? {} : { rel: 'noopener nofollow noreferrer', target: '_blank' }
return ( return (
<Wrapper> <Wrapper>
<a href={dest} className={linkClassNames} target="_blank" rel={rel} {...other}> <a href={dest} className={linkClassNames} {...relTarget} {...other}>
{content} {content}
</a> </a>
</Wrapper> </Wrapper>

View File

@ -152,10 +152,7 @@ const Quickstart = ({
type={optionType} type={optionType}
className={classNames( className={classNames(
classes.input, classes.input,
classes[optionType], classes[optionType]
{
[classes.long]: options.length >= 4,
}
)} )}
name={id} name={id}
id={`quickstart-${option.id}`} id={`quickstart-${option.id}`}
@ -167,11 +164,7 @@ const Quickstart = ({
htmlFor={`quickstart-${option.id}`} htmlFor={`quickstart-${option.id}`}
> >
{option.title} {option.title}
{option.meta && ( {option.meta && <span>{option.meta}</span>}
<span className={classes.meta}>
{option.meta}
</span>
)}
{option.help && ( {option.help && (
<span <span
data-tooltip={option.help} data-tooltip={option.help}

View File

@ -1,13 +1,14 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Helmet from 'react-helmet' import Helmet from 'react-helmet'
import { StaticQuery, graphql } from 'gatsby'
import socialImageDefault from '../images/social_default.jpg' import socialImageDefault from '../images/social_default.jpg'
import socialImageApi from '../images/social_api.jpg' import socialImageApi from '../images/social_api.jpg'
import socialImageUniverse from '../images/social_universe.jpg' import socialImageUniverse from '../images/social_universe.jpg'
import socialImageNightly from '../images/social_nightly.jpg' import socialImageNightly from '../images/social_nightly.jpg'
import socialImageLegacy from '../images/social_legacy.jpg' import socialImageLegacy from '../images/social_legacy.jpg'
import siteMetadata from '../../meta/site.json'
import { siteUrl } from '../../meta/dynamicMeta'
function getPageTitle(title, sitename, slogan, sectionTitle, nightly, legacy) { function getPageTitle(title, sitename, slogan, sectionTitle, nightly, legacy) {
if (sectionTitle && title) { if (sectionTitle && title) {
@ -38,86 +39,78 @@ export default function SEO({
nightly, nightly,
legacy, legacy,
}) { }) {
return ( const metaDescription = description || siteMetadata.description
<StaticQuery const pageTitle = getPageTitle(
query={query} title,
render={(data) => { siteMetadata.title,
const siteMetadata = data.site.siteMetadata siteMetadata.slogan,
const metaDescription = description || siteMetadata.description sectionTitle,
const pageTitle = getPageTitle( nightly,
title, legacy
siteMetadata.title, )
siteMetadata.slogan, const socialImage = siteUrl + getImage(section, nightly, legacy)
sectionTitle, const meta = [
nightly, {
legacy name: 'description',
) content: metaDescription,
const socialImage = siteMetadata.siteUrl + getImage(section, nightly, legacy) },
const meta = [ {
{ property: 'og:title',
name: 'description', content: pageTitle,
content: metaDescription, },
}, {
{ property: 'og:description',
property: 'og:title', content: metaDescription,
content: pageTitle, },
}, {
{ property: 'og:type',
property: 'og:description', content: `website`,
content: metaDescription, },
}, {
{ property: 'og:site_name',
property: 'og:type', content: title,
content: `website`, },
}, {
{ property: 'og:image',
property: 'og:site_name', content: socialImage,
content: title, },
}, {
{ name: 'twitter:card',
property: 'og:image', content: 'summary_large_image',
content: socialImage, },
}, {
{ name: 'twitter:image',
name: 'twitter:card', content: socialImage,
content: 'summary_large_image', },
}, {
{ name: 'twitter:creator',
name: 'twitter:image', content: `@${siteMetadata.social.twitter}`,
content: socialImage, },
}, {
{ name: 'twitter:site',
name: 'twitter:creator', content: `@${siteMetadata.social.twitter}`,
content: `@${siteMetadata.social.twitter}`, },
}, {
{ name: 'twitter:title',
name: 'twitter:site', content: pageTitle,
content: `@${siteMetadata.social.twitter}`, },
}, {
{ name: 'twitter:description',
name: 'twitter:title', content: metaDescription,
content: pageTitle, },
}, {
{ name: 'docsearch:language',
name: 'twitter:description', content: lang,
content: metaDescription, },
}, ]
{
name: 'docsearch:language',
content: lang,
},
]
return ( return (
<Helmet <Helmet
defer={false} defer={false}
htmlAttributes={{ lang }} htmlAttributes={{ lang }}
bodyAttributes={{ class: bodyClass }} bodyAttributes={{ class: bodyClass }}
title={pageTitle} title={pageTitle}
meta={meta} meta={meta}
/>
)
}}
/> />
) )
} }
@ -131,19 +124,3 @@ SEO.propTypes = {
section: PropTypes.string, section: PropTypes.string,
bodyClass: PropTypes.string, bodyClass: PropTypes.string,
} }
const query = graphql`
query DefaultSEOQuery {
site {
siteMetadata {
title
description
slogan
siteUrl
social {
twitter
}
}
}
}
`

View File

@ -70,12 +70,6 @@ export const Help = ({ children, className, size = 16 }) => (
</span> </span>
) )
/**
* Allows inserting comments that will appear in .md preview on GitHub, but
* won't be included in the final build of the site.
*/
export const Comment = () => null
const Permalink = ({ id, children }) => const Permalink = ({ id, children }) =>
!id ? ( !id ? (
<span className={headingTextClassName}>{children}</span> <span className={headingTextClassName}>{children}</span>

View File

@ -3,10 +3,11 @@ import { Parser as HtmlToReactParser } from 'html-to-react'
import remark from 'remark' import remark from 'remark'
import remark2react from 'remark-react' import remark2react from 'remark-react'
import siteMetadata from '../../meta/site.json' import siteMetadata from '../../meta/site.json'
import { domain } from '../../meta/dynamicMeta'
const htmlToReactParser = new HtmlToReactParser() const htmlToReactParser = new HtmlToReactParser()
const isNightly = siteMetadata.nightlyBranches.includes(siteMetadata.domain) const isNightly = siteMetadata.nightlyBranches.includes(domain)
export const DEFAULT_BRANCH = isNightly ? 'develop' : 'master' export const DEFAULT_BRANCH = isNightly ? 'develop' : 'master'
export const repo = siteMetadata.repo export const repo = siteMetadata.repo
export const modelsRepo = siteMetadata.modelsRepo export const modelsRepo = siteMetadata.modelsRepo

View File

@ -1,16 +1,15 @@
import React from 'react' import React from 'react'
import { window } from 'browser-monads' import { window } from 'browser-monads'
import { graphql } from 'gatsby'
import Template from '../templates/index' import Template from '../templates/index'
import { LandingHeader, LandingTitle } from '../components/landing' import { LandingHeader, LandingTitle } from '../components/landing'
import Button from '../components/button' import Button from '../components/button'
import { nightly, legacy } from '../../meta/dynamicMeta'
export default ({ data, location }) => { const page404 = ({ location }) => {
const { nightly, legacy } = data.site.siteMetadata
const pageContext = { title: '404 Error', searchExclude: true, isIndex: false } const pageContext = { title: '404 Error', searchExclude: true, isIndex: false }
return ( return (
<Template data={data} pageContext={pageContext} location={location}> <Template pageContext={pageContext} location={location}>
<LandingHeader style={{ minHeight: 400 }} nightly={nightly} legacy={legacy}> <LandingHeader style={{ minHeight: 400 }} nightly={nightly} legacy={legacy}>
<LandingTitle> <LandingTitle>
Ooops, this page Ooops, this page
@ -26,24 +25,4 @@ export default ({ data, location }) => {
) )
} }
export const pageQuery = graphql` export default page404
query {
site {
siteMetadata {
nightly
legacy
title
description
navigation {
text
url
}
docSearch {
apiKey
indexName
appId
}
}
}
}
`

61
website/src/remark.js Normal file
View File

@ -0,0 +1,61 @@
import Link from './components/link'
import Section, { Hr } from './components/section'
import { Table, Tr, Th, Tx, Td } from './components/table'
import { Pre, Code, InlineCode, TypeAnnotation } from './components/code'
import { Ol, Ul, Li } from './components/list'
import { H2, H3, H4, H5, P, Abbr, Help } from './components/typography'
import Accordion from './components/accordion'
import Infobox from './components/infobox'
import Aside from './components/aside'
import Button from './components/button'
import Tag from './components/tag'
import Grid from './components/grid'
import { YouTube, SoundCloud, Iframe, Image, GoogleSheet } from './components/embed'
import Project from './widgets/project'
import { Integration, IntegrationLogo } from './widgets/integration'
export const remarkComponents = {
a: Link,
p: P,
pre: Pre,
code: Code,
inlineCode: InlineCode,
del: TypeAnnotation,
table: Table,
img: Image,
tr: Tr,
th: Th,
td: Td,
ol: Ol,
ul: Ul,
li: Li,
h2: H2,
h3: H3,
h4: H4,
h5: H5,
blockquote: Aside,
section: Section,
wrapper: ({ children }) => children,
hr: Hr,
Infobox,
Table,
Tr,
Tx,
Th,
Td,
Help,
Button,
YouTube,
SoundCloud,
Iframe,
GoogleSheet,
Abbr,
Tag,
Accordion,
Grid,
InlineCode,
Project,
Integration,
IntegrationLogo,
}

View File

@ -1,3 +1,4 @@
@use 'sass:math'
@import base @import base
$triangle-size: 2rem $triangle-size: 2rem
@ -55,14 +56,14 @@ $border-radius: 6px
// Banner effect // Banner effect
&:after &:after
position: absolute position: absolute
bottom: -$triangle-size / 2 bottom: math.div(-$triangle-size, 2)
left: $border-radius / 2 left: math.div($border-radius, 2)
width: 0 width: 0
height: 0 height: 0
border-color: transparent border-color: transparent
border-style: solid border-style: solid
border-top-color: var(--color-dark) border-top-color: var(--color-dark)
border-width: $triangle-size / 2 0 0 calc(#{$triangle-size} - #{$border-radius / 2}) border-width: math.div($triangle-size, 2) 0 0 calc(#{$triangle-size} - #{math.div($border-radius, 2)})
content: "" content: ""
@include breakpoint(max, sm) @include breakpoint(max, sm)

View File

@ -56,7 +56,7 @@
--color-inline-code-text: var(--color-back) --color-inline-code-text: var(--color-back)
--color-inline-code-bg: var(--color-dark-secondary) --color-inline-code-bg: var(--color-dark-secondary)
.type-annotation, .type-annotation
white-space: pre-wrap white-space: pre-wrap
font-family: var(--font-code) font-family: var(--font-code)

View File

@ -1,3 +1,5 @@
@use 'sass:math'
.root .root
margin-bottom: var(--spacing-md) margin-bottom: var(--spacing-md)
@ -6,8 +8,8 @@
height: 0 height: 0
@each $ratio1, $ratio2 in (16, 9), (4, 3) @each $ratio1, $ratio2 in (16, 9), (4, 3)
&.ratio#{$ratio1}x#{$ratio2} .ratio#{$ratio1}x#{$ratio2}
padding-bottom: (100% * $ratio2 / $ratio1) padding-bottom: (100% * math.div($ratio2, $ratio1))
.iframe .iframe
position: absolute position: absolute

View File

@ -1,3 +1,4 @@
@use 'sass:math'
@import base @import base
$grid-gap-wide: 5rem $grid-gap-wide: 5rem
@ -9,7 +10,7 @@ $flex-gap: 2rem
@if $gap == 0 @if $gap == 0
flex: 0 0 100% / $cols flex: 0 0 100% / $cols
@else @else
flex: 0 0 calc(#{100% / $cols} - #{$gap * ($cols - 1)}) flex: 0 0 calc(#{math.div(100%, $cols)} - #{$gap * ($cols - 1)})
.root .root
display: flex display: flex

View File

@ -546,3 +546,34 @@ body [id]:target
code, a code, a
color: inherit color: inherit
/* Algolia DocSearch */
@include breakpoint(max, xs)
.algolia-autocomplete .ds-dropdown-menu
max-width: 90vw !important
min-width: 90vw !important
.algolia-autocomplete .algolia-docsearch-suggestion--category-header
display: block
font: bold var(--font-size-lg)/var(--line-height-md) var(--font-secondary)
text-transform: uppercase
color: var(--color-theme)
.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column
color: var(--color-dark)
.algolia-autocomplete .algolia-docsearch-suggestion--title
font-size: var(--font-size-sm)
.algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content
background: var(--color-subtle-opaque) !important
.algolia-autocomplete .algolia-docsearch-suggestion--text
font-size: var(--font-size-sm)
.algolia-autocomplete .algolia-docsearch-suggestion--highlight
box-shadow: none !important
background: var(--color-theme-opaque) !important
color: var(--color-theme-dark) !important

View File

@ -1,3 +1,4 @@
@use 'sass:math'
@import base @import base
.root .root
@ -45,7 +46,7 @@
&:hover &:hover
background: var(--color-subtle-light) background: var(--color-subtle-light)
.input:focus + .input:focus
border: 1px solid var(--color-theme) border: 1px solid var(--color-theme)
outline: none outline: none
@ -82,14 +83,14 @@
vertical-align: middle vertical-align: middle
margin-right: 0.5rem margin-right: 0.5rem
cursor: pointer cursor: pointer
border-radius: $size / 4 border-radius: math.div($size, 4)
background: var(--color-back) background: var(--color-back)
position: relative position: relative
top: -1px top: -1px
.checkbox:checked + &:before .checkbox:checked + &:before
// Embed "check" icon here for simplicity // Embed "check" icon here for simplicity
background: var(--color-theme) url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij4gICAgPHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkgMTYuMTcybDEwLjU5NC0xMC41OTQgMS40MDYgMS40MDYtMTIgMTItNS41NzgtNS41NzggMS40MDYtMS40MDZ6Ii8+PC9zdmc+); background: var(--color-theme) url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij4gICAgPHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkgMTYuMTcybDEwLjU5NC0xMC41OTQgMS40MDYgMS40MDYtMTIgMTItNS41NzgtNS41NzggMS40MDYtMS40MDZ6Ii8+PC9zdmc+)
background-size: contain background-size: contain
border-color: var(--color-theme) border-color: var(--color-theme)

View File

@ -26,33 +26,3 @@
top: 0.25rem top: 0.25rem
left: 0.15rem left: 0.15rem
cursor: pointer cursor: pointer
/* Algolia DocSearch */
@include breakpoint(max, xs)
\:global(.algolia-autocomplete .ds-dropdown-menu)
max-width: 90vw !important
min-width: 90vw !important
\:global(.algolia-autocomplete .algolia-docsearch-suggestion--category-header)
display: block
font: bold var(--font-size-lg)/var(--line-height-md) var(--font-secondary)
text-transform: uppercase
color: var(--color-theme)
\:global(.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column)
color: var(--color-dark)
\:global(.algolia-autocomplete .algolia-docsearch-suggestion--title)
font-size: var(--font-size-sm)
\:global(.algolia-autocomplete .ds-dropdown-menu .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content)
background: var(--color-subtle-opaque) !important
\:global(.algolia-autocomplete .algolia-docsearch-suggestion--text)
font-size: var(--font-size-sm)
\:global(.algolia-autocomplete .algolia-docsearch-suggestion--highlight)
box-shadow: none !important
background: var(--color-theme-opaque) !important
color: var(--color-theme-dark) !important

View File

@ -1,3 +1,4 @@
@use 'sass:math'
@import base @import base
$crumb-bullet: 14px $crumb-bullet: 14px
@ -58,7 +59,7 @@ $crumb-bar: 2px
position: relative position: relative
.crumb .crumb
margin-bottom: $crumb-bullet / 2 margin-bottom: math.div($crumb-bullet, 2)
position: relative position: relative
padding-left: 2rem padding-left: 2rem
color: var(--color-theme) color: var(--color-theme)
@ -71,7 +72,7 @@ $crumb-bar: 2px
width: $crumb-bullet width: $crumb-bullet
height: $crumb-bullet height: $crumb-bullet
position: absolute position: absolute
top: $crumb-bullet / 4 top: math.div($crumb-bullet, 4)
left: 0 left: 0
content: "" content: ""
border-radius: 50% border-radius: 50%
@ -83,13 +84,13 @@ $crumb-bar: 2px
height: 100% height: 100%
position: absolute position: absolute
top: $crumb-bullet top: $crumb-bullet
left: ($crumb-bullet - $crumb-bar) / 2 left: math.div(($crumb-bullet - $crumb-bar), 2)
content: "" content: ""
background: var(--color-subtle) background: var(--color-subtle)
&:first-child:before &:first-child:before
height: calc(100% + #{$crumb-bullet * 2}) height: calc(100% + #{$crumb-bullet * 2})
top: -$crumb-bullet / 2 top: math.div(-$crumb-bullet, 2)
.crumb-active .crumb-active
color: var(--color-dark) color: var(--color-dark)

View File

@ -1,6 +1,5 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { StaticQuery, graphql } from 'gatsby'
import Models from './models' import Models from './models'
@ -13,98 +12,99 @@ import Sidebar from '../components/sidebar'
import Main from '../components/main' import Main from '../components/main'
import { getCurrentSource, github } from '../components/util' import { getCurrentSource, github } from '../components/util'
const Docs = ({ pageContext, children }) => ( import siteMetadata from '../../meta/site.json'
<StaticQuery import sidebars from '../../meta/sidebars.json'
query={query} import models from '../../meta/languages.json'
render={({ site }) => { import { nightly, legacy } from '../../meta/dynamicMeta'
const {
id,
slug,
title,
section,
teaser,
source,
tag,
isIndex,
next,
menu,
theme,
version,
apiDetails,
} = pageContext
const { sidebars = [], modelsRepo, languages, nightly, legacy } = site.siteMetadata
const isModels = section === 'models'
const sidebar = pageContext.sidebar
? { items: pageContext.sidebar }
: sidebars.find((bar) => bar.section === section)
let pageMenu = menu ? menu.map(([text, id]) => ({ text, id })) : []
if (isModels) { const Docs = ({ pageContext, children }) => {
sidebar.items[1].items = languages const {
.filter(({ models }) => models && models.length) id,
.sort((a, b) => a.name.localeCompare(b.name)) slug,
.map((lang) => ({ title,
text: lang.name, section,
url: `/models/${lang.code}`, teaser,
isActive: id === lang.code, source,
menu: lang.models.map((model) => ({ tag,
text: model, isIndex,
id: model, next,
})), menu,
})) theme,
} version,
const sourcePath = source ? github(source) : null apiDetails,
const currentSource = getCurrentSource(slug, isIndex) } = pageContext
const { modelsRepo } = siteMetadata
const { languages } = models
const isModels = section === 'models'
const sidebar = pageContext.sidebar
? { items: pageContext.sidebar }
: sidebars.find((bar) => bar.section === section)
let pageMenu = menu ? menu.map(([text, id]) => ({ text, id })) : []
const subFooter = ( if (isModels) {
<Grid cols={2}> sidebar.items[1].items = languages
<div style={{ marginTop: 'var(--spacing-lg)' }}> .filter(({ models }) => models && models.length)
{(!isModels || (isModels && isIndex)) && ( .sort((a, b) => a.name.localeCompare(b.name))
<Button to={currentSource} icon="code"> .map((lang) => ({
Suggest edits text: lang.name,
</Button> url: `/models/${lang.code}`,
)} isActive: id === lang.code,
</div> menu: lang.models.map((model) => ({
{next && <ReadNext title={next.title} to={next.slug} />} text: model,
</Grid> id: model,
) })),
}))
}
const sourcePath = source ? github(source) : null
const currentSource = getCurrentSource(slug, isIndex)
return ( const subFooter = (
<> <Grid cols={2}>
{sidebar && <Sidebar items={sidebar.items} pageMenu={pageMenu} slug={slug} />} <div style={{ marginTop: 'var(--spacing-lg)' }}>
<Main {(!isModels || (isModels && isIndex)) && (
section={section} <Button to={currentSource} icon="code">
theme={nightly ? 'nightly' : legacy ? 'legacy' : theme} Suggest edits
sidebar </Button>
asides )}
wrapContent </div>
footer={<Footer />} {next && <ReadNext title={next.title} to={next.slug} />}
> </Grid>
{isModels && !isIndex ? ( )
<Models pageContext={pageContext} repo={modelsRepo}>
{subFooter} return (
</Models> <>
) : ( {sidebar && <Sidebar items={sidebar.items} pageMenu={pageMenu} slug={slug} />}
<> <Main
<Title section={section}
title={title} theme={nightly ? 'nightly' : legacy ? 'legacy' : theme}
teaser={teaser} sidebar
source={sourcePath} asides
tag={tag} wrapContent
version={version} footer={<Footer />}
id="_title" >
apiDetails={apiDetails} {isModels && !isIndex ? (
/> <Models pageContext={pageContext} repo={modelsRepo}>
{children} {subFooter}
{subFooter} </Models>
</> ) : (
)} <>
</Main> <Title
</> title={title}
) teaser={teaser}
}} source={sourcePath}
/> tag={tag}
) version={version}
id="_title"
apiDetails={apiDetails}
/>
{children}
{subFooter}
</>
)}
</Main>
</>
)
}
Docs.propTypes = { Docs.propTypes = {
pageContext: PropTypes.shape({ pageContext: PropTypes.shape({
@ -125,32 +125,3 @@ Docs.propTypes = {
} }
export default Docs export default Docs
const query = graphql`
query DocsQuery {
site {
siteMetadata {
repo
modelsRepo
languages {
code
name
models
}
nightly
legacy
sidebars {
section
items {
label
items {
text
url
tag
}
}
}
}
}
}
`

View File

@ -1,6 +1,5 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { graphql } from 'gatsby'
import { MDXProvider } from '@mdx-js/tag' import { MDXProvider } from '@mdx-js/tag'
import { withMDXScope } from 'gatsby-mdx/context' import { withMDXScope } from 'gatsby-mdx/context'
import useOnlineStatus from '@rehooks/online-status' import useOnlineStatus from '@rehooks/online-status'
@ -18,70 +17,13 @@ import Progress from '../components/progress'
import Footer from '../components/footer' import Footer from '../components/footer'
import SEO from '../components/seo' import SEO from '../components/seo'
import Link from '../components/link' import Link from '../components/link'
import Section, { Hr } from '../components/section' import { InlineCode } from '../components/code'
import { Table, Tr, Th, Tx, Td } from '../components/table'
import { Pre, Code, InlineCode, TypeAnnotation } from '../components/code'
import { Ol, Ul, Li } from '../components/list'
import { H2, H3, H4, H5, P, Abbr, Help } from '../components/typography'
import Accordion from '../components/accordion'
import Infobox from '../components/infobox'
import Aside from '../components/aside'
import Button from '../components/button'
import Tag from '../components/tag'
import Grid from '../components/grid'
import { YouTube, SoundCloud, Iframe, Image, GoogleSheet } from '../components/embed'
import Alert from '../components/alert' import Alert from '../components/alert'
import Search from '../components/search' import Search from '../components/search'
import Project from '../widgets/project'
import { Integration, IntegrationLogo } from '../widgets/integration'
const mdxComponents = { import siteMetadata from '../../meta/site.json'
a: Link, import { nightly, legacy } from '../../meta/dynamicMeta'
p: P, import { remarkComponents } from '../remark'
pre: Pre,
code: Code,
inlineCode: InlineCode,
del: TypeAnnotation,
table: Table,
img: Image,
tr: Tr,
th: Th,
td: Td,
ol: Ol,
ul: Ul,
li: Li,
h2: H2,
h3: H3,
h4: H4,
h5: H5,
blockquote: Aside,
section: Section,
wrapper: ({ children }) => children,
hr: Hr,
}
const scopeComponents = {
Infobox,
Table,
Tr,
Tx,
Th,
Td,
Help,
Button,
YouTube,
SoundCloud,
Iframe,
GoogleSheet,
Abbr,
Tag,
Accordion,
Grid,
InlineCode,
Project,
Integration,
IntegrationLogo,
}
const AlertSpace = ({ nightly, legacy }) => { const AlertSpace = ({ nightly, legacy }) => {
const isOnline = useOnlineStatus() const isOnline = useOnlineStatus()
@ -112,7 +54,7 @@ const AlertSpace = ({ nightly, legacy }) => {
)} )}
{!isOnline && ( {!isOnline && (
<Alert title="Looks like you're offline." icon="offline" variant="warning"> <Alert title="Looks like you're offline." icon="offline" variant="warning">
But don't worry, your visited pages should be saved for you. But don&apos;t worry, your visited pages should be saved for you.
</Alert> </Alert>
)} )}
</> </>
@ -160,20 +102,19 @@ class Layout extends React.Component {
// NB: Compiling the scope here instead of in render() is super // NB: Compiling the scope here instead of in render() is super
// important! Otherwise, it triggers unnecessary rerenders of ALL // important! Otherwise, it triggers unnecessary rerenders of ALL
// consumers (e.g. mdx elements), even on anchor navigation! // consumers (e.g. mdx elements), even on anchor navigation!
this.state = { scope: { ...scopeComponents, ...props.scope } } this.state = { scope: { ...remarkComponents, ...props.scope } }
} }
render() { render() {
const { data, pageContext, location, children } = this.props const { data, pageContext, location, children } = this.props
const { file, site = {} } = data || {} const { file, site = {} } = data || {}
const mdx = file ? file.childMdx : null const mdx = file ? file.childMdx : null
const meta = site.siteMetadata || {}
const { title, section, sectionTitle, teaser, theme = 'blue', searchExclude } = pageContext const { title, section, sectionTitle, teaser, theme = 'blue', searchExclude } = pageContext
const uiTheme = meta.nightly ? 'nightly' : meta.legacy ? 'legacy' : theme const uiTheme = nightly ? 'nightly' : legacy ? 'legacy' : theme
const bodyClass = classNames(`theme-${uiTheme}`, { 'search-exclude': !!searchExclude }) const bodyClass = classNames(`theme-${uiTheme}`, { 'search-exclude': !!searchExclude })
const isDocs = ['usage', 'models', 'api', 'styleguide'].includes(section) const isDocs = ['usage', 'models', 'api', 'styleguide'].includes(section)
const content = !mdx ? null : ( const content = !mdx ? null : (
<MDXProvider components={mdxComponents}> <MDXProvider components={remarkComponents}>
<MDXRenderer scope={this.state.scope}>{mdx.code.body}</MDXRenderer> <MDXRenderer scope={this.state.scope}>{mdx.code.body}</MDXRenderer>
</MDXProvider> </MDXProvider>
) )
@ -182,21 +123,21 @@ class Layout extends React.Component {
<> <>
<SEO <SEO
title={title} title={title}
description={teaser || meta.description} description={teaser || siteMetadata.description}
section={section} section={section}
sectionTitle={sectionTitle} sectionTitle={sectionTitle}
bodyClass={bodyClass} bodyClass={bodyClass}
nightly={meta.nightly} nightly={nightly}
/> />
<AlertSpace nightly={meta.nightly} legacy={meta.legacy} /> <AlertSpace nightly={nightly} legacy={legacy} />
<Navigation <Navigation
title={meta.title} title={siteMetadata.title}
items={meta.navigation} items={siteMetadata.navigation}
section={section} section={section}
search={<Search settings={meta.docSearch} />} search={<Search settings={siteMetadata.docSearch} />}
alert={meta.nightly ? null : navAlert} alert={nightly ? null : navAlert}
> >
<Progress key={location.href} /> <Progress />
</Navigation> </Navigation>
{isDocs ? ( {isDocs ? (
<Docs pageContext={pageContext}>{content}</Docs> <Docs pageContext={pageContext}>{content}</Docs>
@ -219,33 +160,3 @@ class Layout extends React.Component {
} }
export default withMDXScope(Layout) export default withMDXScope(Layout)
export const pageQuery = graphql`
query ($slug: String!) {
site {
siteMetadata {
nightly
legacy
title
description
navigation {
text
url
}
docSearch {
apiKey
indexName
appId
}
}
}
file(fields: { slug: { eq: $slug } }) {
childMdx {
code {
scope
body
}
}
}
}
`

View File

@ -1,5 +1,4 @@
import React, { useEffect, useState, useMemo, Fragment } from 'react' import React, { useEffect, useState, useMemo, Fragment } from 'react'
import { StaticQuery, graphql } from 'gatsby'
import { window } from 'browser-monads' import { window } from 'browser-monads'
import Title from '../components/title' import Title from '../components/title'
@ -17,6 +16,9 @@ import Accordion from '../components/accordion'
import { join, arrayToObj, abbrNum, markdownToReact } from '../components/util' import { join, arrayToObj, abbrNum, markdownToReact } from '../components/util'
import { isString, isEmptyObj } from '../components/util' import { isString, isEmptyObj } from '../components/util'
import siteMetadata from '../../meta/site.json'
import languages from '../../meta/languages.json'
const COMPONENT_LINKS = { const COMPONENT_LINKS = {
tok2vec: '/api/tok2vec', tok2vec: '/api/tok2vec',
transformer: '/api/transformer', transformer: '/api/transformer',
@ -367,7 +369,7 @@ const Model = ({
const labelNames = labels[pipe] || [] const labelNames = labels[pipe] || []
const help = LABEL_SCHEME_META[pipe] const help = LABEL_SCHEME_META[pipe]
return ( return (
<Tr key={`${name}-${pipe}`} evenodd={false} key={pipe}> <Tr evenodd={false} key={pipe}>
<Td style={{ width: '20%' }}> <Td style={{ width: '20%' }}>
<Label> <Label>
{pipe} {help && <Help>{help}</Help>} {pipe} {help && <Help>{help}</Help>}
@ -415,43 +417,23 @@ const Models = ({ pageContext, repo, children }) => {
return ( return (
<> <>
<Title title={title} teaser={`Available trained pipelines for ${title}`} /> <Title title={title} teaser={`Available trained pipelines for ${title}`} />
<StaticQuery {models.map((modelName) => (
query={query} <Model
render={({ site }) => key={modelName}
models.map((modelName) => ( name={modelName}
<Model langId={id}
key={modelName} langName={title}
name={modelName} compatibility={compatibility}
langId={id} baseUrl={baseUrl}
langName={title} repo={repo}
compatibility={compatibility} licenses={arrayToObj(languages.licenses, 'id')}
baseUrl={baseUrl} hasExamples={meta.hasExamples}
repo={repo} prereleases={siteMetadata.nightly}
licenses={arrayToObj(site.siteMetadata.licenses, 'id')} />
hasExamples={meta.hasExamples} ))}
prereleases={site.siteMetadata.nightly}
/>
))
}
/>
{children} {children}
</> </>
) )
} }
export default Models export default Models
const query = graphql`
query ModelsQuery {
site {
siteMetadata {
nightly
licenses {
id
url
}
}
}
}
`

View File

@ -1,6 +1,5 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { StaticQuery, graphql } from 'gatsby'
import Card from '../components/card' import Card from '../components/card'
import Link from '../components/link' import Link from '../components/link'
@ -19,6 +18,9 @@ import { H3, H5, Label, InlineList } from '../components/typography'
import { YouTube, SoundCloud, Iframe } from '../components/embed' import { YouTube, SoundCloud, Iframe } from '../components/embed'
import { github, markdownToReact } from '../components/util' import { github, markdownToReact } from '../components/util'
import { nightly, legacy } from '../../meta/dynamicMeta'
import universe from '../../meta/universe.json'
function getSlug(data) { function getSlug(data) {
if (data.isCategory) return `/universe/category/${data.id}` if (data.isCategory) return `/universe/category/${data.id}`
if (data.isProject) return `/universe/project/${data.id}` if (data.isProject) return `/universe/project/${data.id}`
@ -123,9 +125,9 @@ const UniverseContent = ({ content = [], categories, theme, pageContext, mdxComp
</Section> </Section>
)} )}
<section className="search-exclude"> <section className="search-exclude">
<H3>Found a mistake or something isn't working?</H3> <H3>Found a mistake or something isn&apos;t working?</H3>
<p> <p>
If you've come across a universe project that isn't working or is If you&apos;ve come across a universe project that isn&apos;t working or is
incompatible with the reported spaCy version, let us know by{' '} incompatible with the reported spaCy version, let us know by{' '}
<Link to="https://github.com/explosion/spaCy/discussions/new"> <Link to="https://github.com/explosion/spaCy/discussions/new">
opening a discussion thread opening a discussion thread
@ -234,7 +236,7 @@ const Project = ({ data, components }) => (
)} )}
{data.cran && ( {data.cran && (
<Aside title="Installation"> <Aside title="Installation">
<CodeBlock lang="r">install.packages("{data.cran}")</CodeBlock> <CodeBlock lang="r">install.packages(&quot;{data.cran}&quot;)</CodeBlock>
</Aside> </Aside>
)} )}
@ -333,73 +335,18 @@ const Project = ({ data, components }) => (
</> </>
) )
const Universe = ({ pageContext, location, mdxComponents }) => ( const Universe = ({ pageContext, location, mdxComponents }) => {
<StaticQuery const theme = nightly ? 'nightly' : legacy ? 'legacy' : pageContext.theme
query={query} return (
render={(data) => { <UniverseContent
const { universe, nightly, legacy } = data.site.siteMetadata content={universe.resources}
const theme = nightly ? 'nightly' : legacy ? 'legacy' : pageContext.theme categories={universe.categories}
return ( pageContext={pageContext}
<UniverseContent location={location}
content={universe.resources} mdxComponents={mdxComponents}
categories={universe.categories} theme={theme}
pageContext={pageContext} />
location={location} )
mdxComponents={mdxComponents} }
theme={theme}
/>
)
}}
/>
)
export default Universe export default Universe
const query = graphql`
query UniverseQuery {
site {
siteMetadata {
nightly
legacy
universe {
resources {
type
id
title
slogan
url
github
description
spacy_version
pip
cran
category
thumb
image
cover
code_example
code_language
youtube
soundcloud
iframe
iframe_height
author
author_links {
twitter
github
website
}
}
categories {
label
items {
id
title
description
}
}
}
}
}
}
`

View File

@ -1,72 +1,65 @@
import React from 'react' import React from 'react'
import { graphql, StaticQuery } from 'gatsby'
import { Ul, Li } from '../components/list' import { Ul, Li } from '../components/list'
export default () => ( import models from '../../meta/languages.json'
<StaticQuery
query={query}
render={({ site }) => {
const { counts } = site.siteMetadata
return (
<Ul>
<Li>
Support for <strong>{counts.langs}+ languages</strong>
</Li>
<Li>
<strong>{counts.models} trained pipelines</strong> for{' '}
{counts.modelLangs} languages
</Li>
<Li>
Multi-task learning with pretrained <strong>transformers</strong> like
BERT
</Li>
<Li>
Pretrained <strong>word vectors</strong>
</Li>
<Li> State-of-the-art speed</Li>
<Li>
Production-ready <strong>training system</strong>
</Li>
<Li>
Linguistically-motivated <strong>tokenization</strong>
</Li>
<Li>
Components for <strong>named entity</strong> recognition, part-of-speech
tagging, dependency parsing, sentence segmentation,{' '}
<strong>text classification</strong>, lemmatization, morphological analysis,
entity linking and more
</Li>
<Li>
Easily extensible with <strong>custom components</strong> and attributes
</Li>
<Li>
Support for custom models in <strong>PyTorch</strong>,{' '}
<strong>TensorFlow</strong> and other frameworks
</Li>
<Li>
Built in <strong>visualizers</strong> for syntax and NER
</Li>
<Li>
Easy <strong>model packaging</strong>, deployment and workflow management
</Li>
<Li> Robust, rigorously evaluated accuracy</Li>
</Ul>
)
}}
/>
)
const query = graphql` /**
query FeaturesQuery { * Compute the overall total counts of models and languages
site { */
siteMetadata { function getCounts(langs = []) {
counts { return {
langs langs: langs.length,
modelLangs modelLangs: langs.filter(({ models }) => models && !!models.length).length,
models models: langs.map(({ models }) => (models ? models.length : 0)).reduce((a, b) => a + b, 0),
}
}
}
} }
` }
const Features = () => {
const counts = getCounts(models.languages)
return (
<Ul>
<Li>
Support for <strong>{counts.langs}+ languages</strong>
</Li>
<Li>
<strong>{counts.models} trained pipelines</strong> for {counts.modelLangs}{' '}
languages
</Li>
<Li>
Multi-task learning with pretrained <strong>transformers</strong> like BERT
</Li>
<Li>
Pretrained <strong>word vectors</strong>
</Li>
<Li> State-of-the-art speed</Li>
<Li>
Production-ready <strong>training system</strong>
</Li>
<Li>
Linguistically-motivated <strong>tokenization</strong>
</Li>
<Li>
Components for <strong>named entity</strong> recognition, part-of-speech tagging,
dependency parsing, sentence segmentation, <strong>text classification</strong>,
lemmatization, morphological analysis, entity linking and more
</Li>
<Li>
Easily extensible with <strong>custom components</strong> and attributes
</Li>
<Li>
Support for custom models in <strong>PyTorch</strong>,{' '}
<strong>TensorFlow</strong> and other frameworks
</Li>
<Li>
Built in <strong>visualizers</strong> for syntax and NER
</Li>
<Li>
Easy <strong>model packaging</strong>, deployment and workflow management
</Li>
<Li> Robust, rigorously evaluated accuracy</Li>
</Ul>
)
}
export default Features

View File

@ -1,6 +1,5 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { StaticQuery, graphql } from 'gatsby'
import { import {
LandingHeader, LandingHeader,
@ -19,13 +18,15 @@ import { Ul, Li } from '../components/list'
import Button from '../components/button' import Button from '../components/button'
import Link from '../components/link' import Link from '../components/link'
import QuickstartTraining from './quickstart-training' import QuickstartTraining from '../widgets/quickstart-training'
import Project from './project' import Project from '../widgets/project'
import Features from './features' import Features from '../widgets/features'
import Layout from '../components/layout'
import courseImage from '../../docs/images/course.jpg' import courseImage from '../../docs/images/course.jpg'
import prodigyImage from '../../docs/images/prodigy_overview.jpg' import prodigyImage from '../../docs/images/prodigy_overview.jpg'
import projectsImage from '../../docs/images/projects.png' import projectsImage from '../../docs/images/projects.png'
import tailoredPipelinesImage from '../../docs/images/spacy-tailored-pipelines_wide.png' import tailoredPipelinesImage from '../../docs/images/spacy-tailored-pipelines_wide.png'
import { nightly, legacy } from '../../meta/dynamicMeta'
import Benchmarks from '../../docs/usage/_benchmarks-models.mdx' import Benchmarks from '../../docs/usage/_benchmarks-models.mdx'
@ -56,8 +57,7 @@ for entity in doc.ents:
` `
} }
const Landing = ({ data }) => { const Landing = () => {
const { nightly, legacy } = data
const codeExample = getCodeExample(nightly) const codeExample = getCodeExample(nightly)
return ( return (
<> <>
@ -75,15 +75,15 @@ const Landing = ({ data }) => {
<LandingCard title="Get things done" url="/usage/spacy-101" button="Get started"> <LandingCard title="Get things done" url="/usage/spacy-101" button="Get started">
spaCy is designed to help you do real work to build real products, or gather spaCy is designed to help you do real work to build real products, or gather
real insights. The library respects your time, and tries to avoid wasting it. real insights. The library respects your time, and tries to avoid wasting it.
It's easy to install, and its API is simple and productive. It&apos;s easy to install, and its API is simple and productive.
</LandingCard> </LandingCard>
<LandingCard <LandingCard
title="Blazing fast" title="Blazing fast"
url="/usage/facts-figures" url="/usage/facts-figures"
button="Facts &amp; Figures" button="Facts &amp; Figures"
> >
spaCy excels at large-scale information extraction tasks. It's written from the spaCy excels at large-scale information extraction tasks. It&apos;s written from
ground up in carefully memory-managed Cython. If your application needs to the ground up in carefully memory-managed Cython. If your application needs to
process entire web dumps, spaCy is the library you want to be using. process entire web dumps, spaCy is the library you want to be using.
</LandingCard> </LandingCard>
@ -115,33 +115,33 @@ const Landing = ({ data }) => {
<img src={tailoredPipelinesImage} alt="spaCy Tailored Pipelines" /> <img src={tailoredPipelinesImage} alt="spaCy Tailored Pipelines" />
</Link> </Link>
<strong> <strong>
Get a custom spaCy pipeline, tailor-made for your NLP problem by spaCy's Get a custom spaCy pipeline, tailor-made for your NLP problem by
core developers. spaCy&apos;s core developers.
</strong> </strong>
<br /> <br />
<br /> <br />
<Ul> <Ul>
<Li emoji="🔥"> <Li emoji="🔥">
<strong>Streamlined.</strong> Nobody knows spaCy better than we do. Send <strong>Streamlined.</strong> Nobody knows spaCy better than we do. Send
us your pipeline requirements and we'll be ready to start producing your us your pipeline requirements and we&apos;ll be ready to start producing
solution in no time at all. your solution in no time at all.
</Li> </Li>
<Li emoji="🐿 "> <Li emoji="🐿 ">
<strong>Production ready.</strong> spaCy pipelines are robust and easy <strong>Production ready.</strong> spaCy pipelines are robust and easy
to deploy. You'll get a complete spaCy project folder which is ready to{' '} to deploy. You&apos;ll get a complete spaCy project folder which is
<InlineCode>spacy project run</InlineCode>. ready to <InlineCode>spacy project run</InlineCode>.
</Li> </Li>
<Li emoji="🔮"> <Li emoji="🔮">
<strong>Predictable.</strong> You'll know exactly what you're going to <strong>Predictable.</strong> You&apos;ll know exactly what you&apos;re
get and what it's going to cost. We quote fees up-front, let you try going to get and what it&apos;s going to cost. We quote fees up-front,
before you buy, and don't charge for over-runs at our end all the risk let you try before you buy, and don&apos;t charge for over-runs at our
is on us. end all the risk is on us.
</Li> </Li>
<Li emoji="🛠"> <Li emoji="🛠">
<strong>Maintainable.</strong> spaCy is an industry standard, and we'll <strong>Maintainable.</strong> spaCy is an industry standard, and
deliver your pipeline with full code, data, tests and documentation, so we&apos;ll deliver your pipeline with full code, data, tests and
your team can retrain, update and extend the solution as your documentation, so your team can retrain, update and extend the solution
requirements change. as your requirements change.
</Li> </Li>
</Ul> </Ul>
</LandingBanner> </LandingBanner>
@ -166,7 +166,7 @@ const Landing = ({ data }) => {
<br /> <br />
Prodigy is an <strong>annotation tool</strong> so efficient that data scientists Prodigy is an <strong>annotation tool</strong> so efficient that data scientists
can do the annotation themselves, enabling a new level of rapid iteration. can do the annotation themselves, enabling a new level of rapid iteration.
Whether you're working on entity recognition, intent detection or image Whether you&apos;re working on entity recognition, intent detection or image
classification, Prodigy can help you <strong>train and evaluate</strong> your classification, Prodigy can help you <strong>train and evaluate</strong> your
models faster. models faster.
</LandingBanner> </LandingBanner>
@ -214,7 +214,7 @@ const Landing = ({ data }) => {
<LandingCol> <LandingCol>
<H2>End-to-end workflows from prototype to production</H2> <H2>End-to-end workflows from prototype to production</H2>
<p> <p>
spaCy's new project system gives you a smooth path from prototype to spaCy&apos;s new project system gives you a smooth path from prototype to
production. It lets you keep track of all those{' '} production. It lets you keep track of all those{' '}
<strong>data transformation</strong>, preprocessing and{' '} <strong>data transformation</strong>, preprocessing and{' '}
<strong>training steps</strong>, so you can make sure your project is always <strong>training steps</strong>, so you can make sure your project is always
@ -237,11 +237,11 @@ const Landing = ({ data }) => {
small small
> >
spaCy v3.0 features all new <strong>transformer-based pipelines</strong> that spaCy v3.0 features all new <strong>transformer-based pipelines</strong> that
bring spaCy's accuracy right up to the current <strong>state-of-the-art</strong> bring spaCy&apos;s accuracy right up to the current{' '}
. You can use any pretrained transformer to train your own pipelines, and even <strong>state-of-the-art</strong>. You can use any pretrained transformer to
share one transformer between multiple components with{' '} train your own pipelines, and even share one transformer between multiple
<strong>multi-task learning</strong>. Training is now fully configurable and components with <strong>multi-task learning</strong>. Training is now fully
extensible, and you can define your own custom models using{' '} configurable and extensible, and you can define your own custom models using{' '}
<strong>PyTorch</strong>, <strong>TensorFlow</strong> and other frameworks. <strong>PyTorch</strong>, <strong>TensorFlow</strong> and other frameworks.
</LandingBanner> </LandingBanner>
<LandingBanner <LandingBanner
@ -271,7 +271,7 @@ const Landing = ({ data }) => {
<LandingCol> <LandingCol>
<H2>Benchmarks</H2> <H2>Benchmarks</H2>
<p> <p>
spaCy v3.0 introduces transformer-based pipelines that bring spaCy's spaCy v3.0 introduces transformer-based pipelines that bring spaCy&apos;s
accuracy right up to the current <strong>state-of-the-art</strong>. You can accuracy right up to the current <strong>state-of-the-art</strong>. You can
also use a CPU-optimized pipeline, which is less accurate but much cheaper also use a CPU-optimized pipeline, which is less accurate but much cheaper
to run. to run.
@ -289,29 +289,4 @@ const Landing = ({ data }) => {
) )
} }
Landing.propTypes = { export default Landing
data: PropTypes.shape({
repo: PropTypes.string,
languages: PropTypes.arrayOf(
PropTypes.shape({
models: PropTypes.arrayOf(PropTypes.string),
})
),
}),
}
export default () => (
<StaticQuery query={landingQuery} render={({ site }) => <Landing data={site.siteMetadata} />} />
)
const landingQuery = graphql`
query LandingQuery {
site {
siteMetadata {
nightly
legacy
repo
}
}
}
`

View File

@ -1,5 +1,4 @@
import React from 'react' import React from 'react'
import { StaticQuery, graphql } from 'gatsby'
import Link from '../components/link' import Link from '../components/link'
import { InlineCode } from '../components/code' import { InlineCode } from '../components/code'
@ -8,6 +7,8 @@ import { Ul, Li } from '../components/list'
import Infobox from '../components/infobox' import Infobox from '../components/infobox'
import { github, join } from '../components/util' import { github, join } from '../components/util'
import models from '../../meta/languages.json'
const Language = ({ name, code, models }) => ( const Language = ({ name, code, models }) => (
<Tr> <Tr>
<Td>{name}</Td> <Td>{name}</Td>
@ -31,75 +32,54 @@ const Language = ({ name, code, models }) => (
</Tr> </Tr>
) )
const Languages = () => ( const Languages = () => {
<StaticQuery const langs = models.languages
query={query} const withModels = langs
render={({ site }) => { .filter(({ models }) => models && !!models.length)
const langs = site.siteMetadata.languages .sort((a, b) => a.name.localeCompare(b.name))
const withModels = langs const withoutModels = langs
.filter(({ models }) => models && !!models.length) .filter(({ models }) => !models || !models.length)
.sort((a, b) => a.name.localeCompare(b.name)) .sort((a, b) => a.name.localeCompare(b.name))
const withoutModels = langs const withDeps = langs.filter(({ dependencies }) => dependencies && dependencies.length)
.filter(({ models }) => !models || !models.length) return (
.sort((a, b) => a.name.localeCompare(b.name)) <>
const withDeps = langs.filter(({ dependencies }) => dependencies && dependencies.length) <Table>
return ( <thead>
<> <Tr>
<Table> <Th>Language</Th>
<thead> <Th>Code</Th>
<Tr> <Th>Language Data</Th>
<Th>Language</Th> <Th>Pipelines</Th>
<Th>Code</Th> </Tr>
<Th>Language Data</Th> </thead>
<Th>Pipelines</Th> <tbody>
</Tr> {withModels.map((model) => (
</thead> <Language {...model} key={model.code} />
<tbody> ))}
{withModels.map((model) => ( {withoutModels.map((model) => (
<Language {...model} key={model.code} /> <Language {...model} key={model.code} />
))} ))}
{withoutModels.map((model) => ( </tbody>
<Language {...model} key={model.code} /> </Table>
))} <Infobox title="Dependencies">
</tbody> <p>Some language tokenizers require external dependencies.</p>
</Table> <Ul>
<Infobox title="Dependencies"> {withDeps.map(({ code, name, dependencies }) => (
<p>Some language tokenizers require external dependencies.</p> <Li key={code}>
<Ul> <strong>{name}:</strong>{' '}
{withDeps.map(({ code, name, dependencies }) => ( {join(
<Li key={code}> dependencies.map((dep, i) => (
<strong>{name}:</strong>{' '} <Link key={i} to={dep.url}>
{join( {dep.name}
dependencies.map((dep, i) => ( </Link>
<Link to={dep.url}>{dep.name}</Link> ))
)) )}
)} </Li>
</Li> ))}
))} </Ul>
</Ul> </Infobox>
</Infobox> </>
</> )
) }
}}
/>
)
export default Languages export default Languages
const query = graphql`
query LanguagesQuery {
site {
siteMetadata {
languages {
code
name
models
dependencies {
name
url
}
}
}
}
}
`

View File

@ -1,8 +1,9 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { StaticQuery, graphql } from 'gatsby'
import { Quickstart, QS } from '../components/quickstart' import { Quickstart, QS } from '../components/quickstart'
import { repo, DEFAULT_BRANCH } from '../components/util' import { repo, DEFAULT_BRANCH } from '../components/util'
import siteMetadata from '../../meta/site.json'
import models from '../../meta/languages.json'
const DEFAULT_OS = 'mac' const DEFAULT_OS = 'mac'
const DEFAULT_PLATFORM = 'x86' const DEFAULT_PLATFORM = 'x86'
@ -51,215 +52,178 @@ const QuickstartInstall = ({ id, title }) => {
] ]
.filter((e) => e) .filter((e) => e)
.join(',') .join(',')
return (
<StaticQuery
query={query}
render={({ site }) => {
const { nightly, languages } = site.siteMetadata
const pkg = nightly ? 'spacy-nightly' : 'spacy'
const models = languages.filter(({ models }) => models !== null)
const data = [
{
id: 'os',
title: 'Operating system',
options: [
{ id: 'mac', title: 'macOS / OSX', checked: true },
{ id: 'windows', title: 'Windows' },
{ id: 'linux', title: 'Linux' },
],
defaultValue: DEFAULT_OS,
},
{
id: 'platform',
title: 'Platform',
options: [
{ id: 'x86', title: 'x86', checked: true },
{ id: 'arm', title: 'ARM / M1' },
],
defaultValue: DEFAULT_PLATFORM,
},
{
id: 'package',
title: 'Package manager',
options: [
{ id: 'pip', title: 'pip', checked: true },
!nightly ? { id: 'conda', title: 'conda' } : null,
{ id: 'source', title: 'from source' },
].filter((o) => o),
},
{
id: 'hardware',
title: 'Hardware',
options: [
{ id: 'cpu', title: 'CPU', checked: DEFAULT_HARDWARE === 'cpu' },
{ id: 'gpu', title: 'GPU', checked: DEFAULT_HARDWARE == 'gpu' },
],
dropdown: Object.keys(CUDA).map((id) => ({
id: CUDA[id],
title: `CUDA ${id}`,
})),
defaultValue: DEFAULT_CUDA,
},
{
id: 'config',
title: 'Configuration',
multiple: true,
options: [
{
id: 'venv',
title: 'virtual env',
help: 'Use a virtual environment',
},
{
id: 'train',
title: 'train models',
help: 'Check this if you plan to train your own models with spaCy to install extra dependencies and data resources',
},
],
},
{
id: 'models',
title: 'Trained pipelines',
multiple: true,
options: models
.sort((a, b) => a.name.localeCompare(b.name))
.map(({ code, name }) => ({
id: code,
title: name,
checked: DEFAULT_MODELS.includes(code),
})),
},
]
if (selectedModels.length) {
data.push({
id: 'optimize',
title: 'Select pipeline for',
options: [
{
id: 'efficiency',
title: 'efficiency',
checked: DEFAULT_OPT === 'efficiency',
help: 'Faster and smaller pipeline, but less accurate',
},
{
id: 'accuracy',
title: 'accuracy',
checked: DEFAULT_OPT === 'accuracy',
help: 'Larger and slower pipeline, but more accurate',
},
],
})
}
return (
<Quickstart
data={data}
title={title}
id={id}
setters={setters}
showDropdown={showDropdown}
>
<QS os="mac" hardware="gpu" platform="arm">
# Note M1 GPU support is experimental, see{' '}
<a href="https://github.com/explosion/thinc/issues/792">
Thinc issue #792
</a>
</QS>
<QS package="pip" config="venv">
python -m venv .env
</QS>
<QS package="pip" config="venv" os="mac">
source .env/bin/activate
</QS>
<QS package="pip" config="venv" os="linux">
source .env/bin/activate
</QS>
<QS package="pip" config="venv" os="windows">
.env\Scripts\activate
</QS>
<QS package="source" config="venv">
python -m venv .env
</QS>
<QS package="source" config="venv" os="mac">
source .env/bin/activate
</QS>
<QS package="source" config="venv" os="linux">
source .env/bin/activate
</QS>
<QS package="source" config="venv" os="windows">
.env\Scripts\activate
</QS>
<QS package="conda" config="venv">
conda create -n venv
</QS>
<QS package="conda" config="venv">
conda activate venv
</QS>
<QS package="pip">pip install -U pip setuptools wheel</QS>
<QS package="source">pip install -U pip setuptools wheel</QS>
<QS package="pip">
{pipExtras
? `pip install -U '${pkg}[${pipExtras}]'`
: `pip install -U ${pkg}`}
{nightly ? ' --pre' : ''}
</QS>
<QS package="conda">conda install -c conda-forge spacy</QS>
<QS package="conda" hardware="gpu" os="windows">
conda install -c conda-forge cupy
</QS>
<QS package="conda" hardware="gpu" os="linux">
conda install -c conda-forge cupy
</QS>
<QS package="conda" hardware="gpu" os="mac" platform="x86">
conda install -c conda-forge cupy
</QS>
<QS package="conda" config="train">
conda install -c conda-forge spacy-transformers
</QS>
<QS package="source">
git clone https://github.com/{repo}
{nightly ? ` --branch ${DEFAULT_BRANCH}` : ''}
</QS>
<QS package="source">cd spaCy</QS>
<QS package="source">pip install -r requirements.txt</QS>
<QS package="source">
pip install --no-build-isolation --editable{' '}
{train || hardware == 'gpu' ? `'.[${pipExtras}]'` : '.'}
</QS>
<QS config="train" package="conda" comment prompt={false}>
# packages only available via pip
</QS>
<QS config="train" package="conda">
pip install spacy-lookups-data
</QS>
{models.map(({ code, models: modelOptions }) => { const { nightly } = siteMetadata
const pkg = modelOptions[efficiency ? 0 : modelOptions.length - 1] const pkg = nightly ? 'spacy-nightly' : 'spacy'
return ( const languages = models.languages.filter(({ models }) => !!models)
<QS models={code} key={code}> const data = [
python -m spacy download {pkg} {
</QS> id: 'os',
) title: 'Operating system',
})} options: [
</Quickstart> { id: 'mac', title: 'macOS / OSX', checked: true },
{ id: 'windows', title: 'Windows' },
{ id: 'linux', title: 'Linux' },
],
defaultValue: DEFAULT_OS,
},
{
id: 'platform',
title: 'Platform',
options: [
{ id: 'x86', title: 'x86', checked: true },
{ id: 'arm', title: 'ARM / M1' },
],
defaultValue: DEFAULT_PLATFORM,
},
{
id: 'package',
title: 'Package manager',
options: [
{ id: 'pip', title: 'pip', checked: true },
!nightly ? { id: 'conda', title: 'conda' } : null,
{ id: 'source', title: 'from source' },
].filter((o) => o),
},
{
id: 'hardware',
title: 'Hardware',
options: [
{ id: 'cpu', title: 'CPU', checked: DEFAULT_HARDWARE === 'cpu' },
{ id: 'gpu', title: 'GPU', checked: DEFAULT_HARDWARE == 'gpu' },
],
dropdown: Object.keys(CUDA).map((id) => ({
id: CUDA[id],
title: `CUDA ${id}`,
})),
defaultValue: DEFAULT_CUDA,
},
{
id: 'config',
title: 'Configuration',
multiple: true,
options: [
{
id: 'venv',
title: 'virtual env',
help: 'Use a virtual environment',
},
{
id: 'train',
title: 'train models',
help: 'Check this if you plan to train your own models with spaCy to install extra dependencies and data resources',
},
],
},
{
id: 'models',
title: 'Trained pipelines',
multiple: true,
options: languages
.sort((a, b) => a.name.localeCompare(b.name))
.map(({ code, name }) => ({
id: code,
title: name,
checked: DEFAULT_MODELS.includes(code),
})),
},
]
if (selectedModels.length) {
data.push({
id: 'optimize',
title: 'Select pipeline for',
options: [
{
id: 'efficiency',
title: 'efficiency',
checked: DEFAULT_OPT === 'efficiency',
help: 'Faster and smaller pipeline, but less accurate',
},
{
id: 'accuracy',
title: 'accuracy',
checked: DEFAULT_OPT === 'accuracy',
help: 'Larger and slower pipeline, but more accurate',
},
],
})
}
return (
<Quickstart data={data} title={title} id={id} setters={setters} showDropdown={showDropdown}>
<QS os="mac" hardware="gpu" platform="arm">
# Note M1 GPU support is experimental, see{' '}
<a href="https://github.com/explosion/thinc/issues/792">Thinc issue #792</a>
</QS>
<QS package="pip" config="venv">
python -m venv .env
</QS>
<QS package="pip" config="venv" os="mac">
source .env/bin/activate
</QS>
<QS package="pip" config="venv" os="linux">
source .env/bin/activate
</QS>
<QS package="pip" config="venv" os="windows">
.env\Scripts\activate
</QS>
<QS package="source" config="venv">
python -m venv .env
</QS>
<QS package="source" config="venv" os="mac">
source .env/bin/activate
</QS>
<QS package="source" config="venv" os="linux">
source .env/bin/activate
</QS>
<QS package="source" config="venv" os="windows">
.env\Scripts\activate
</QS>
<QS package="conda" config="venv">
conda create -n venv
</QS>
<QS package="conda" config="venv">
conda activate venv
</QS>
<QS package="pip">pip install -U pip setuptools wheel</QS>
<QS package="source">pip install -U pip setuptools wheel</QS>
<QS package="pip">
{pipExtras ? `pip install -U '${pkg}[${pipExtras}]'` : `pip install -U ${pkg}`}
{nightly ? ' --pre' : ''}
</QS>
<QS package="conda">conda install -c conda-forge spacy</QS>
<QS package="conda" hardware="gpu">
conda install -c conda-forge cupy
</QS>
<QS package="conda" config="train">
conda install -c conda-forge spacy-transformers
</QS>
<QS package="source">
git clone https://github.com/{repo}
{nightly ? ` --branch ${DEFAULT_BRANCH}` : ''}
</QS>
<QS package="source">cd spaCy</QS>
<QS package="source">pip install -r requirements.txt</QS>
<QS package="source">
pip install --no-build-isolation --editable{' '}
{train || hardware == 'gpu' ? `'.[${pipExtras}]'` : '.'}
</QS>
<QS config="train" package="conda" comment prompt={false}>
# packages only available via pip
</QS>
<QS config="train" package="conda">
pip install spacy-lookups-data
</QS>
{languages.map(({ code, models: modelOptions }) => {
const pkg = modelOptions[efficiency ? 0 : modelOptions.length - 1]
return (
<QS models={code} key={code}>
python -m spacy download {pkg}
</QS>
) )
}} })}
/> </Quickstart>
) )
} }
export default QuickstartInstall export default QuickstartInstall
const query = graphql`
query QuickstartInstallQuery {
site {
siteMetadata {
nightly
languages {
code
name
models
}
}
}
}
`

View File

@ -1,7 +1,7 @@
import React, { Fragment, useState } from 'react' import React, { Fragment, useState } from 'react'
import { StaticQuery, graphql } from 'gatsby'
import { Quickstart, QS } from '../components/quickstart' import { Quickstart, QS } from '../components/quickstart'
import models from '../../meta/languages.json'
const DEFAULT_LANG = 'en' const DEFAULT_LANG = 'en'
const DEFAULT_OPT = 'efficiency' const DEFAULT_OPT = 'efficiency'
@ -62,80 +62,59 @@ const QuickstartInstall = ({ id, title, description, children }) => {
lang: setLang, lang: setLang,
optimize: (v) => setEfficiency(v.includes('efficiency')), optimize: (v) => setEfficiency(v.includes('efficiency')),
} }
return (
<StaticQuery
query={query}
render={({ site }) => {
const models = site.siteMetadata.languages.filter(({ models }) => models !== null)
data[0].dropdown = models
.sort((a, b) => a.name.localeCompare(b.name))
.map(({ code, name }) => ({
id: code,
title: name,
}))
return (
<Quickstart
data={data}
title={title}
id={id}
description={description}
setters={setters}
copy={false}
>
{models.map(({ code, models, example }) => {
const pkg = efficiency ? models[0] : models[models.length - 1]
const exampleText = example || 'No text available yet'
return lang !== code ? null : (
<Fragment key={code}>
<QS>python -m spacy download {pkg}</QS>
<QS divider />
<QS load="spacy" prompt="python">
import spacy
</QS>
<QS load="spacy" prompt="python">
nlp = spacy.load("{pkg}")
</QS>
<QS load="module" prompt="python">
import {pkg}
</QS>
<QS load="module" prompt="python">
nlp = {pkg}.load()
</QS>
<QS config="example" prompt="python">
doc = nlp("{exampleText}")
</QS>
<QS config="example" prompt="python">
print([
{code === 'xx'
? '(ent.text, ent.label) for ent in doc.ents'
: '(w.text, w.pos_) for w in doc'}
])
</QS>
</Fragment>
)
})}
{children} const languages = models.languages.filter(({ models }) => !!models)
</Quickstart> data[0].dropdown = languages
.sort((a, b) => a.name.localeCompare(b.name))
.map(({ code, name }) => ({
id: code,
title: name,
}))
return (
<Quickstart
data={data}
title={title}
id={id}
description={description}
setters={setters}
copy={false}
>
{languages.map(({ code, models, example }) => {
const pkg = efficiency ? models[0] : models[models.length - 1]
const exampleText = example || 'No text available yet'
return lang !== code ? null : (
<Fragment key={code}>
<QS>python -m spacy download {pkg}</QS>
<QS divider />
<QS load="spacy" prompt="python">
import spacy
</QS>
<QS load="spacy" prompt="python">
nlp = spacy.load(&quot;{pkg}&quot;)
</QS>
<QS load="module" prompt="python">
import {pkg}
</QS>
<QS load="module" prompt="python">
nlp = {pkg}.load()
</QS>
<QS config="example" prompt="python">
doc = nlp(&quot;{exampleText}&quot;)
</QS>
<QS config="example" prompt="python">
print([
{code === 'xx'
? '(ent.text, ent.label) for ent in doc.ents'
: '(w.text, w.pos_) for w in doc'}
])
</QS>
</Fragment>
) )
}} })}
/>
{children}
</Quickstart>
) )
} }
export default QuickstartInstall export default QuickstartInstall
const query = graphql`
query QuickstartModelsQuery {
site {
siteMetadata {
languages {
code
name
models
example
}
}
}
}
`

View File

@ -1,10 +1,10 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { StaticQuery, graphql } from 'gatsby'
import highlightCode from 'gatsby-remark-prismjs/highlight-code.js' import highlightCode from 'gatsby-remark-prismjs/highlight-code.js'
import { Quickstart } from '../components/quickstart' import { Quickstart } from '../components/quickstart'
import generator, { DATA as GENERATOR_DATA } from './quickstart-training-generator' import generator, { DATA as GENERATOR_DATA } from './quickstart-training-generator'
import { htmlToReact } from '../components/util' import { htmlToReact } from '../components/util'
import models from '../../meta/languages.json'
const DEFAULT_LANG = 'en' const DEFAULT_LANG = 'en'
const DEFAULT_HARDWARE = 'cpu' const DEFAULT_HARDWARE = 'cpu'
@ -112,54 +112,31 @@ export default function QuickstartTraining({ id, title, download = 'base_config.
.split('\n') .split('\n')
.map((line) => (line.startsWith('#') ? `<span class="token comment">${line}</span>` : line)) .map((line) => (line.startsWith('#') ? `<span class="token comment">${line}</span>` : line))
.join('\n') .join('\n')
let data = DATA
data[0].dropdown = models.languages
.map(({ name, code }) => ({
id: code,
title: name,
}))
.sort((a, b) => a.title.localeCompare(b.title))
if (!_components.includes('textcat')) {
data = data.map((field) => (field.id === 'textcat' ? { ...field, hidden: true } : field))
}
return ( return (
<StaticQuery <Quickstart
query={query} Container="div"
render={({ site }) => { download={download}
let data = DATA rawContent={rawContent}
const langs = site.siteMetadata.languages data={data}
data[0].dropdown = langs title={title}
.map(({ name, code }) => ({ id={id}
id: code, setters={setters}
title: name, hidePrompts
})) small
.sort((a, b) => a.title.localeCompare(b.title)) codeLang="ini"
if (!_components.includes('textcat')) { >
data = data.map((field) => {htmlToReact(displayContent)}
field.id === 'textcat' ? { ...field, hidden: true } : field </Quickstart>
)
}
return (
<Quickstart
id="quickstart-widget"
Container="div"
download={download}
rawContent={rawContent}
data={data}
title={title}
id={id}
setters={setters}
hidePrompts
small
codeLang="ini"
>
{htmlToReact(displayContent)}
</Quickstart>
)
}}
/>
) )
} }
const query = graphql`
query QuickstartTrainingQuery {
site {
siteMetadata {
languages {
code
name
}
}
}
}
`