diff --git a/.eslintrc.js b/.eslintrc.js index a162b92f5f0..33f1a5acf21 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -12,15 +12,8 @@ module.exports = { 'plugin:import/recommended', 'prettier', ], - settings: { - import: { - ignore: ['^theme$'], - }, - }, rules: { 'react/prop-types': 'off', - // our theme use exports which dont work with import/no-unresolved - 'import/no-unresolved': ['error', {ignore: ['^theme$']}], }, overrides: [ { diff --git a/.github/workflows/ci-theme.yml b/.github/workflows/ci-theme.yml deleted file mode 100644 index 93d23570bbc..00000000000 --- a/.github/workflows/ci-theme.yml +++ /dev/null @@ -1,175 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: CI - theme - -on: - workflow_dispatch: - pull_request: - paths: - - theme/** - push: - branches: - - main - paths: - - theme/** - schedule: - # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1 - - cron: "0 9 * * 1" - -jobs: - lint: - name: Lint - if: github.repository_owner == 'npm' - runs-on: ubuntu-latest - defaults: - run: - shell: bash - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - id: node - with: - node-version: 18.x - check-latest: contains('18.x', '.x') - cache: npm - - # node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows - - name: Update Windows npm - if: | - matrix.platform.os == 'windows-latest' && ( - startsWith(steps.node.outputs.node-version, 'v10.') || startsWith(steps.node.outputs.node-version, 'v12.') || startsWith(steps.node.outputs.node-version, 'v14.') - ) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - # Start on Node 10 because we dont test on anything lower - - name: Install npm@7 on Node 10 - shell: bash - if: startsWith(steps.node.outputs.node-version, 'v10.') - id: npm-7 - run: | - npm i --prefer-online --no-fund --no-audit -g npm@7 - echo "updated=true" >> "$GITHUB_OUTPUT" - - - name: Install npm@8 on Node 12 - shell: bash - if: startsWith(steps.node.outputs.node-version, 'v12.') - id: npm-8 - run: | - npm i --prefer-online --no-fund --no-audit -g npm@8 - echo "updated=true" >> "$GITHUB_OUTPUT" - - - name: Install npm@9 on Node 14/16/18.0 - shell: bash - if: startsWith(steps.node.outputs.node-version, 'v14.') || startsWith(steps.node.outputs.node-version, 'v16.') || startsWith(steps.node.outputs.node-version, 'v18.0.') - id: npm-9 - run: | - npm i --prefer-online --no-fund --no-audit -g npm@9 - echo "updated=true" >> "$GITHUB_OUTPUT" - - - name: Install npm@latest on Node - if: ${{ !(steps.npm-7.outputs.updated || steps.npm-8.outputs.updated || steps.npm-9.outputs.updated) }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --no-audit --no-fund - - name: Lint - run: npm run lint --ignore-scripts -w theme - - name: Post Lint - run: npm run postlint --ignore-scripts -w theme - - test: - name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} - if: github.repository_owner == 'npm' - strategy: - fail-fast: false - matrix: - platform: - - name: Linux - os: ubuntu-latest - shell: bash - node-version: - - 18.x - runs-on: ${{ matrix.platform.os }} - defaults: - run: - shell: ${{ matrix.platform.shell }} - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Git User - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - name: Setup Node - uses: actions/setup-node@v3 - id: node - with: - node-version: ${{ matrix.node-version }} - check-latest: contains(matrix.node-version, '.x') - cache: npm - - # node 10/12/14 ship with npm@6, which is known to fail when updating itself in windows - - name: Update Windows npm - if: | - matrix.platform.os == 'windows-latest' && ( - startsWith(steps.node.outputs.node-version, 'v10.') || startsWith(steps.node.outputs.node-version, 'v12.') || startsWith(steps.node.outputs.node-version, 'v14.') - ) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - # Start on Node 10 because we dont test on anything lower - - name: Install npm@7 on Node 10 - shell: bash - if: startsWith(steps.node.outputs.node-version, 'v10.') - id: npm-7 - run: | - npm i --prefer-online --no-fund --no-audit -g npm@7 - echo "updated=true" >> "$GITHUB_OUTPUT" - - - name: Install npm@8 on Node 12 - shell: bash - if: startsWith(steps.node.outputs.node-version, 'v12.') - id: npm-8 - run: | - npm i --prefer-online --no-fund --no-audit -g npm@8 - echo "updated=true" >> "$GITHUB_OUTPUT" - - - name: Install npm@9 on Node 14/16/18.0 - shell: bash - if: startsWith(steps.node.outputs.node-version, 'v14.') || startsWith(steps.node.outputs.node-version, 'v16.') || startsWith(steps.node.outputs.node-version, 'v18.0.') - id: npm-9 - run: | - npm i --prefer-online --no-fund --no-audit -g npm@9 - echo "updated=true" >> "$GITHUB_OUTPUT" - - - name: Install npm@latest on Node - if: ${{ !(steps.npm-7.outputs.updated || steps.npm-8.outputs.updated || steps.npm-9.outputs.updated) }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - - name: npm Version - run: npm -v - - name: Install Dependencies - run: npm i --no-audit --no-fund - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - - name: Test - run: npm test --ignore-scripts -w theme diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0816f4ccf94..849612835f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,13 +7,11 @@ on: pull_request: paths-ignore: - cli/** - - theme/** push: branches: - main paths-ignore: - cli/** - - theme/** schedule: # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1 - cron: "0 9 * * 1" diff --git a/.gitignore b/.gitignore index 76179b2041b..5b2679dce33 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,3 @@ !/tap-snapshots/ !/test/ !/cli/ -!/theme/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4a0b7c1372d..d88d5fac1c4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,11 +10,10 @@ This is the documentation for [https://docs.npmjs.com/](https://docs.npmjs.com/) - [Navigation](#navigation) - [CLI](#cli) - [Deploying changes](#deploying-changes) -- [Theme](#theme) ## Quick start -1. `npm install` to download Gatsby, our theme, and the dependencies +1. `npm install` to download Gatsby and all the dependencies 2. `npm run develop`: starts the test server at `http://localhost:8000`. 3. Update the content - it's MDX, which is like Markdown - in the `content` directory. 4. Review your content at `http://localhost:8000`. (Gatsby watches the filesystem and will reload your content changes immediately.) @@ -109,7 +108,7 @@ The content pages should include [frontmatter](https://jekyllrb.com/docs/front-m ## Navigation -The site's navigation (on the left-hand sidebar of the site) is controlled by `src/theme/nav.yml`. If you add or remove a page from the site, you'll also want to add or remove it from the navigation configuration. +The site's navigation (on the left-hand sidebar of the site) is controlled by `src/nav.yml`. If you add or remove a page from the site, you'll also want to add or remove it from the navigation configuration. ## CLI @@ -147,7 +146,3 @@ The docs site (https://docs.npmjs.com/) is published from a [GitHub Actions work 3. Merge that pull request On step three, your changes will be published live! 🎉 - -## Theme - -The Gatsby theme used here is located in the [`theme/`](./theme) directory. It is a variation of [doctocat](https://github.com/primer/doctocat) with some theme changes for npm's design language and additional components to support multiple versions of the CLI documentation. diff --git a/README.md b/README.md index de38e2c6f09..b049181164c 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,6 @@ This is the documentation for [https://docs.npmjs.com/](https://docs.npmjs.com/) Do you want to know more? Check out our [contributing guide](CONTRIBUTING.md). -## Theme - -The gatsby theme used here is located in the [`theme/`](./theme) directory. It is a variation of [doctocat](https://github.com/primer/doctocat) with some theme changes for npm's design language and additional components to support multiple versions of the CLI documentation. - ## License The npm product documentation in the content, and static folders are licensed under a [CC-BY 4.0 license](LICENSE). diff --git a/theme/gatsby-browser.js b/gatsby-browser.js similarity index 100% rename from theme/gatsby-browser.js rename to gatsby-browser.js diff --git a/gatsby-config.js b/gatsby-config.js index fb6c04eb81d..88080b5455c 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -1,3 +1,45 @@ +const path = require('path') +const fs = require('fs') + +const {NODE_ENV, GATSBY_PARTIAL_CONTENT, GATSBY_CONTENT_DIR = 'content'} = process.env +const DEV = NODE_ENV === 'development' +const CONTENT_DIR = path.resolve(__dirname, '..', GATSBY_CONTENT_DIR) + +const walkDirs = dir => { + const dirs = fs + .readdirSync(dir) + .filter(d => fs.statSync(path.join(dir, d)).isDirectory()) + .map(p => path.join(dir, p)) + const nested = dirs.flatMap(d => walkDirs(d)) + return [...dirs, ...nested] +} + +const getContentOptions = () => { + if (!DEV || !GATSBY_PARTIAL_CONTENT) { + return + } + + const partialContent = (GATSBY_PARTIAL_CONTENT ?? '').split(',') + + const paths = walkDirs(CONTENT_DIR) + .map(p => path.relative(CONTENT_DIR, p)) + .sort() + .reduce( + (acc, p) => { + const include = partialContent.some(partial => partial.startsWith(p)) + acc[include ? 'include' : 'ignore'].push(p) + return acc + }, + {include: [], ignore: []}, + ) + + console.log(`Only including the following partial content in dev mode:\n - ${paths.include.join('\n - ')}`) + + return { + ignore: paths.ignore, + } +} + module.exports = { trailingSlash: 'never', siteMetadata: { @@ -10,15 +52,34 @@ module.exports = { }, plugins: [ { - resolve: './theme', + resolve: 'gatsby-plugin-styled-components', + }, + 'gatsby-plugin-react-helmet', + 'gatsby-plugin-catch-links', + 'gatsby-transformer-yaml', + { + resolve: 'gatsby-plugin-mdx', options: { - icon: './src/images/favicon.png', - showContributors: false, - repo: { - url: 'https://github.com/npm/documentation', - defaultBranch: 'main', + extensions: ['.mdx', '.md'], + defaultLayouts: { + default: require.resolve('./src/layout/default.js'), }, }, }, + { + resolve: 'gatsby-source-filesystem', + options: { + name: 'content', + path: CONTENT_DIR, + ...getContentOptions(), + }, + }, + { + resolve: 'gatsby-plugin-manifest', + options: { + icon: path.resolve('./src/images/favicon.png'), + }, + }, + 'gatsby-plugin-meta-redirect', ], } diff --git a/gatsby-node.js b/gatsby-node.js index 866a892ba0e..7b0b73078be 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,5 +1,12 @@ const path = require('path') +const DEV = process.env.NODE_ENV === 'development' +const SHOW_CONTRIBUTORS = false +const REPO = { + url: 'https://github.com/npm/documentation', + defaultBranch: 'main', +} + exports.onCreateNode = ({node, actions, getNode}) => { if (node.internal.type === 'Mdx') { const {name, relativeDirectory: dir} = getNode(node.parent) @@ -31,3 +38,215 @@ exports.onCreateWebpackConfig = ({actions}) => { }, }) } + +exports.createSchemaCustomization = ({actions: {createTypes}}) => { + createTypes(` + type Mdx implements Node { + frontmatter: MdxFrontmatter + fields: MdxFields + } + type MdxFrontmatter { + github_repo: String, + github_branch: String, + github_path: String, + edit_on_github: Boolean, + slug: String, + redirect_from: [String] + } + type MdxFields { + slug: String + } + `) +} + +exports.createPages = async ({graphql, actions}) => { + const rootAbsolutePath = process.cwd() + + const {data} = await graphql(` + { + allMdx { + nodes { + id + fileAbsolutePath + fields { + slug + } + frontmatter { + title + github_repo + github_branch + github_path + edit_on_github + slug + redirect_from + } + tableOfContents + parent { + ... on File { + relativeDirectory + name + } + } + } + } + } + `) + + // Turn every MDX file into a page. + return Promise.all( + data.allMdx.nodes.map(async node => { + const {id, frontmatter, fileAbsolutePath, tableOfContents = {}} = node + + const pagePath = getPath(node) + const relativePath = path.relative(rootAbsolutePath, fileAbsolutePath) + const editUrl = getEditUrl(REPO, relativePath, frontmatter) + + const contributors = SHOW_CONTRIBUTORS ? await fetchContributors(REPO, relativePath, frontmatter) : {} + + // Fix some old CLI pages which have mismatched headings at the top level. + // All top level headings should be the same level. + const toc = tableOfContents.items?.reduce((acc, item) => { + if (!item.url && Array.isArray(item.items)) { + acc.push(...item.items) + } else { + acc.push(item) + } + return acc + }, []) + + actions.createPage({ + path: pagePath, + component: fileAbsolutePath, + context: { + mdxId: id, + editUrl, + contributors, + tableOfContents: toc, + repositoryUrl: REPO.url, + }, + }) + + if (!DEV) { + for (const from of frontmatter.redirect_from ?? []) { + actions.createRedirect({ + fromPath: from, + toPath: `/${pagePath}`, + isPermanent: true, + redirectInBrowser: true, + }) + + if (pagePath.startsWith('cli/') && !from.endsWith('index')) { + actions.createRedirect({ + fromPath: `${from}.html`, + toPath: `/${pagePath}`, + isPermanent: true, + redirectInBrowser: true, + }) + } + } + } + }), + ) +} + +function getPath(node) { + // sites can programmatically override slug, that takes priority + if (node.fields && node.fields.slug) { + return node.fields.slug + } + + // then a slug specified in frontmatter + if (node.frontmatter && node.frontmatter.slug) { + return node.frontmatter.slug + } + + // finally, we'll just use the path on disk + return path + .join(node.parent.relativeDirectory, node.parent.name === 'index' ? '/' : node.parent.name) + .replace(/\\/g, '/') // Windows paths to forward slashes +} + +function getGitHubData(repo, overrideData, filePath) { + const gh = { + nwo: new URL(repo.url).pathname.slice(1).split('/'), + branch: 'master', + } + + if (overrideData.github_repo) { + gh.nwo = overrideData.github_repo + } + + if (overrideData.github_branch) { + gh.branch = overrideData.github_branch + } else if (repo.defaultBranch) { + gh.branch = repo.defaultBranch + } + + if (overrideData.github_path) { + gh.path = overrideData.github_path + } else { + gh.path = filePath + } + + return gh +} + +function getEditUrl(repo, filePath, overrideData = {}) { + if (overrideData.edit_on_github === false) { + return null + } + + const gh = getGitHubData(repo, overrideData, filePath) + return `https://github.com/${gh.nwo}/edit/${gh.branch}/${gh.path}` +} + +const CONTRIBUTOR_CACHE = new Map() + +async function fetchContributors(repo, filePath, overrideData = {}) { + if (!process.env.GITHUB_TOKEN) { + console.warn('Skipping fetching contributors because no github token was set') + return + } + + const gh = getGitHubData(repo, overrideData, filePath) + const key = JSON.stringify(gh) + + const cached = CONTRIBUTOR_CACHE.get(key) + if (cached) { + return cached + } + + try { + const resp = await fetch( + `https://api.github.com/repos/${gh.nwo}/commits?path=${gh.path}&sha=${gh.branch}&per_page=100`, + { + headers: { + Authorization: `token ${process.env.GITHUB_TOKEN}`, + }, + }, + ) + + const logins = new Set() + let latestCommit = null + + for (const item of await resp.json().then(r => r.data)) { + if (item.author?.login) { + logins.add(item.author.login) + if (!latestCommit) { + latestCommit = { + login: item.author.login, + date: item.commit.author.date, + url: item.html_url, + } + } + } + } + + const result = {logins: [...logins], latestCommit} + CONTRIBUTOR_CACHE.set(key, result) + return result + } catch (error) { + console.error(`[ERROR] Unable to fetch contributors for ${filePath}. ${error.message}`) + return [] + } +} diff --git a/theme/gatsby-ssr.js b/gatsby-ssr.js similarity index 100% rename from theme/gatsby-ssr.js rename to gatsby-ssr.js diff --git a/package-lock.json b/package-lock.json index 15db2eca055..e039afbb0cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,15 +8,37 @@ "name": "documentation", "version": "1.0.0", "workspaces": [ - "cli/", - "theme/" + "cli/" ], "dependencies": { + "@mdx-js/mdx": "^1.6.22", + "@mdx-js/react": "^1.6.22", + "@primer/octicons-react": "^19.8.0", "@primer/react": "^35.31.0", + "babel-plugin-styled-components": "^2.1.4", + "copy-to-clipboard": "^3.3.3", + "details-element-polyfill": "^2.4.0", + "downshift": "^8.2.2", + "framer-motion": "^3.10.6", + "fuse.js": "^3.6.1", "gatsby": "^4.25.7", + "gatsby-plugin-catch-links": "^4.25.0", + "gatsby-plugin-manifest": "^4.25.0", + "gatsby-plugin-mdx": "^3.20.0", + "gatsby-plugin-meta-redirect": "^1.1.1", + "gatsby-plugin-react-helmet": "^5.25.0", + "gatsby-plugin-styled-components": "^5.25.0", + "gatsby-source-filesystem": "^4.25.0", + "gatsby-transformer-yaml": "^4.25.0", + "github-slugger": "^2.0.0", + "lodash.debounce": "4.0.8", + "prism-react-renderer": "^0.2.0", "react": "^17.0.2", + "react-addons-text-content": "^0.0.4", "react-dom": "^17.0.2", - "theme": "^1.0.0" + "react-focus-on": "^3.9.1", + "react-helmet": "^6.1.0", + "styled-components": "^5.3.11" }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", @@ -32149,10 +32171,6 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, - "node_modules/theme": { - "resolved": "theme", - "link": true - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -34353,6 +34371,7 @@ }, "theme": { "version": "1.0.0", + "extraneous": true, "license": "MIT", "dependencies": { "@mdx-js/mdx": "^1.6.22", diff --git a/package.json b/package.json index 805db01f450..4690f00277f 100644 --- a/package.json +++ b/package.json @@ -24,15 +24,37 @@ "format": "prettier --write ." }, "workspaces": [ - "cli/", - "theme/" + "cli/" ], "dependencies": { + "@mdx-js/mdx": "^1.6.22", + "@mdx-js/react": "^1.6.22", + "@primer/octicons-react": "^19.8.0", "@primer/react": "^35.31.0", + "babel-plugin-styled-components": "^2.1.4", + "copy-to-clipboard": "^3.3.3", + "details-element-polyfill": "^2.4.0", + "downshift": "^8.2.2", + "framer-motion": "^3.10.6", + "fuse.js": "^3.6.1", "gatsby": "^4.25.7", + "gatsby-plugin-catch-links": "^4.25.0", + "gatsby-plugin-manifest": "^4.25.0", + "gatsby-plugin-mdx": "^3.20.0", + "gatsby-plugin-meta-redirect": "^1.1.1", + "gatsby-plugin-react-helmet": "^5.25.0", + "gatsby-plugin-styled-components": "^5.25.0", + "gatsby-source-filesystem": "^4.25.0", + "gatsby-transformer-yaml": "^4.25.0", + "github-slugger": "^2.0.0", + "lodash.debounce": "4.0.8", + "prism-react-renderer": "^0.2.0", "react": "^17.0.2", + "react-addons-text-content": "^0.0.4", "react-dom": "^17.0.2", - "theme": "^1.0.0" + "react-focus-on": "^3.9.1", + "react-helmet": "^6.1.0", + "styled-components": "^5.3.11" }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", diff --git a/theme/src/components/__tests__/contributors.test.js b/src/components/__tests__/contributors.test.js similarity index 100% rename from theme/src/components/__tests__/contributors.test.js rename to src/components/__tests__/contributors.test.js diff --git a/theme/src/components/__tests__/page-footer.test.js b/src/components/__tests__/page-footer.test.js similarity index 100% rename from theme/src/components/__tests__/page-footer.test.js rename to src/components/__tests__/page-footer.test.js diff --git a/theme/src/components/clipboard-copy.js b/src/components/clipboard-copy.js similarity index 100% rename from theme/src/components/clipboard-copy.js rename to src/components/clipboard-copy.js diff --git a/theme/src/components/container.js b/src/components/container.js similarity index 100% rename from theme/src/components/container.js rename to src/components/container.js diff --git a/theme/src/components/contributors.js b/src/components/contributors.js similarity index 100% rename from theme/src/components/contributors.js rename to src/components/contributors.js diff --git a/theme/src/components/dark-button.js b/src/components/dark-button.js similarity index 100% rename from theme/src/components/dark-button.js rename to src/components/dark-button.js diff --git a/theme/src/components/dark-text-input.js b/src/components/dark-text-input.js similarity index 100% rename from theme/src/components/dark-text-input.js rename to src/components/dark-text-input.js diff --git a/theme/src/components/drawer.js b/src/components/drawer.js similarity index 100% rename from theme/src/components/drawer.js rename to src/components/drawer.js diff --git a/theme/src/components/head.js b/src/components/head.js similarity index 100% rename from theme/src/components/head.js rename to src/components/head.js diff --git a/theme/src/components/header.js b/src/components/header.js similarity index 97% rename from theme/src/components/header.js rename to src/components/header.js index 82032bebae1..edc7704336a 100644 --- a/theme/src/components/header.js +++ b/src/components/header.js @@ -30,7 +30,7 @@ function Header({location, repositoryUrl}) { } return ( - + props => { +const getActiveClass = props => { const location = NavHierarchy.getLocation(props.location.pathname) const href = NavHierarchy.getLocation(props.href) - - if (NavHierarchy.isActiveUrl(location, href)) { - return {className: `${className} active`} - } - - return {className: `${className}`} + return NavHierarchy.isActiveUrl(location, href) ? 'active' : '' } const ActiveLink = ({className, children, ...props}) => ( - + ({className: `${className} ${getActiveClass(p)}`})} {...props}> {children} ) @@ -126,11 +121,7 @@ function secondLevelItems(items, path) { {item.title} - {item.description != null ? ( - <> - {item.description} - - ) : null} + {item.description != null ? {item.description} : null} {thirdLevelItems(children, path)} diff --git a/theme/src/components/npm-logo.js b/src/components/npm-logo.js similarity index 100% rename from theme/src/components/npm-logo.js rename to src/components/npm-logo.js diff --git a/theme/src/components/page-footer.js b/src/components/page-footer.js similarity index 100% rename from theme/src/components/page-footer.js rename to src/components/page-footer.js diff --git a/theme/src/components/search-results.js b/src/components/search-results.js similarity index 100% rename from theme/src/components/search-results.js rename to src/components/search-results.js diff --git a/theme/src/components/search.js b/src/components/search.js similarity index 100% rename from theme/src/components/search.js rename to src/components/search.js diff --git a/theme/src/components/sidebar.js b/src/components/sidebar.js similarity index 100% rename from theme/src/components/sidebar.js rename to src/components/sidebar.js diff --git a/theme/src/components/table-of-contents.js b/src/components/table-of-contents.js similarity index 100% rename from theme/src/components/table-of-contents.js rename to src/components/table-of-contents.js diff --git a/theme/src/components/variant-select.js b/src/components/variant-select.js similarity index 100% rename from theme/src/components/variant-select.js rename to src/components/variant-select.js diff --git a/src/theme/header-nav.yml b/src/header-nav.yml similarity index 100% rename from src/theme/header-nav.yml rename to src/header-nav.yml diff --git a/theme/src/hooks/use-breakpoint.js b/src/hooks/use-breakpoint.js similarity index 100% rename from theme/src/hooks/use-breakpoint.js rename to src/hooks/use-breakpoint.js diff --git a/theme/src/hooks/use-scroll-size.js b/src/hooks/use-scroll-size.js similarity index 100% rename from theme/src/hooks/use-scroll-size.js rename to src/hooks/use-scroll-size.js diff --git a/theme/src/hooks/use-search.js b/src/hooks/use-search.js similarity index 95% rename from theme/src/hooks/use-search.js rename to src/hooks/use-search.js index cd132f0eb3c..f00fb22209d 100644 --- a/theme/src/hooks/use-search.js +++ b/src/hooks/use-search.js @@ -4,6 +4,9 @@ import {navigate, graphql, useStaticQuery} from 'gatsby' import {useIsMobile} from './use-breakpoint' const useSearchData = () => { + // TODO: this static query runs for all pages changes in dev mode. + // When not testing search explicitly it should be replaced with + // some static data. const rawData = useStaticQuery(graphql` { allMdx { diff --git a/theme/src/hooks/use-site-metadata.js b/src/hooks/use-site-metadata.js similarity index 100% rename from theme/src/hooks/use-site-metadata.js rename to src/hooks/use-site-metadata.js diff --git a/theme/src/hooks/use-slugger.js b/src/hooks/use-slugger.js similarity index 100% rename from theme/src/hooks/use-slugger.js rename to src/hooks/use-slugger.js diff --git a/theme/src/layout/default.js b/src/layout/default.js similarity index 100% rename from theme/src/layout/default.js rename to src/layout/default.js diff --git a/theme/src/layout/hero.js b/src/layout/hero.js similarity index 100% rename from theme/src/layout/hero.js rename to src/layout/hero.js diff --git a/theme/src/mdx/code.js b/src/mdx/code.js similarity index 100% rename from theme/src/mdx/code.js rename to src/mdx/code.js diff --git a/theme/src/mdx/index.js b/src/mdx/index.js similarity index 100% rename from theme/src/mdx/index.js rename to src/mdx/index.js diff --git a/theme/src/mdx/nav-hierarchy.js b/src/mdx/nav-hierarchy.js similarity index 100% rename from theme/src/mdx/nav-hierarchy.js rename to src/mdx/nav-hierarchy.js diff --git a/src/theme/nav.yml b/src/nav.yml similarity index 100% rename from src/theme/nav.yml rename to src/nav.yml diff --git a/theme/src/page-element.js b/src/page-element.js similarity index 100% rename from theme/src/page-element.js rename to src/page-element.js diff --git a/theme/src/root-element.js b/src/root-element.js similarity index 100% rename from theme/src/root-element.js rename to src/root-element.js diff --git a/src/shared.js b/src/shared.js index 0f94370d755..f4ff110a8ab 100644 --- a/src/shared.js +++ b/src/shared.js @@ -1,5 +1,5 @@ import React from 'react' -import {Link, Note, Screenshot} from 'theme' +import {Link, Note, Screenshot} from './mdx' const shared = { /* User login */ diff --git a/theme/src/util/aria-live.js b/src/util/aria-live.js similarity index 100% rename from theme/src/util/aria-live.js rename to src/util/aria-live.js diff --git a/theme/src/util/nav-hierarchy.js b/src/util/nav-hierarchy.js similarity index 100% rename from theme/src/util/nav-hierarchy.js rename to src/util/nav-hierarchy.js diff --git a/theme/src/util/search.worker.js b/src/util/search.worker.js similarity index 100% rename from theme/src/util/search.worker.js rename to src/util/search.worker.js diff --git a/theme/.gitignore b/theme/.gitignore deleted file mode 100644 index fcff975a1b0..00000000000 --- a/theme/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -# ignore everything in the root -/* - -# keep these -!**/.gitignore -!/.eslintrc.js -!/.eslintrc.local.* -!/.gitignore -!/bin/ -!/CHANGELOG* -!/docs/ -!/gatsby-*.js -!/lib/ -!/LICENSE* -!/map.js -!/package.json -!/README* -!/scripts/ -!/src -!/tap-snapshots/ -!/test/ diff --git a/theme/LICENSE b/theme/LICENSE deleted file mode 100644 index 3a807b6b611..00000000000 --- a/theme/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) GitHub, Inc. - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/theme/README.md b/theme/README.md deleted file mode 100644 index 0d9e7bceacc..00000000000 --- a/theme/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# theme - -```javascript -// gatsby-config.js - -module.exports = { - plugins: [ - { - resolve: './theme', - options: { - icon: './path/to/favicon.png', - showContributors: false, - repo: { - url: 'https://github.com/org/repo', - defaultBranch: 'main', - }, - }, - }, - ], -} -``` - -## Theme Options - -| Option | Required | Default | Type | Description | -| ---------------- | -------- | ------- | ------- | ------------------------------------------------------- | -| icon | yes | n/a | string | The favicon to display | -| showContributors | yes | n/a | boolean | Determines if the repository contributors are displayed | -| repo | yes | n/a | object | `url` and `defaultBranch` to repository | diff --git a/theme/gatsby-config.js b/theme/gatsby-config.js deleted file mode 100644 index 03c891f85e4..00000000000 --- a/theme/gatsby-config.js +++ /dev/null @@ -1,76 +0,0 @@ -const path = require('path') -const fs = require('fs') - -const {NODE_ENV, GATSBY_PARTIAL_CONTENT, GATSBY_CONTENT_DIR = 'content'} = process.env -const DEV = NODE_ENV === 'development' -const CONTENT_DIR = path.resolve(__dirname, '..', GATSBY_CONTENT_DIR) - -const walkDirs = dir => { - const dirs = fs - .readdirSync(dir) - .filter(d => fs.statSync(path.join(dir, d)).isDirectory()) - .map(p => path.join(dir, p)) - const nested = dirs.flatMap(d => walkDirs(d)) - return [...dirs, ...nested] -} - -const getContentOptions = () => { - if (!DEV || !GATSBY_PARTIAL_CONTENT) { - return - } - - const partialContent = (GATSBY_PARTIAL_CONTENT ?? '').split(',') - - const paths = walkDirs(CONTENT_DIR) - .map(p => path.relative(CONTENT_DIR, p)) - .sort() - .reduce( - (acc, p) => { - const include = partialContent.some(partial => partial.startsWith(p)) - acc[include ? 'include' : 'ignore'].push(p) - return acc - }, - {include: [], ignore: []}, - ) - - console.log(`Only including the following partial content in dev mode:\n - ${paths.include.join('\n - ')}`) - - return { - ignore: paths.ignore, - } -} - -module.exports = ({icon}) => ({ - plugins: [ - { - resolve: 'gatsby-plugin-styled-components', - }, - 'gatsby-plugin-react-helmet', - 'gatsby-plugin-catch-links', - 'gatsby-transformer-yaml', - { - resolve: 'gatsby-plugin-mdx', - options: { - extensions: ['.mdx', '.md'], - defaultLayouts: { - default: require.resolve('./src/layout/default.js'), - }, - }, - }, - { - resolve: 'gatsby-source-filesystem', - options: { - name: 'content', - path: CONTENT_DIR, - ...getContentOptions(), - }, - }, - { - resolve: 'gatsby-plugin-manifest', - options: { - icon: path.resolve(icon), - }, - }, - 'gatsby-plugin-meta-redirect', - ], -}) diff --git a/theme/gatsby-node.js b/theme/gatsby-node.js deleted file mode 100644 index dac9a27d0f0..00000000000 --- a/theme/gatsby-node.js +++ /dev/null @@ -1,215 +0,0 @@ -const path = require('path') - -const DEV = process.env.NODE_ENV === 'development' - -exports.createSchemaCustomization = ({actions: {createTypes}}) => { - createTypes(` - type Mdx implements Node { - frontmatter: MdxFrontmatter - fields: MdxFields - } - type MdxFrontmatter { - github_repo: String, - github_branch: String, - github_path: String, - edit_on_github: Boolean, - slug: String, - redirect_from: [String] - } - type MdxFields { - slug: String - } - `) -} - -exports.createPages = async ({graphql, actions}, {repo, showContributors}) => { - const rootAbsolutePath = process.cwd() - - const {data} = await graphql(` - { - allMdx { - nodes { - id - fileAbsolutePath - fields { - slug - } - frontmatter { - title - github_repo - github_branch - github_path - edit_on_github - slug - redirect_from - } - tableOfContents - parent { - ... on File { - relativeDirectory - name - } - } - } - } - } - `) - - // Turn every MDX file into a page. - return Promise.all( - data.allMdx.nodes.map(async node => { - const {id, frontmatter, fileAbsolutePath, tableOfContents = {}} = node - - const pagePath = getPath(node) - const relativePath = path.relative(rootAbsolutePath, fileAbsolutePath) - const editUrl = getEditUrl(repo, relativePath, frontmatter) - - const contributors = showContributors ? await fetchContributors(repo, relativePath, frontmatter) : {} - - // Fix some old CLI pages which have mismatched headings at the top level. - // All top level headings should be the same level. - const toc = tableOfContents.items?.reduce((acc, item) => { - if (!item.url && Array.isArray(item.items)) { - acc.push(...item.items) - } else { - acc.push(item) - } - return acc - }, []) - - actions.createPage({ - path: pagePath, - component: fileAbsolutePath, - context: { - mdxId: id, - editUrl, - contributors, - tableOfContents: toc, - repositoryUrl: repo.url, - }, - }) - - if (!DEV) { - for (const from of frontmatter.redirect_from ?? []) { - actions.createRedirect({ - fromPath: from, - toPath: `/${pagePath}`, - isPermanent: true, - redirectInBrowser: true, - }) - - if (pagePath.startsWith('cli/') && !from.endsWith('index')) { - actions.createRedirect({ - fromPath: `${from}.html`, - toPath: `/${pagePath}`, - isPermanent: true, - redirectInBrowser: true, - }) - } - } - } - }), - ) -} - -function getPath(node) { - // sites can programmatically override slug, that takes priority - if (node.fields && node.fields.slug) { - return node.fields.slug - } - - // then a slug specified in frontmatter - if (node.frontmatter && node.frontmatter.slug) { - return node.frontmatter.slug - } - - // finally, we'll just use the path on disk - return path - .join(node.parent.relativeDirectory, node.parent.name === 'index' ? '/' : node.parent.name) - .replace(/\\/g, '/') // Windows paths to forward slashes -} - -function getGitHubData(repo, overrideData, filePath) { - const gh = { - nwo: new URL(repo.url).pathname.slice(1).split('/'), - branch: 'master', - } - - if (overrideData.github_repo) { - gh.nwo = overrideData.github_repo - } - - if (overrideData.github_branch) { - gh.branch = overrideData.github_branch - } else if (repo.defaultBranch) { - gh.branch = repo.defaultBranch - } - - if (overrideData.github_path) { - gh.path = overrideData.github_path - } else { - gh.path = filePath - } - - return gh -} - -function getEditUrl(repo, filePath, overrideData = {}) { - if (overrideData.edit_on_github === false) { - return null - } - - const gh = getGitHubData(repo, overrideData, filePath) - return `https://github.com/${gh.nwo}/edit/${gh.branch}/${gh.path}` -} - -const CONTRIBUTOR_CACHE = new Map() - -async function fetchContributors(repo, filePath, overrideData = {}) { - if (!process.env.GITHUB_TOKEN) { - console.warn('Skipping fetching contributors because no github token was set') - return - } - - const gh = getGitHubData(repo, overrideData, filePath) - const key = JSON.stringify(gh) - - const cached = CONTRIBUTOR_CACHE.get(key) - if (cached) { - return cached - } - - try { - const resp = await fetch( - `https://api.github.com/repos/${gh.nwo}/commits?path=${gh.path}&sha=${gh.branch}&per_page=100`, - { - headers: { - Authorization: `token ${process.env.GITHUB_TOKEN}`, - }, - }, - ) - - const logins = new Set() - let latestCommit = null - - for (const item of await resp.json().then(r => r.data)) { - if (item.author?.login) { - logins.add(item.author.login) - if (!latestCommit) { - latestCommit = { - login: item.author.login, - date: item.commit.author.date, - url: item.html_url, - } - } - } - } - - const result = {logins: [...logins], latestCommit} - CONTRIBUTOR_CACHE.set(key, result) - return result - } catch (error) { - console.error(`[ERROR] Unable to fetch contributors for ${filePath}. ${error.message}`) - return [] - } -} diff --git a/theme/package.json b/theme/package.json deleted file mode 100644 index 108d5bad3a9..00000000000 --- a/theme/package.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "theme", - "version": "1.0.0", - "repository": { - "url": "https://github.com/npm/documentation.git", - "directory": "theme", - "type": "git" - }, - "private": true, - "exports": { - ".": "./src/mdx/index.js", - "./layout/*.js": "./src/layout/*.js" - }, - "license": "MIT", - "scripts": { - "test": "jest", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "template-oss-apply": "template-oss-apply --force", - "lintfix": "npm run lint -- --fix", - "snap": "tap", - "posttest": "npm run lint", - "format": "prettier --write ." - }, - "peerDependencies": { - "gatsby": "^4.25.7", - "react": "^17.0.2", - "react-dom": "^17.0.2" - }, - "dependencies": { - "@mdx-js/mdx": "^1.6.22", - "@mdx-js/react": "^1.6.22", - "@primer/octicons-react": "^19.8.0", - "@primer/react": "^35.31.0", - "babel-plugin-styled-components": "^2.1.4", - "copy-to-clipboard": "^3.3.3", - "details-element-polyfill": "^2.4.0", - "downshift": "^8.2.2", - "framer-motion": "^3.10.6", - "fuse.js": "^3.6.1", - "gatsby-plugin-catch-links": "^4.25.0", - "gatsby-plugin-manifest": "^4.25.0", - "gatsby-plugin-mdx": "^3.20.0", - "gatsby-plugin-meta-redirect": "^1.1.1", - "gatsby-plugin-react-helmet": "^5.25.0", - "gatsby-plugin-styled-components": "^5.25.0", - "gatsby-source-filesystem": "^4.25.0", - "gatsby-transformer-yaml": "^4.25.0", - "github-slugger": "^2.0.0", - "lodash.debounce": "4.0.8", - "prism-react-renderer": "^0.2.0", - "react-addons-text-content": "^0.0.4", - "react-focus-on": "^3.9.1", - "react-helmet": "^6.1.0", - "styled-components": "^5.3.11" - }, - "devDependencies": { - "@npmcli/template-oss": "4.19.0" - }, - "author": "GitHub Inc.", - "engines": { - "node": ">=18.0.0" - }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.19.0", - "content": "./scripts/template-oss" - } -} diff --git a/theme/scripts/template-oss/index.js b/theme/scripts/template-oss/index.js deleted file mode 100644 index cbbbcc00e13..00000000000 --- a/theme/scripts/template-oss/index.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - ...require('../../../scripts/template-oss'), - allowPaths: ['/src', '/gatsby-*.js'], -} diff --git a/theme/src/header-nav.yml b/theme/src/header-nav.yml deleted file mode 100644 index c085d7c38a2..00000000000 --- a/theme/src/header-nav.yml +++ /dev/null @@ -1,2 +0,0 @@ -# For shadowing only -[] diff --git a/theme/src/nav.yml b/theme/src/nav.yml deleted file mode 100644 index c085d7c38a2..00000000000 --- a/theme/src/nav.yml +++ /dev/null @@ -1,2 +0,0 @@ -# For shadowing only -[]