diff --git a/website/README.md b/website/README.md index a8fa9c175..1083665ee 100644 --- a/website/README.md +++ b/website/README.md @@ -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 diff --git a/website/docs/api/morphology.mdx b/website/docs/api/morphology.mdx index 565e520b5..080f1c3fe 100644 --- a/website/docs/api/morphology.mdx +++ b/website/docs/api/morphology.mdx @@ -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"} diff --git a/website/docs/api/sentencizer.mdx b/website/docs/api/sentencizer.mdx index f5017fbdb..2a1d6a119 100644 --- a/website/docs/api/sentencizer.mdx +++ b/website/docs/api/sentencizer.mdx @@ -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]~~ | diff --git a/website/docs/api/token.mdx b/website/docs/api/token.mdx index 89bd77447..1eef1f4cd 100644 --- a/website/docs/api/token.mdx +++ b/website/docs/api/token.mdx @@ -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. diff --git a/website/docs/styleguide.mdx b/website/docs/styleguide.mdx index 78b2c1d75..1f0899082 100644 --- a/website/docs/styleguide.mdx +++ b/website/docs/styleguide.mdx @@ -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 > diff --git a/website/gatsby-config.js b/website/gatsby-config.js index 1d919dc33..ca3c75aad 100644 --- a/website/gatsby-config.js +++ b/website/gatsby-config.js @@ -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`, diff --git a/website/gatsby-node.js b/website/gatsby-node.js index 4a580eb03..caa507db6 100644 --- a/website/gatsby-node.js +++ b/website/gatsby-node.js @@ -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}` diff --git a/website/meta/dynamicMeta.js b/website/meta/dynamicMeta.js new file mode 100644 index 000000000..da3031c13 --- /dev/null +++ b/website/meta/dynamicMeta.js @@ -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, +} diff --git a/website/meta/site.json b/website/meta/site.json index fa79d3c69..5dcb89443 100644 --- a/website/meta/site.json +++ b/website/meta/site.json @@ -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" }, diff --git a/website/runtime.txt b/website/runtime.txt index 475ba515c..cc1923a40 100644 --- a/website/runtime.txt +++ b/website/runtime.txt @@ -1 +1 @@ -3.7 +3.8 diff --git a/website/src/components/accordion.js b/website/src/components/accordion.js index 00596326f..504f415a5 100644 --- a/website/src/components/accordion.js +++ b/website/src/components/accordion.js @@ -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}> diff --git a/website/src/components/code.js b/website/src/components/code.js index c4a3640f6..28e3cb5d4 100644 --- a/website/src/components/code.js +++ b/website/src/components/code.js @@ -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} · Python 3 · 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} · Python 3 · 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> + ) +} diff --git a/website/src/components/footer.js b/website/src/components/footer.js index df19443f2..759db8a7b 100644 --- a/website/src/components/footer.js +++ b/website/src/components/footer.js @@ -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> - © 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> + © 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 - } - } - } - } -` diff --git a/website/src/components/infobox.js b/website/src/components/infobox.js index 6df8426b8..d17cbc285 100644 --- a/website/src/components/infobox.js +++ b/website/src/components/infobox.js @@ -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} diff --git a/website/src/components/landing.js b/website/src/components/landing.js index de054ddce..ec8cf88d6 100644 --- a/website/src/components/landing.js +++ b/website/src/components/landing.js @@ -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}> diff --git a/website/src/components/link.js b/website/src/components/link.js index 4f4442679..917b009b7 100644 --- a/website/src/components/link.js +++ b/website/src/components/link.js @@ -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> diff --git a/website/src/components/quickstart.js b/website/src/components/quickstart.js index 0ea88c621..e5d4e00be 100644 --- a/website/src/components/quickstart.js +++ b/website/src/components/quickstart.js @@ -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} diff --git a/website/src/components/seo.js b/website/src/components/seo.js index b32501948..a426317af 100644 --- a/website/src/components/seo.js +++ b/website/src/components/seo.js @@ -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 - } - } - } - } -` diff --git a/website/src/components/typography.js b/website/src/components/typography.js index 959dc0285..e05948ff5 100644 --- a/website/src/components/typography.js +++ b/website/src/components/typography.js @@ -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> diff --git a/website/src/components/util.js b/website/src/components/util.js index 2b9c6fd4f..e3d5aef65 100644 --- a/website/src/components/util.js +++ b/website/src/components/util.js @@ -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 diff --git a/website/src/pages/404.js b/website/src/pages/404.js index 53baebab9..29ff29bca 100644 --- a/website/src/pages/404.js +++ b/website/src/pages/404.js @@ -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 diff --git a/website/src/remark.js b/website/src/remark.js new file mode 100644 index 000000000..5c4f019a0 --- /dev/null +++ b/website/src/remark.js @@ -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, +} diff --git a/website/src/styles/aside.module.sass b/website/src/styles/aside.module.sass index 1ea3f970a..aca74a33a 100644 --- a/website/src/styles/aside.module.sass +++ b/website/src/styles/aside.module.sass @@ -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) diff --git a/website/src/styles/code.module.sass b/website/src/styles/code.module.sass index aa1f499dd..142b9fbd4 100644 --- a/website/src/styles/code.module.sass +++ b/website/src/styles/code.module.sass @@ -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) diff --git a/website/src/styles/embed.module.sass b/website/src/styles/embed.module.sass index 1eaf7b8d2..fdb740951 100644 --- a/website/src/styles/embed.module.sass +++ b/website/src/styles/embed.module.sass @@ -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 diff --git a/website/src/styles/grid.module.sass b/website/src/styles/grid.module.sass index 482ad03cf..7bf8ebd56 100644 --- a/website/src/styles/grid.module.sass +++ b/website/src/styles/grid.module.sass @@ -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 diff --git a/website/src/styles/layout.sass b/website/src/styles/layout.sass index b9b5c02dc..4df924b60 100644 --- a/website/src/styles/layout.sass +++ b/website/src/styles/layout.sass @@ -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 diff --git a/website/src/styles/quickstart.module.sass b/website/src/styles/quickstart.module.sass index d0f9db551..fb9f0b17b 100644 --- a/website/src/styles/quickstart.module.sass +++ b/website/src/styles/quickstart.module.sass @@ -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) diff --git a/website/src/styles/search.module.sass b/website/src/styles/search.module.sass index 7a20ea821..8ac4d0b0e 100644 --- a/website/src/styles/search.module.sass +++ b/website/src/styles/search.module.sass @@ -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 diff --git a/website/src/styles/sidebar.module.sass b/website/src/styles/sidebar.module.sass index ace19e6a4..36809dfbe 100644 --- a/website/src/styles/sidebar.module.sass +++ b/website/src/styles/sidebar.module.sass @@ -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) diff --git a/website/src/templates/docs.js b/website/src/templates/docs.js index 6c684f725..c593e0360 100644 --- a/website/src/templates/docs.js +++ b/website/src/templates/docs.js @@ -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 - } - } - } - } - } - } -` diff --git a/website/src/templates/index.js b/website/src/templates/index.js index 438e5b91e..0b48f6e93 100644 --- a/website/src/templates/index.js +++ b/website/src/templates/index.js @@ -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'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 - } - } - } - } -` diff --git a/website/src/templates/models.js b/website/src/templates/models.js index e19edda8b..d946d5836 100644 --- a/website/src/templates/models.js +++ b/website/src/templates/models.js @@ -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 - } - } - } - } -` diff --git a/website/src/templates/universe.js b/website/src/templates/universe.js index 6db6d0fb2..80f3d25df 100644 --- a/website/src/templates/universe.js +++ b/website/src/templates/universe.js @@ -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't working?</H3> <p> - If you've come across a universe project that isn't working or is + If you've come across a universe project that isn'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("{data.cran}")</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 - } - } - } - } - } - } -` diff --git a/website/src/widgets/features.js b/website/src/widgets/features.js index 73863d5cc..23864d1eb 100644 --- a/website/src/widgets/features.js +++ b/website/src/widgets/features.js @@ -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 diff --git a/website/src/widgets/landing.js b/website/src/widgets/landing.js index 5d1ca1432..3fb45414f 100644 --- a/website/src/widgets/landing.js +++ b/website/src/widgets/landing.js @@ -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's easy to install, and its API is simple and productive. </LandingCard> <LandingCard title="Blazing fast" url="/usage/facts-figures" button="Facts & 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'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'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'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'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'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. </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'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'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'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'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'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 diff --git a/website/src/widgets/languages.js b/website/src/widgets/languages.js index 14c3f23bf..9f5f9e23f 100644 --- a/website/src/widgets/languages.js +++ b/website/src/widgets/languages.js @@ -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 - } - } - } - } - } -` diff --git a/website/src/widgets/quickstart-install.js b/website/src/widgets/quickstart-install.js index a64188e16..dbbbf0fe5 100644 --- a/website/src/widgets/quickstart-install.js +++ b/website/src/widgets/quickstart-install.js @@ -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 - } - } - } - } -` diff --git a/website/src/widgets/quickstart-models.js b/website/src/widgets/quickstart-models.js index af44788b5..b2a0a6280 100644 --- a/website/src/widgets/quickstart-models.js +++ b/website/src/widgets/quickstart-models.js @@ -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("{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> ) } export default QuickstartInstall - -const query = graphql` - query QuickstartModelsQuery { - site { - siteMetadata { - languages { - code - name - models - example - } - } - } - } -` diff --git a/website/src/widgets/quickstart-training.js b/website/src/widgets/quickstart-training.js index 4c6051875..68971d2d9 100644 --- a/website/src/widgets/quickstart-training.js +++ b/website/src/widgets/quickstart-training.js @@ -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 - } - } - } - } -`