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
├── docs # the actual markdown content
├── meta # JSON-formatted site metadata
| ├── dynamicMeta.js # At build time generated meta data
| ├── languages.json # supported languages and statistical models
| ├── sidebars.json # sidebar navigations for different sections
| ├── site.json # general site metadata

View File

@ -105,11 +105,11 @@ representation.
## Attributes {#attributes}
| Name | Description |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `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~~ |
| `VALUE_SEP` | The [FEATS](https://universaldependencies.org/format.html#morphological-annotation) value separator. Default is `,`. ~~str~~ |
| Name | Description |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `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~~ |
| `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"}

View File

@ -38,8 +38,8 @@ how the component should be configured. You can override its settings via the
> ```
| 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~~ |
| `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~~ |
| **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.

View File

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

View File

@ -13,16 +13,11 @@ const codeBlocksPlugin = require('./src/plugins/remark-code-blocks.js')
// Import metadata
const site = require('./meta/site.json')
const sidebars = require('./meta/sidebars.json')
const models = require('./meta/languages.json')
const universe = require('./meta/universe.json')
const { domain, nightly: isNightly, legacy: isLegacy } = site
const { siteUrl } = require('./meta/dynamicMeta')
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 branch = isNightly ? 'develop' : 'master'
@ -34,30 +29,11 @@ const replacements = {
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 = {
siteMetadata: {
...site,
sidebars,
...models,
counts: getCounts(models.languages),
universe,
nightly: isNightly,
legacy: isLegacy,
binderBranch: domain,
siteUrl,
},
plugins: [
{
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 BASE_PATH = 'docs'
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) {
return pagePath === `/` ? pagePath : pagePath.replace(/\/$/, ``)
@ -26,37 +29,6 @@ exports.createPages = ({ graphql, actions }) => {
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"] } }) {
edges {
node {
@ -107,8 +79,10 @@ exports.createPages = ({ graphql, actions }) => {
reject(result.errors)
}
const sectionData = result.data.site.siteMetadata.sections
const sections = Object.assign({}, ...sectionData.map((s) => ({ [s.id]: s })))
const sections = Object.assign(
{},
...siteMetadata.sections.map((s) => ({ [s.id]: s }))
)
/* Regular pages */
@ -183,8 +157,8 @@ exports.createPages = ({ graphql, actions }) => {
},
})
const universe = result.data.site.siteMetadata.universe.resources
universe.forEach((page) => {
const universeResources = universe.resources
universeResources.forEach((page) => {
const slug = `/universe/project/${page.id}`
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(
[],
universeCategories.map((cat) => cat.items)
@ -227,7 +201,7 @@ exports.createPages = ({ graphql, actions }) => {
/* Models */
const langs = result.data.site.siteMetadata.languages
const langs = models.languages
const modelLangs = langs.filter(({ models }) => models && models.length)
modelLangs.forEach(({ code, name, models, example, has_examples }, i) => {
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"
},
"binderUrl": "explosion/spacy-io-binder",
"binderBranch": "spacy.io",
"binderVersion": "3.4",
"sections": [
{ "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,
})
// Make sure accordion is expanded if JS is disabled
useEffect(() => setIsExpanded(expanded), [])
useEffect(() => setIsExpanded(expanded), [expanded])
return (
<section className="accordion" id={id}>
<div className={rootClassNames}>

View File

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

View File

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

View File

@ -53,7 +53,7 @@ export const LandingGrid = ({ cols = 3, blocks = false, style, children }) => (
</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 }) => (
<div className={classes.card}>

View File

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

View File

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

View File

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

View File

@ -3,10 +3,11 @@ import { Parser as HtmlToReactParser } from 'html-to-react'
import remark from 'remark'
import remark2react from 'remark-react'
import siteMetadata from '../../meta/site.json'
import { domain } from '../../meta/dynamicMeta'
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 repo = siteMetadata.repo
export const modelsRepo = siteMetadata.modelsRepo

View File

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

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
$triangle-size: 2rem
@ -55,14 +56,14 @@ $border-radius: 6px
// Banner effect
&:after
position: absolute
bottom: -$triangle-size / 2
left: $border-radius / 2
bottom: math.div(-$triangle-size, 2)
left: math.div($border-radius, 2)
width: 0
height: 0
border-color: transparent
border-style: solid
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: ""
@include breakpoint(max, sm)

View File

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

View File

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

View File

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

View File

@ -546,3 +546,34 @@ body [id]:target
code, a
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
.root
@ -45,7 +46,7 @@
&:hover
background: var(--color-subtle-light)
.input:focus +
.input:focus
border: 1px solid var(--color-theme)
outline: none
@ -82,14 +83,14 @@
vertical-align: middle
margin-right: 0.5rem
cursor: pointer
border-radius: $size / 4
border-radius: math.div($size, 4)
background: var(--color-back)
position: relative
top: -1px
.checkbox:checked + &:before
// 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
border-color: var(--color-theme)

View File

@ -26,33 +26,3 @@
top: 0.25rem
left: 0.15rem
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
$crumb-bullet: 14px
@ -58,7 +59,7 @@ $crumb-bar: 2px
position: relative
.crumb
margin-bottom: $crumb-bullet / 2
margin-bottom: math.div($crumb-bullet, 2)
position: relative
padding-left: 2rem
color: var(--color-theme)
@ -71,7 +72,7 @@ $crumb-bar: 2px
width: $crumb-bullet
height: $crumb-bullet
position: absolute
top: $crumb-bullet / 4
top: math.div($crumb-bullet, 4)
left: 0
content: ""
border-radius: 50%
@ -83,13 +84,13 @@ $crumb-bar: 2px
height: 100%
position: absolute
top: $crumb-bullet
left: ($crumb-bullet - $crumb-bar) / 2
left: math.div(($crumb-bullet - $crumb-bar), 2)
content: ""
background: var(--color-subtle)
&:first-child:before
height: calc(100% + #{$crumb-bullet * 2})
top: -$crumb-bullet / 2
top: math.div(-$crumb-bullet, 2)
.crumb-active
color: var(--color-dark)

View File

@ -1,6 +1,5 @@
import React from 'react'
import PropTypes from 'prop-types'
import { StaticQuery, graphql } from 'gatsby'
import Models from './models'
@ -13,98 +12,99 @@ import Sidebar from '../components/sidebar'
import Main from '../components/main'
import { getCurrentSource, github } from '../components/util'
const Docs = ({ pageContext, children }) => (
<StaticQuery
query={query}
render={({ site }) => {
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 })) : []
import siteMetadata from '../../meta/site.json'
import sidebars from '../../meta/sidebars.json'
import models from '../../meta/languages.json'
import { nightly, legacy } from '../../meta/dynamicMeta'
if (isModels) {
sidebar.items[1].items = languages
.filter(({ models }) => models && models.length)
.sort((a, b) => a.name.localeCompare(b.name))
.map((lang) => ({
text: lang.name,
url: `/models/${lang.code}`,
isActive: id === lang.code,
menu: lang.models.map((model) => ({
text: model,
id: model,
})),
}))
}
const sourcePath = source ? github(source) : null
const currentSource = getCurrentSource(slug, isIndex)
const Docs = ({ pageContext, children }) => {
const {
id,
slug,
title,
section,
teaser,
source,
tag,
isIndex,
next,
menu,
theme,
version,
apiDetails,
} = 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 = (
<Grid cols={2}>
<div style={{ marginTop: 'var(--spacing-lg)' }}>
{(!isModels || (isModels && isIndex)) && (
<Button to={currentSource} icon="code">
Suggest edits
</Button>
)}
</div>
{next && <ReadNext title={next.title} to={next.slug} />}
</Grid>
)
if (isModels) {
sidebar.items[1].items = languages
.filter(({ models }) => models && models.length)
.sort((a, b) => a.name.localeCompare(b.name))
.map((lang) => ({
text: lang.name,
url: `/models/${lang.code}`,
isActive: id === lang.code,
menu: lang.models.map((model) => ({
text: model,
id: model,
})),
}))
}
const sourcePath = source ? github(source) : null
const currentSource = getCurrentSource(slug, isIndex)
return (
<>
{sidebar && <Sidebar items={sidebar.items} pageMenu={pageMenu} slug={slug} />}
<Main
section={section}
theme={nightly ? 'nightly' : legacy ? 'legacy' : theme}
sidebar
asides
wrapContent
footer={<Footer />}
>
{isModels && !isIndex ? (
<Models pageContext={pageContext} repo={modelsRepo}>
{subFooter}
</Models>
) : (
<>
<Title
title={title}
teaser={teaser}
source={sourcePath}
tag={tag}
version={version}
id="_title"
apiDetails={apiDetails}
/>
{children}
{subFooter}
</>
)}
</Main>
</>
)
}}
/>
)
const subFooter = (
<Grid cols={2}>
<div style={{ marginTop: 'var(--spacing-lg)' }}>
{(!isModels || (isModels && isIndex)) && (
<Button to={currentSource} icon="code">
Suggest edits
</Button>
)}
</div>
{next && <ReadNext title={next.title} to={next.slug} />}
</Grid>
)
return (
<>
{sidebar && <Sidebar items={sidebar.items} pageMenu={pageMenu} slug={slug} />}
<Main
section={section}
theme={nightly ? 'nightly' : legacy ? 'legacy' : theme}
sidebar
asides
wrapContent
footer={<Footer />}
>
{isModels && !isIndex ? (
<Models pageContext={pageContext} repo={modelsRepo}>
{subFooter}
</Models>
) : (
<>
<Title
title={title}
teaser={teaser}
source={sourcePath}
tag={tag}
version={version}
id="_title"
apiDetails={apiDetails}
/>
{children}
{subFooter}
</>
)}
</Main>
</>
)
}
Docs.propTypes = {
pageContext: PropTypes.shape({
@ -125,32 +125,3 @@ Docs.propTypes = {
}
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 PropTypes from 'prop-types'
import { graphql } from 'gatsby'
import { MDXProvider } from '@mdx-js/tag'
import { withMDXScope } from 'gatsby-mdx/context'
import useOnlineStatus from '@rehooks/online-status'
@ -18,70 +17,13 @@ import Progress from '../components/progress'
import Footer from '../components/footer'
import SEO from '../components/seo'
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 { InlineCode } from '../components/code'
import Alert from '../components/alert'
import Search from '../components/search'
import Project from '../widgets/project'
import { Integration, IntegrationLogo } from '../widgets/integration'
const mdxComponents = {
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,
}
const scopeComponents = {
Infobox,
Table,
Tr,
Tx,
Th,
Td,
Help,
Button,
YouTube,
SoundCloud,
Iframe,
GoogleSheet,
Abbr,
Tag,
Accordion,
Grid,
InlineCode,
Project,
Integration,
IntegrationLogo,
}
import siteMetadata from '../../meta/site.json'
import { nightly, legacy } from '../../meta/dynamicMeta'
import { remarkComponents } from '../remark'
const AlertSpace = ({ nightly, legacy }) => {
const isOnline = useOnlineStatus()
@ -112,7 +54,7 @@ const AlertSpace = ({ nightly, legacy }) => {
)}
{!isOnline && (
<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>
)}
</>
@ -160,20 +102,19 @@ class Layout extends React.Component {
// NB: Compiling the scope here instead of in render() is super
// important! Otherwise, it triggers unnecessary rerenders of ALL
// consumers (e.g. mdx elements), even on anchor navigation!
this.state = { scope: { ...scopeComponents, ...props.scope } }
this.state = { scope: { ...remarkComponents, ...props.scope } }
}
render() {
const { data, pageContext, location, children } = this.props
const { file, site = {} } = data || {}
const mdx = file ? file.childMdx : null
const meta = site.siteMetadata || {}
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 isDocs = ['usage', 'models', 'api', 'styleguide'].includes(section)
const content = !mdx ? null : (
<MDXProvider components={mdxComponents}>
<MDXProvider components={remarkComponents}>
<MDXRenderer scope={this.state.scope}>{mdx.code.body}</MDXRenderer>
</MDXProvider>
)
@ -182,21 +123,21 @@ class Layout extends React.Component {
<>
<SEO
title={title}
description={teaser || meta.description}
description={teaser || siteMetadata.description}
section={section}
sectionTitle={sectionTitle}
bodyClass={bodyClass}
nightly={meta.nightly}
nightly={nightly}
/>
<AlertSpace nightly={meta.nightly} legacy={meta.legacy} />
<AlertSpace nightly={nightly} legacy={legacy} />
<Navigation
title={meta.title}
items={meta.navigation}
title={siteMetadata.title}
items={siteMetadata.navigation}
section={section}
search={<Search settings={meta.docSearch} />}
alert={meta.nightly ? null : navAlert}
search={<Search settings={siteMetadata.docSearch} />}
alert={nightly ? null : navAlert}
>
<Progress key={location.href} />
<Progress />
</Navigation>
{isDocs ? (
<Docs pageContext={pageContext}>{content}</Docs>
@ -219,33 +160,3 @@ class Layout extends React.Component {
}
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 { StaticQuery, graphql } from 'gatsby'
import { window } from 'browser-monads'
import Title from '../components/title'
@ -17,6 +16,9 @@ import Accordion from '../components/accordion'
import { join, arrayToObj, abbrNum, markdownToReact } from '../components/util'
import { isString, isEmptyObj } from '../components/util'
import siteMetadata from '../../meta/site.json'
import languages from '../../meta/languages.json'
const COMPONENT_LINKS = {
tok2vec: '/api/tok2vec',
transformer: '/api/transformer',
@ -367,7 +369,7 @@ const Model = ({
const labelNames = labels[pipe] || []
const help = LABEL_SCHEME_META[pipe]
return (
<Tr key={`${name}-${pipe}`} evenodd={false} key={pipe}>
<Tr evenodd={false} key={pipe}>
<Td style={{ width: '20%' }}>
<Label>
{pipe} {help && <Help>{help}</Help>}
@ -415,43 +417,23 @@ const Models = ({ pageContext, repo, children }) => {
return (
<>
<Title title={title} teaser={`Available trained pipelines for ${title}`} />
<StaticQuery
query={query}
render={({ site }) =>
models.map((modelName) => (
<Model
key={modelName}
name={modelName}
langId={id}
langName={title}
compatibility={compatibility}
baseUrl={baseUrl}
repo={repo}
licenses={arrayToObj(site.siteMetadata.licenses, 'id')}
hasExamples={meta.hasExamples}
prereleases={site.siteMetadata.nightly}
/>
))
}
/>
{models.map((modelName) => (
<Model
key={modelName}
name={modelName}
langId={id}
langName={title}
compatibility={compatibility}
baseUrl={baseUrl}
repo={repo}
licenses={arrayToObj(languages.licenses, 'id')}
hasExamples={meta.hasExamples}
prereleases={siteMetadata.nightly}
/>
))}
{children}
</>
)
}
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 PropTypes from 'prop-types'
import { StaticQuery, graphql } from 'gatsby'
import Card from '../components/card'
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 { github, markdownToReact } from '../components/util'
import { nightly, legacy } from '../../meta/dynamicMeta'
import universe from '../../meta/universe.json'
function getSlug(data) {
if (data.isCategory) return `/universe/category/${data.id}`
if (data.isProject) return `/universe/project/${data.id}`
@ -123,9 +125,9 @@ const UniverseContent = ({ content = [], categories, theme, pageContext, mdxComp
</Section>
)}
<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>
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{' '}
<Link to="https://github.com/explosion/spaCy/discussions/new">
opening a discussion thread
@ -234,7 +236,7 @@ const Project = ({ data, components }) => (
)}
{data.cran && (
<Aside title="Installation">
<CodeBlock lang="r">install.packages("{data.cran}")</CodeBlock>
<CodeBlock lang="r">install.packages(&quot;{data.cran}&quot;)</CodeBlock>
</Aside>
)}
@ -333,73 +335,18 @@ const Project = ({ data, components }) => (
</>
)
const Universe = ({ pageContext, location, mdxComponents }) => (
<StaticQuery
query={query}
render={(data) => {
const { universe, nightly, legacy } = data.site.siteMetadata
const theme = nightly ? 'nightly' : legacy ? 'legacy' : pageContext.theme
return (
<UniverseContent
content={universe.resources}
categories={universe.categories}
pageContext={pageContext}
location={location}
mdxComponents={mdxComponents}
theme={theme}
/>
)
}}
/>
)
const Universe = ({ pageContext, location, mdxComponents }) => {
const theme = nightly ? 'nightly' : legacy ? 'legacy' : pageContext.theme
return (
<UniverseContent
content={universe.resources}
categories={universe.categories}
pageContext={pageContext}
location={location}
mdxComponents={mdxComponents}
theme={theme}
/>
)
}
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 { graphql, StaticQuery } from 'gatsby'
import { Ul, Li } from '../components/list'
export default () => (
<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>
)
}}
/>
)
import models from '../../meta/languages.json'
const query = graphql`
query FeaturesQuery {
site {
siteMetadata {
counts {
langs
modelLangs
models
}
}
}
/**
* 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),
}
`
}
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 PropTypes from 'prop-types'
import { StaticQuery, graphql } from 'gatsby'
import {
LandingHeader,
@ -19,13 +18,15 @@ import { Ul, Li } from '../components/list'
import Button from '../components/button'
import Link from '../components/link'
import QuickstartTraining from './quickstart-training'
import Project from './project'
import Features from './features'
import QuickstartTraining from '../widgets/quickstart-training'
import Project from '../widgets/project'
import Features from '../widgets/features'
import Layout from '../components/layout'
import courseImage from '../../docs/images/course.jpg'
import prodigyImage from '../../docs/images/prodigy_overview.jpg'
import projectsImage from '../../docs/images/projects.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'
@ -56,8 +57,7 @@ for entity in doc.ents:
`
}
const Landing = ({ data }) => {
const { nightly, legacy } = data
const Landing = () => {
const codeExample = getCodeExample(nightly)
return (
<>
@ -75,15 +75,15 @@ const Landing = ({ data }) => {
<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
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
title="Blazing fast"
url="/usage/facts-figures"
button="Facts &amp; Figures"
>
spaCy excels at large-scale information extraction tasks. It's written from the
ground up in carefully memory-managed Cython. If your application needs to
spaCy excels at large-scale information extraction tasks. It&apos;s written from
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.
</LandingCard>
@ -115,33 +115,33 @@ const Landing = ({ data }) => {
<img src={tailoredPipelinesImage} alt="spaCy Tailored Pipelines" />
</Link>
<strong>
Get a custom spaCy pipeline, tailor-made for your NLP problem by spaCy's
core developers.
Get a custom spaCy pipeline, tailor-made for your NLP problem by
spaCy&apos;s core developers.
</strong>
<br />
<br />
<Ul>
<Li emoji="🔥">
<strong>Streamlined.</strong> Nobody knows spaCy better than we do. Send
us your pipeline requirements and we'll be ready to start producing your
solution in no time at all.
us your pipeline requirements and we&apos;ll be ready to start producing
your solution in no time at all.
</Li>
<Li emoji="🐿 ">
<strong>Production ready.</strong> spaCy pipelines are robust and easy
to deploy. You'll get a complete spaCy project folder which is ready to{' '}
<InlineCode>spacy project run</InlineCode>.
to deploy. You&apos;ll get a complete spaCy project folder which is
ready to <InlineCode>spacy project run</InlineCode>.
</Li>
<Li emoji="🔮">
<strong>Predictable.</strong> You'll know exactly what you're going to
get and what it's going to cost. We quote fees up-front, let you try
before you buy, and don't charge for over-runs at our end all the risk
is on us.
<strong>Predictable.</strong> You&apos;ll know exactly what you&apos;re
going to get and what it&apos;s going to cost. We quote fees up-front,
let you try before you buy, and don&apos;t charge for over-runs at our
end all the risk is on us.
</Li>
<Li emoji="🛠">
<strong>Maintainable.</strong> spaCy is an industry standard, and we'll
deliver your pipeline with full code, data, tests and documentation, so
your team can retrain, update and extend the solution as your
requirements change.
<strong>Maintainable.</strong> spaCy is an industry standard, and
we&apos;ll deliver your pipeline with full code, data, tests and
documentation, so your team can retrain, update and extend the solution
as your requirements change.
</Li>
</Ul>
</LandingBanner>
@ -166,7 +166,7 @@ const Landing = ({ data }) => {
<br />
Prodigy is an <strong>annotation tool</strong> so efficient that data scientists
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
models faster.
</LandingBanner>
@ -214,7 +214,7 @@ const Landing = ({ data }) => {
<LandingCol>
<H2>End-to-end workflows from prototype to production</H2>
<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{' '}
<strong>data transformation</strong>, preprocessing and{' '}
<strong>training steps</strong>, so you can make sure your project is always
@ -237,11 +237,11 @@ const Landing = ({ data }) => {
small
>
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>
. You can use any pretrained transformer to train your own pipelines, and even
share one transformer between multiple components with{' '}
<strong>multi-task learning</strong>. Training is now fully configurable and
extensible, and you can define your own custom models using{' '}
bring spaCy&apos;s accuracy right up to the current{' '}
<strong>state-of-the-art</strong>. You can use any pretrained transformer to
train your own pipelines, and even share one transformer between multiple
components with <strong>multi-task learning</strong>. Training is now fully
configurable and extensible, and you can define your own custom models using{' '}
<strong>PyTorch</strong>, <strong>TensorFlow</strong> and other frameworks.
</LandingBanner>
<LandingBanner
@ -271,7 +271,7 @@ const Landing = ({ data }) => {
<LandingCol>
<H2>Benchmarks</H2>
<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
also use a CPU-optimized pipeline, which is less accurate but much cheaper
to run.
@ -289,29 +289,4 @@ const Landing = ({ data }) => {
)
}
Landing.propTypes = {
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
}
}
}
`
export default Landing

View File

@ -1,5 +1,4 @@
import React from 'react'
import { StaticQuery, graphql } from 'gatsby'
import Link from '../components/link'
import { InlineCode } from '../components/code'
@ -8,6 +7,8 @@ import { Ul, Li } from '../components/list'
import Infobox from '../components/infobox'
import { github, join } from '../components/util'
import models from '../../meta/languages.json'
const Language = ({ name, code, models }) => (
<Tr>
<Td>{name}</Td>
@ -31,75 +32,54 @@ const Language = ({ name, code, models }) => (
</Tr>
)
const Languages = () => (
<StaticQuery
query={query}
render={({ site }) => {
const langs = site.siteMetadata.languages
const withModels = langs
.filter(({ models }) => models && !!models.length)
.sort((a, b) => a.name.localeCompare(b.name))
const withoutModels = langs
.filter(({ models }) => !models || !models.length)
.sort((a, b) => a.name.localeCompare(b.name))
const withDeps = langs.filter(({ dependencies }) => dependencies && dependencies.length)
return (
<>
<Table>
<thead>
<Tr>
<Th>Language</Th>
<Th>Code</Th>
<Th>Language Data</Th>
<Th>Pipelines</Th>
</Tr>
</thead>
<tbody>
{withModels.map((model) => (
<Language {...model} key={model.code} />
))}
{withoutModels.map((model) => (
<Language {...model} key={model.code} />
))}
</tbody>
</Table>
<Infobox title="Dependencies">
<p>Some language tokenizers require external dependencies.</p>
<Ul>
{withDeps.map(({ code, name, dependencies }) => (
<Li key={code}>
<strong>{name}:</strong>{' '}
{join(
dependencies.map((dep, i) => (
<Link to={dep.url}>{dep.name}</Link>
))
)}
</Li>
))}
</Ul>
</Infobox>
</>
)
}}
/>
)
const Languages = () => {
const langs = models.languages
const withModels = langs
.filter(({ models }) => models && !!models.length)
.sort((a, b) => a.name.localeCompare(b.name))
const withoutModels = langs
.filter(({ models }) => !models || !models.length)
.sort((a, b) => a.name.localeCompare(b.name))
const withDeps = langs.filter(({ dependencies }) => dependencies && dependencies.length)
return (
<>
<Table>
<thead>
<Tr>
<Th>Language</Th>
<Th>Code</Th>
<Th>Language Data</Th>
<Th>Pipelines</Th>
</Tr>
</thead>
<tbody>
{withModels.map((model) => (
<Language {...model} key={model.code} />
))}
{withoutModels.map((model) => (
<Language {...model} key={model.code} />
))}
</tbody>
</Table>
<Infobox title="Dependencies">
<p>Some language tokenizers require external dependencies.</p>
<Ul>
{withDeps.map(({ code, name, dependencies }) => (
<Li key={code}>
<strong>{name}:</strong>{' '}
{join(
dependencies.map((dep, i) => (
<Link key={i} to={dep.url}>
{dep.name}
</Link>
))
)}
</Li>
))}
</Ul>
</Infobox>
</>
)
}
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 { StaticQuery, graphql } from 'gatsby'
import { Quickstart, QS } from '../components/quickstart'
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_PLATFORM = 'x86'
@ -51,215 +52,178 @@ const QuickstartInstall = ({ id, title }) => {
]
.filter((e) => e)
.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 pkg = modelOptions[efficiency ? 0 : modelOptions.length - 1]
return (
<QS models={code} key={code}>
python -m spacy download {pkg}
</QS>
)
})}
</Quickstart>
const { nightly } = siteMetadata
const pkg = nightly ? 'spacy-nightly' : 'spacy'
const languages = models.languages.filter(({ models }) => !!models)
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: 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
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 { StaticQuery, graphql } from 'gatsby'
import { Quickstart, QS } from '../components/quickstart'
import models from '../../meta/languages.json'
const DEFAULT_LANG = 'en'
const DEFAULT_OPT = 'efficiency'
@ -62,80 +62,59 @@ const QuickstartInstall = ({ id, title, description, children }) => {
lang: setLang,
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}
</Quickstart>
const languages = models.languages.filter(({ models }) => !!models)
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
const query = graphql`
query QuickstartModelsQuery {
site {
siteMetadata {
languages {
code
name
models
example
}
}
}
}
`

View File

@ -1,10 +1,10 @@
import React, { useState } from 'react'
import { StaticQuery, graphql } from 'gatsby'
import highlightCode from 'gatsby-remark-prismjs/highlight-code.js'
import { Quickstart } from '../components/quickstart'
import generator, { DATA as GENERATOR_DATA } from './quickstart-training-generator'
import { htmlToReact } from '../components/util'
import models from '../../meta/languages.json'
const DEFAULT_LANG = 'en'
const DEFAULT_HARDWARE = 'cpu'
@ -112,54 +112,31 @@ export default function QuickstartTraining({ id, title, download = 'base_config.
.split('\n')
.map((line) => (line.startsWith('#') ? `<span class="token comment">${line}</span>` : line))
.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 (
<StaticQuery
query={query}
render={({ site }) => {
let data = DATA
const langs = site.siteMetadata.languages
data[0].dropdown = langs
.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 (
<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>
)
}}
/>
<Quickstart
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
}
}
}
}
`