From 4806403e1f683b3fce965aa03e886c65efaea3e9 Mon Sep 17 00:00:00 2001 From: Nilu Date: Mon, 20 Apr 2020 18:12:56 +0200 Subject: [PATCH 1/8] matchpath --- gatsby-config.js | 8 ++-- gatsby-node.js | 64 +++++++++++-------------- src/components/layout.tsx | 1 - src/components/parentTitleComp.tsx | 1 - src/components/sidebar/tree.tsx | 4 +- src/components/sidebar/treeNode.tsx | 2 +- src/components/topSection.tsx | 18 +++++-- src/hooks/useAllArticlesQuery.ts | 10 ++-- src/interfaces/AllArticles.interface.ts | 3 +- src/interfaces/Article.interface.ts | 18 ++++--- src/interfaces/EdgeNode.interface.ts | 8 +++- src/layouts/articleLayout.tsx | 14 +----- src/utils/algolia.js | 5 +- src/utils/parentTitle.ts | 5 +- 14 files changed, 80 insertions(+), 81 deletions(-) diff --git a/gatsby-config.js b/gatsby-config.js index 39e9b111a8..e5bc661efb 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -7,10 +7,10 @@ const gatsbyRemarkPlugins = [ resolve: `gatsby-remark-autolink-headers`, options: { icon: ` - - - - + + + + `, className: `title-link`, }, diff --git a/gatsby-node.js b/gatsby-node.js index df60d1997d..e37315f87e 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,51 +1,26 @@ const path = require(`path`); -// const urlGenerator = require(`./src/utils/urlGenerator`) -// const { createFilePath } = require(`gatsby-source-filesystem`); exports.onCreateNode = ({ node, getNode, actions }) => { const { createNodeField } = actions; if (node.internal.type === `Mdx`) { const parent = getNode(node.parent); - let value = parent.relativePath.replace(parent.ext, ''); - if (value === 'index') { value = ''; } createNodeField({ - name: `slug`, node, + name: `slug`, value: `/${value}`, }); - createNodeField({ - name: 'id', - node, - value: node.id, - }); - createNodeField({ - name: 'title', - node, - value: node.frontmatter.title || parent.name, - }); - createNodeField({ - name: 'staticLink', - node, - value: node.frontmatter.staticLink || false, - }); - createNodeField({ - name: 'duration', - node, - value: node.frontmatter.duration || '', - }); - createNodeField({ - name: 'experimental', - node, - value: node.frontmatter.experimental || false, - }); } }; +// const matchesLangDb = (slug, langSwitcher, dbSwitcher) => { +// return `${slug.replace(/\d+-/g, '')}/*`; +// }; + exports.createPages = ({ graphql, actions }) => { const { createPage } = actions; return new Promise((resolve, reject) => { @@ -54,13 +29,13 @@ exports.createPages = ({ graphql, actions }) => { allMdx { edges { node { - fields { - id - } - tableOfContents fields { slug } + frontmatter { + langSwitcher + dbSwitcher + } } } } @@ -68,12 +43,29 @@ exports.createPages = ({ graphql, actions }) => { `).then(result => { result.data.allMdx.edges.forEach(({ node }) => { createPage({ - path: node.fields.slug ? node.fields.slug.replace(/\d+-/g, "") : '/', + path: node.fields.slug ? node.fields.slug.replace(/\d+-/g, '') : '/', component: path.resolve(`./src/layouts/articleLayout.tsx`), + matchPath: + node.frontmatter.langSwitcher || node.frontmatter.dbSwitcher + ? `${node.fields.slug.replace(/\d+-/g, '')}/*` + : ``, context: { - id: node.fields.id, + slug: node.fields.slug, }, }); + // if(node.frontmatter.langSwitcher) { + // node.frontmatter.langSwitcher.forEach(lang => createPage({ + // path: node.fields.slug ? `${node.fields.slug.replace(/\d+-/g, '')}-${lang}` : '/', + // component: path.resolve(`./src/layouts/articleLayout.tsx`), + // // matchPath: + // // node.frontmatter.langSwitcher || node.frontmatter.dbSwitcher + // // ? `${node.fields.slug.replace(/\d+-/g, '')}/*` + // // : ``, + // context: { + // slug: `${node.fields.slug.replace(/\d+-/g, '')}-${lang}` + // }, + // })) + // } }); resolve(); }); diff --git a/src/components/layout.tsx b/src/components/layout.tsx index 013ade1cf4..67a54d90b4 100644 --- a/src/components/layout.tsx +++ b/src/components/layout.tsx @@ -9,7 +9,6 @@ import { MDXProvider } from '@mdx-js/react'; import customMdx from '../components/customMdx'; import './layout.css'; import Sidebar from './sidebar'; -import Overlay from './search/overlay'; interface ThemeProps { colorPrimary: string; diff --git a/src/components/parentTitleComp.tsx b/src/components/parentTitleComp.tsx index 8006951630..aceb6b347c 100644 --- a/src/components/parentTitleComp.tsx +++ b/src/components/parentTitleComp.tsx @@ -17,7 +17,6 @@ interface ParentTitleProps { const ParentTitle = ({ slug }: ParentTitleProps) => { const { allMdx }: AllArticles = useAllArticlesQuery(); - const parentTitle = getParentTitle(slug, allMdx); return {parentTitle}; }; diff --git a/src/components/sidebar/tree.tsx b/src/components/sidebar/tree.tsx index 8121827ab6..ce2bec6e11 100644 --- a/src/components/sidebar/tree.tsx +++ b/src/components/sidebar/tree.tsx @@ -8,6 +8,7 @@ import { urlGenerator } from '../../utils/urlGenerator'; interface TreeNode { node: { fields: ArticleFields; + frontmatter: any; }; } @@ -27,7 +28,8 @@ const calculateTreeData = (edges: any) => { accu: any, { node: { - fields: { slug, title, staticLink, duration, experimental }, + fields: { slug }, + frontmatter: {title, staticLink, duration, experimental} }, }: TreeNode ) => { diff --git a/src/components/sidebar/treeNode.tsx b/src/components/sidebar/treeNode.tsx index 6be92d0d4a..92decfea71 100644 --- a/src/components/sidebar/treeNode.tsx +++ b/src/components/sidebar/treeNode.tsx @@ -163,7 +163,7 @@ const TreeNode = ({ {title && label !== 'index' && url !== '/01-getting-started/04-example' && ( {hasExpandButton ? ( diff --git a/src/components/topSection.tsx b/src/components/topSection.tsx index 07b6a95fcd..13576d5679 100644 --- a/src/components/topSection.tsx +++ b/src/components/topSection.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import TOC from './toc'; import TechnologySwitch from './techSwitcher'; import ParentTitle from './parentTitleComp'; -import { useNavigate } from '@reach/router'; +import { useNavigate, redirectTo } from '@reach/router'; import { urlGenerator } from '../utils/urlGenerator'; const TopSectionWrapper = styled.div` @@ -46,11 +46,19 @@ const TopSection = ({ location, title, slug, indexPage, langSwitcher, dbSwitcher ); const goToNewPath = () => { - const newParams = `?${langSwitcher ? `lang=${langSelected}${dbSwitcher ? '&' : ''}` : ''}${ - dbSwitcher ? `db=${dbSelected}` : '' + // const newParams = `?${langSwitcher ? `lang=${langSelected}${dbSwitcher ? '&' : ''}` : ''}${ + // dbSwitcher ? `db=${dbSelected}` : '' + // }`; + // if (!(location.pathname.includes(urlGenerator(slug)) && location.search === newParams)) { + // navigate(newParams); + // } + + console.log(location) + const newParams = `${langSwitcher ? `${langSelected}${dbSwitcher ? '-' : ''}` : ''}${ + dbSwitcher ? `${dbSelected}` : '' }`; - if (!(location.pathname.includes(urlGenerator(slug)) && location.search === newParams)) { - navigate(newParams); + if (!(location.pathname.includes(urlGenerator(slug)) && location.pathname.includes(newParams))) { + redirectTo(location.pathname + '/'+newParams); } }; diff --git a/src/hooks/useAllArticlesQuery.ts b/src/hooks/useAllArticlesQuery.ts index d7e2f2c43d..23d6f5fc69 100644 --- a/src/hooks/useAllArticlesQuery.ts +++ b/src/hooks/useAllArticlesQuery.ts @@ -7,14 +7,16 @@ export const useAllArticlesQuery = () => { allMdx(sort: { fields: fields___slug }) { edges { node { - rawBody - objectID: id - fields { - slug + frontmatter { title duration staticLink experimental + langSwitcher + dbSwitcher + } + fields { + slug } } } diff --git a/src/interfaces/AllArticles.interface.ts b/src/interfaces/AllArticles.interface.ts index 644d578c6c..e97d88ccea 100644 --- a/src/interfaces/AllArticles.interface.ts +++ b/src/interfaces/AllArticles.interface.ts @@ -1,8 +1,7 @@ import { EdgeNode } from './EdgeNode.interface'; -import { ArticleFields } from './Article.interface'; export interface AllEdges { - edges?: [EdgeNode]; + edges?: [EdgeNode]; } export interface AllArticles { diff --git a/src/interfaces/Article.interface.ts b/src/interfaces/Article.interface.ts index d48ea30d71..e94e713aa9 100644 --- a/src/interfaces/Article.interface.ts +++ b/src/interfaces/Article.interface.ts @@ -1,8 +1,13 @@ -import { AllEdges } from './AllArticles.interface'; - export interface ArticleFields { slug: string; +} + +export interface ArticleFrontmatter { title: string; + metaTitle?: string; + metaDescription?: string; + langSwitcher?: string[]; + dbSwitcher?: string[]; staticLink?: boolean; duration?: string; experimental?: boolean; @@ -13,15 +18,8 @@ export interface ArticleData { fields: ArticleFields; body: string; parent: any; - frontmatter: { - title: string; - metaTitle?: string; - metaDescription?: string; - langSwitcher?: string[]; - dbSwitcher?: string[]; - }; + frontmatter: ArticleFrontmatter; }; - allMdx: AllEdges; site: { siteMetadata: { docsLocation: string; diff --git a/src/interfaces/EdgeNode.interface.ts b/src/interfaces/EdgeNode.interface.ts index 21f9802f1e..cb5634a151 100644 --- a/src/interfaces/EdgeNode.interface.ts +++ b/src/interfaces/EdgeNode.interface.ts @@ -1,5 +1,9 @@ -export interface EdgeNode { +import { ArticleFrontmatter } from './Article.interface'; +import { ArticleFields } from './Article.interface'; + +export interface EdgeNode { node: { - frontmatter: { [Property in keyof Type]: Type[Property] }; + frontmatter: { [Property in keyof ArticleFrontmatter]: ArticleFrontmatter[Property] }; + fields: { [Property in keyof ArticleFields]: ArticleFields[Property] }; }; } diff --git a/src/layouts/articleLayout.tsx b/src/layouts/articleLayout.tsx index 1b6ea408ca..3bf192cfbb 100644 --- a/src/layouts/articleLayout.tsx +++ b/src/layouts/articleLayout.tsx @@ -53,13 +53,13 @@ const ArticleLayout = ({ data, ...props }: ArticleLayoutProps) => { export default ArticleLayout; export const query = graphql` - query($id: String!) { + query($slug: String!) { site { siteMetadata { docsLocation } } - mdx(fields: { id: { eq: $id } }) { + mdx(fields: { slug: { eq: $slug } }) { fields { slug } @@ -77,15 +77,5 @@ export const query = graphql` dbSwitcher } } - allMdx { - edges { - node { - fields { - slug - title - } - } - } - } } `; diff --git a/src/utils/algolia.js b/src/utils/algolia.js index a48110e76d..6932eabd55 100644 --- a/src/utils/algolia.js +++ b/src/utils/algolia.js @@ -33,10 +33,11 @@ const handleRawBody = node => { }; const unnestFrontmatter = node => { - const { fields, ...rest } = node; + const { fields, frontmatter, ...rest } = node; return { ...fields, + ...frontmatter, ...rest, }; }; @@ -56,6 +57,8 @@ const queries = [ rawBody fields { slug + } + frontmatter { title } } diff --git a/src/utils/parentTitle.ts b/src/utils/parentTitle.ts index 3a5c1aed10..2b70bf62b7 100644 --- a/src/utils/parentTitle.ts +++ b/src/utils/parentTitle.ts @@ -1,5 +1,8 @@ export const getParentTitle = (slug: string, allMdx?: any) => { - const allContent = allMdx && allMdx.edges && allMdx.edges.map((mdx: any) => mdx.node.fields); + const allContent = + allMdx && + allMdx.edges && + allMdx.edges.map((mdx: any) => ({ ...mdx.node.fields, ...mdx.node.frontmatter })); allContent?.map((content: any) => { content.parentTitle = ''; const parts = content.slug.split('/'); From 7ae04a1f6a6d1edecda0b70da0a3ba0f6b9e4246 Mon Sep 17 00:00:00 2001 From: Nilu Date: Tue, 21 Apr 2020 15:48:53 +0200 Subject: [PATCH 2/8] changeSEO --- gatsby-config.js | 10 ++--- gatsby-node.js | 52 ++++++++++++++--------- package.json | 4 +- src/components/seo.tsx | 28 +++++++----- src/components/topSection.tsx | 28 ++++++------ src/interfaces/Article.interface.ts | 11 +++++ src/layouts/articleLayout.tsx | 66 +++++++++++++++++++++++++---- src/utils/parentTitle.ts | 2 +- yarn.lock | 36 ++++++++-------- 9 files changed, 157 insertions(+), 80 deletions(-) diff --git a/gatsby-config.js b/gatsby-config.js index e5bc661efb..0df30aaf47 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -18,6 +18,7 @@ const gatsbyRemarkPlugins = [ { resolve: `gatsby-remark-images`, }, + 'gatsby-plugin-react-helmet' ]; if (process.env.NODE_ENV === 'development') { @@ -39,17 +40,16 @@ module.exports = { docsLocation: config.siteMetadata.docsLocation, }, plugins: [ - 'gatsby-plugin-react-helmet', 'gatsby-transformer-sharp', 'gatsby-plugin-sharp', 'gatsby-plugin-typescript', 'gatsby-image', 'gatsby-plugin-styled-components', `gatsby-plugin-smoothscroll`, - { - resolve: `gatsby-plugin-algolia`, - options: require(`./src/utils/algolia`), - }, + // { + // resolve: `gatsby-plugin-algolia`, + // options: require(`./src/utils/algolia`), + // }, { resolve: `gatsby-plugin-sitemap`, options: { diff --git a/gatsby-node.js b/gatsby-node.js index e37315f87e..0e798b4958 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -17,10 +17,6 @@ exports.onCreateNode = ({ node, getNode, actions }) => { } }; -// const matchesLangDb = (slug, langSwitcher, dbSwitcher) => { -// return `${slug.replace(/\d+-/g, '')}/*`; -// }; - exports.createPages = ({ graphql, actions }) => { const { createPage } = actions; return new Promise((resolve, reject) => { @@ -33,39 +29,53 @@ exports.createPages = ({ graphql, actions }) => { slug } frontmatter { + title + metaTitle + metaDescription langSwitcher dbSwitcher } + body + parent { + ... on File { + relativePath + } + } } } } } `).then(result => { result.data.allMdx.edges.forEach(({ node }) => { + // if (node.frontmatter.langSwitcher) { + // node.frontmatter.langSwitcher.forEach(lang => + // createPage({ + // path: `${node.fields.slug.replace(/\d+-/g, '')}-${lang}`, + // component: path.resolve(`./src/layouts/articleLayout.tsx`), + // context: { + // slug: `${node.fields.slug}-${lang}`, + // title: `${node.frontmatter.title}-${lang}`, + // frontmatter: node.frontmatter, + // parentSlug: node.fields.slug.replace(/\d+-/g, ''), + // parentPath: node.parent.relativePath, + // body: node.body, + // }, + // }) + // ); + // } createPage({ path: node.fields.slug ? node.fields.slug.replace(/\d+-/g, '') : '/', component: path.resolve(`./src/layouts/articleLayout.tsx`), - matchPath: - node.frontmatter.langSwitcher || node.frontmatter.dbSwitcher - ? `${node.fields.slug.replace(/\d+-/g, '')}/*` - : ``, context: { slug: node.fields.slug, + seoTitle: node.frontmatter.title, + // seoSlug: node.fields.slug + // frontmatter: node.frontmatter, + // parentSlug: node.fields.slug.replace(/\d+-/g, ''), + // parentPath: node.parent.relativePath, + // body: node.body, }, }); - // if(node.frontmatter.langSwitcher) { - // node.frontmatter.langSwitcher.forEach(lang => createPage({ - // path: node.fields.slug ? `${node.fields.slug.replace(/\d+-/g, '')}-${lang}` : '/', - // component: path.resolve(`./src/layouts/articleLayout.tsx`), - // // matchPath: - // // node.frontmatter.langSwitcher || node.frontmatter.dbSwitcher - // // ? `${node.fields.slug.replace(/\d+-/g, '')}/*` - // // : ``, - // context: { - // slug: `${node.fields.slug.replace(/\d+-/g, '')}-${lang}` - // }, - // })) - // } }); resolve(); }); diff --git a/package.json b/package.json index 660cf5b3c9..f95c5fc65b 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "gatsby-plugin-manifest": "^2.0.24", "gatsby-plugin-mdx": "^1.0.73", "gatsby-plugin-offline": "^2.0.25", - "gatsby-plugin-react-helmet": "^3.0.9", + "gatsby-plugin-react-helmet": "^3.2.4", "gatsby-plugin-remove-trailing-slashes": "^2.2.1", "gatsby-plugin-robots-txt": "^1.5.0", "gatsby-plugin-sharp": "^2.4.5", @@ -43,7 +43,7 @@ "react": "^16.8.4", "react-copy-to-clipboard": "^5.0.2", "react-dom": "^16.8.4", - "react-helmet": "^5.2.0", + "react-helmet": "^6.0.0", "react-hooks-global-state": "^1.0.0", "react-hooks-testing-library": "^0.3.6", "react-instantsearch-dom": "^6.4.0", diff --git a/src/components/seo.tsx b/src/components/seo.tsx index 948ff1c48d..f78cf4afc7 100644 --- a/src/components/seo.tsx +++ b/src/components/seo.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; -import Helmet from 'react-helmet'; +import {Helmet} from 'react-helmet'; import favicon from '../images/favicon-32x32.png'; import { useStaticQuery, graphql } from 'gatsby'; -import { useLocation } from '@reach/router'; +import { urlGenerator } from '../utils/urlGenerator'; type SEOProps = { title?: string; @@ -11,7 +11,7 @@ type SEOProps = { slug?: string; }; -const SEO = ({ title, description, keywords }: SEOProps) => { +const SEO = ({ title, description, keywords, slug }: SEOProps) => { const { site } = useStaticQuery(query); const { siteMetadata: { @@ -26,15 +26,21 @@ const SEO = ({ title, description, keywords }: SEOProps) => { }, } = site; - const location = useLocation(); - const searchParams = new URLSearchParams(location.search); - const canonicalUrl = location.href; - const lang = searchParams ? searchParams.get('lang') : ''; - const db = searchParams ? searchParams.get('db') : ''; + // const location = useLocation(); + // const searchParams = new URLSearchParams(location.search); + // const canonicalUrl = location.href; + // const lang = searchParams ? searchParams.get('lang') : ''; + // const db = searchParams ? searchParams.get('db') : ''; + + // const seoTitle = `${title}${lang ? '-' + lang.toUpperCase() : ''}${ + // db ? '-' + db.toUpperCase() : '' + // }`; + + const seoTitle = title; + + let canonicalUrl = pathPrefix ? siteUrl + pathPrefix : siteUrl; + canonicalUrl = slug ? canonicalUrl + urlGenerator(slug) : canonicalUrl; - const seoTitle = `${title}${lang ? '-' + lang.toUpperCase() : ''}${ - db ? '-' + db.toUpperCase() : '' - }`; return ( {/* */} diff --git a/src/components/topSection.tsx b/src/components/topSection.tsx index 13576d5679..6907388345 100644 --- a/src/components/topSection.tsx +++ b/src/components/topSection.tsx @@ -31,7 +31,7 @@ const SwitcherWrapper = styled.div` top: 78px; `; -const TopSection = ({ location, title, slug, indexPage, langSwitcher, dbSwitcher }: any) => { +const TopSection = ({ location, title, slug, indexPage, langSwitcher, dbSwitcher, onChangeParam }: any) => { const navigate = useNavigate(); const getTechFromParam = (type: string, defaultVal: string) => { const searchParam = new URLSearchParams(location.search).get(type); @@ -46,20 +46,22 @@ const TopSection = ({ location, title, slug, indexPage, langSwitcher, dbSwitcher ); const goToNewPath = () => { - // const newParams = `?${langSwitcher ? `lang=${langSelected}${dbSwitcher ? '&' : ''}` : ''}${ - // dbSwitcher ? `db=${dbSelected}` : '' - // }`; - // if (!(location.pathname.includes(urlGenerator(slug)) && location.search === newParams)) { - // navigate(newParams); - // } - - console.log(location) - const newParams = `${langSwitcher ? `${langSelected}${dbSwitcher ? '-' : ''}` : ''}${ - dbSwitcher ? `${dbSelected}` : '' + const newParams = `?${langSwitcher ? `lang=${langSelected}${dbSwitcher ? '&' : ''}` : ''}${ + dbSwitcher ? `db=${dbSelected}` : '' }`; - if (!(location.pathname.includes(urlGenerator(slug)) && location.pathname.includes(newParams))) { - redirectTo(location.pathname + '/'+newParams); + if (!(location.pathname.includes(urlGenerator(slug)) && location.search === newParams)) { + navigate(newParams); + onChangeParam(newParams); } + // const newParams = `${langSwitcher ? `${langSelected}${dbSwitcher ? '-' : ''}` : ''}${ + // dbSwitcher ? `${dbSelected}` : '' + // }`; + + // console.log(newParams); + // if (!(location.pathname.includes(urlGenerator(slug)) && location.pathname.includes(newParams))) { + // redirectTo(`${parentSlug}-${newParams}`); + // //redirectTo(`http://localhost:8000/getting-started/quickstart-${newParams}`) + // } }; // TODO : Simplify the function! diff --git a/src/interfaces/Article.interface.ts b/src/interfaces/Article.interface.ts index e94e713aa9..c14aa6a567 100644 --- a/src/interfaces/Article.interface.ts +++ b/src/interfaces/Article.interface.ts @@ -27,6 +27,17 @@ export interface ArticleData { }; } +// export interface ArticleData { +// sitePage: { +// context: any; +// }; +// site: { +// siteMetadata: { +// docsLocation: string; +// }; +// }; +// } + export interface ArticleQueryData { data: ArticleData; } diff --git a/src/layouts/articleLayout.tsx b/src/layouts/articleLayout.tsx index 3bf192cfbb..aaa74c3e27 100644 --- a/src/layouts/articleLayout.tsx +++ b/src/layouts/articleLayout.tsx @@ -17,13 +17,15 @@ const ArticleLayout = ({ data, ...props }: ArticleLayoutProps) => { const { mdx: { fields: { slug }, - frontmatter: { - title, - metaTitle, - metaDescription, - langSwitcher, - dbSwitcher - }, + frontmatter: { title, metaTitle, metaDescription, langSwitcher, dbSwitcher }, + // context: { + // slug, + // title, + // frontmatter: { title: fTitle, metaTitle, metaDescription, langSwitcher, dbSwitcher }, + // parentPath, + // parentSlug, + // body, + // }, body, parent, }, @@ -32,9 +34,29 @@ const ArticleLayout = ({ data, ...props }: ArticleLayoutProps) => { }, } = data; + const [seoDetails, setSEODetails] = React.useState({ + seoTitle: metaTitle || title, + seoUrl: slug, + }); + + const changeSEODetails = (newParams: string) => { + const lang = new URLSearchParams(newParams).get('lang'); + const db = new URLSearchParams(newParams).get('db'); + + console.log(lang, db) + setSEODetails({ + seoTitle: title + `-${lang}-${db}`, + seoUrl: slug + newParams, + }); + }; + return ( - +
{ slug={slug} langSwitcher={langSwitcher} dbSwitcher={dbSwitcher} + onChangeParam={changeSEODetails} + // parentSlug={parentSlug} />
{body} @@ -52,6 +76,32 @@ const ArticleLayout = ({ data, ...props }: ArticleLayoutProps) => { export default ArticleLayout; +// export const query = graphql` +// query($path: String!) { +// site { +// siteMetadata { +// docsLocation +// } +// } +// sitePage(path: { eq: $path }) { +// context { +// slug +// title +// frontmatter { +// title +// metaTitle +// metaDescription +// langSwitcher +// dbSwitcher +// } +// parentPath +// parentSlug +// body +// } +// } +// } +// `; + export const query = graphql` query($slug: String!) { site { diff --git a/src/utils/parentTitle.ts b/src/utils/parentTitle.ts index 2b70bf62b7..ba0c682803 100644 --- a/src/utils/parentTitle.ts +++ b/src/utils/parentTitle.ts @@ -19,5 +19,5 @@ export const getParentTitle = (slug: string, allMdx?: any) => { }); }); - return allContent?.find((mdx: any) => mdx.slug === slug).parentTitle.slice(0, -2); + return allContent?.find((mdx: any) => slug.includes(mdx.slug)).parentTitle.slice(0, -2); }; diff --git a/yarn.lock b/yarn.lock index e46d14bf31..311b5879da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6825,10 +6825,10 @@ gatsby-plugin-page-creator@^2.2.1: lodash "^4.17.15" micromatch "^3.1.10" -gatsby-plugin-react-helmet@^3.0.9: - version "3.2.1" - resolved "https://registry.yarnpkg.com/gatsby-plugin-react-helmet/-/gatsby-plugin-react-helmet-3.2.1.tgz#28a89e884e5447f7aefead2a80749e3745f5f5a9" - integrity sha512-5oarZdVvp3k3keG26eVFagVHLYw7wCGs/MXRYQg8MEyJewU3X4Uc0eo7qu4TM5EIuZ2ekaL14r86RB6RM5TORA== +gatsby-plugin-react-helmet@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/gatsby-plugin-react-helmet/-/gatsby-plugin-react-helmet-3.2.4.tgz#3a69488454a433c5cef5aa02263a8faffa8cabd1" + integrity sha512-AHmmhodv7E8+qkHC5W0XSTgoQb1iHMB15Jn4NnEnDz696pZ448g1MCnX3bEMGCjYg2wHKJlo29EVoa4z5dS5lw== dependencies: "@babel/runtime" "^7.8.7" @@ -12781,7 +12781,7 @@ react-error-overlay@^6.0.3: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA== -react-fast-compare@^2.0.2: +react-fast-compare@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== @@ -12791,15 +12791,15 @@ react-fast-compare@^3.0.0: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.0.1.tgz#884d339ce1341aad22392e7a88664c71da48600e" integrity sha512-C5vP0J644ofZGd54P8++O7AvrqMEbrGf8Ue0eAUJLJyw168dAX2aiYyX/zcY/eSNwO0IDjsKUaLE6n83D+TnEg== -react-helmet@^5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.1.tgz#16a7192fdd09951f8e0fe22ffccbf9bb3e591ffa" - integrity sha512-CnwD822LU8NDBnjCpZ4ySh8L6HYyngViTZLfBBb3NjtrpN8m49clH8hidHouq20I51Y6TpCTISCBbqiY5GamwA== +react-helmet@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.0.0.tgz#fcb93ebaca3ba562a686eb2f1f9d46093d83b5f8" + integrity sha512-My6S4sa0uHN/IuVUn0HFmasW5xj9clTkB9qmMngscVycQ5vVG51Qp44BEvLJ4lixupTwDlU9qX1/sCrMN4AEPg== dependencies: object-assign "^4.1.1" - prop-types "^15.5.4" - react-fast-compare "^2.0.2" - react-side-effect "^1.1.0" + prop-types "^15.7.2" + react-fast-compare "^2.0.4" + react-side-effect "^2.1.0" react-hooks-global-state@^1.0.0: version "1.0.0" @@ -12895,12 +12895,10 @@ react-refresh@^0.7.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.7.2.tgz#f30978d21eb8cac6e2f2fde056a7d04f6844dd50" integrity sha512-u5l7fhAJXecWUJzVxzMRU2Zvw8m4QmDNHlTrT5uo3KBlYBhmChd7syAakBoay1yIiVhx/8Fi7a6v6kQZfsw81Q== -react-side-effect@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.2.0.tgz#0e940c78faba0c73b9b0eba9cd3dda8dfb7e7dae" - integrity sha512-v1ht1aHg5k/thv56DRcjw+WtojuuDHFUgGfc+bFHOWsF4ZK6C2V57DO0Or0GPsg6+LSTE0M6Ry/gfzhzSwbc5w== - dependencies: - shallowequal "^1.0.1" +react-side-effect@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.0.tgz#1ce4a8b4445168c487ed24dab886421f74d380d3" + integrity sha512-IgmcegOSi5SNX+2Snh1vqmF0Vg/CbkycU9XZbOHJlZ6kMzTmi3yc254oB1WCkgA7OQtIAoLmcSFuHTc/tlcqXg== react-simple-code-editor@^0.10.0: version "0.10.0" @@ -13883,7 +13881,7 @@ shallow-compare@^1.2.2: resolved "https://registry.yarnpkg.com/shallow-compare/-/shallow-compare-1.2.2.tgz#fa4794627bf455a47c4f56881d8a6132d581ffdb" integrity sha512-LUMFi+RppPlrHzbqmFnINTrazo0lPNwhcgzuAXVVcfy/mqPDrQmHAyz5bvV0gDAuRFrk804V0HpQ6u9sZ0tBeg== -shallowequal@^1.0.1, shallowequal@^1.1.0: +shallowequal@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== From 51d944913f45ac86977734265bc3fe1ace212dd0 Mon Sep 17 00:00:00 2001 From: Nilu Date: Tue, 21 Apr 2020 19:35:21 +0200 Subject: [PATCH 3/8] Added --- gatsby-node.js | 43 +++++------ src/components/topSection.tsx | 32 ++++---- src/interfaces/Article.interface.ts | 32 ++++---- src/layouts/articleLayout.tsx | 114 ++++++++++++++-------------- 4 files changed, 110 insertions(+), 111 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index 0e798b4958..0d475d1804 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -47,33 +47,32 @@ exports.createPages = ({ graphql, actions }) => { } `).then(result => { result.data.allMdx.edges.forEach(({ node }) => { - // if (node.frontmatter.langSwitcher) { - // node.frontmatter.langSwitcher.forEach(lang => - // createPage({ - // path: `${node.fields.slug.replace(/\d+-/g, '')}-${lang}`, - // component: path.resolve(`./src/layouts/articleLayout.tsx`), - // context: { - // slug: `${node.fields.slug}-${lang}`, - // title: `${node.frontmatter.title}-${lang}`, - // frontmatter: node.frontmatter, - // parentSlug: node.fields.slug.replace(/\d+-/g, ''), - // parentPath: node.parent.relativePath, - // body: node.body, - // }, - // }) - // ); - // } + if (node.frontmatter.langSwitcher) { + node.frontmatter.langSwitcher.forEach(lang => + createPage({ + path: `${node.fields.slug.replace(/\d+-/g, '')}-${lang}`, + component: path.resolve(`./src/layouts/articleLayout.tsx`), + context: { + slug: `${node.fields.slug}-${lang}`, + title: `${node.frontmatter.title}-${lang}`, + frontmatter: node.frontmatter, + parentSlug: node.fields.slug.replace(/\d+-/g, ''), + parentPath: node.parent.relativePath, + body: node.body, + }, + }) + ); + } createPage({ path: node.fields.slug ? node.fields.slug.replace(/\d+-/g, '') : '/', component: path.resolve(`./src/layouts/articleLayout.tsx`), context: { slug: node.fields.slug, - seoTitle: node.frontmatter.title, - // seoSlug: node.fields.slug - // frontmatter: node.frontmatter, - // parentSlug: node.fields.slug.replace(/\d+-/g, ''), - // parentPath: node.parent.relativePath, - // body: node.body, + title: node.frontmatter.title, + frontmatter: node.frontmatter, + parentSlug: node.fields.slug.replace(/\d+-/g, ''), + parentPath: node.parent.relativePath, + body: node.body, }, }); }); diff --git a/src/components/topSection.tsx b/src/components/topSection.tsx index 6907388345..450ecb02b1 100644 --- a/src/components/topSection.tsx +++ b/src/components/topSection.tsx @@ -31,7 +31,7 @@ const SwitcherWrapper = styled.div` top: 78px; `; -const TopSection = ({ location, title, slug, indexPage, langSwitcher, dbSwitcher, onChangeParam }: any) => { +const TopSection = ({ location, title, slug, indexPage, langSwitcher, dbSwitcher, onChangeParam, parentSlug }: any) => { const navigate = useNavigate(); const getTechFromParam = (type: string, defaultVal: string) => { const searchParam = new URLSearchParams(location.search).get(type); @@ -46,22 +46,22 @@ const TopSection = ({ location, title, slug, indexPage, langSwitcher, dbSwitcher ); const goToNewPath = () => { - const newParams = `?${langSwitcher ? `lang=${langSelected}${dbSwitcher ? '&' : ''}` : ''}${ - dbSwitcher ? `db=${dbSelected}` : '' - }`; - if (!(location.pathname.includes(urlGenerator(slug)) && location.search === newParams)) { - navigate(newParams); - onChangeParam(newParams); - } - // const newParams = `${langSwitcher ? `${langSelected}${dbSwitcher ? '-' : ''}` : ''}${ - // dbSwitcher ? `${dbSelected}` : '' + // const newParams = `?${langSwitcher ? `lang=${langSelected}${dbSwitcher ? '&' : ''}` : ''}${ + // dbSwitcher ? `db=${dbSelected}` : '' // }`; - - // console.log(newParams); - // if (!(location.pathname.includes(urlGenerator(slug)) && location.pathname.includes(newParams))) { - // redirectTo(`${parentSlug}-${newParams}`); - // //redirectTo(`http://localhost:8000/getting-started/quickstart-${newParams}`) + // if (!(location.pathname.includes(urlGenerator(slug)) && location.search === newParams)) { + // navigate(newParams); + // onChangeParam(newParams); // } + const newParams = `${langSwitcher ? `${langSelected}${dbSwitcher ? '-' : ''}` : ''}${ + dbSwitcher ? `${dbSelected}` : '' + }`; + + console.log(newParams); + if (!(location.pathname.includes(urlGenerator(slug)) && location.pathname.includes(newParams))) { + redirectTo(`${parentSlug}-${newParams}`); + //redirectTo(`http://localhost:8000/getting-started/quickstart-${newParams}`) + } }; // TODO : Simplify the function! @@ -147,7 +147,7 @@ const TopSection = ({ location, title, slug, indexPage, langSwitcher, dbSwitcher /> )} - {!indexPage && } + {/* {!indexPage && } */} ); }; diff --git a/src/interfaces/Article.interface.ts b/src/interfaces/Article.interface.ts index c14aa6a567..c6d7282337 100644 --- a/src/interfaces/Article.interface.ts +++ b/src/interfaces/Article.interface.ts @@ -13,23 +13,12 @@ export interface ArticleFrontmatter { experimental?: boolean; } -export interface ArticleData { - mdx: { - fields: ArticleFields; - body: string; - parent: any; - frontmatter: ArticleFrontmatter; - }; - site: { - siteMetadata: { - docsLocation: string; - }; - }; -} - // export interface ArticleData { -// sitePage: { -// context: any; +// mdx: { +// fields: ArticleFields; +// body: string; +// parent: any; +// frontmatter: ArticleFrontmatter; // }; // site: { // siteMetadata: { @@ -38,6 +27,17 @@ export interface ArticleData { // }; // } +export interface ArticleData { + sitePage: { + context: any; + }; + site: { + siteMetadata: { + docsLocation: string; + }; + }; +} + export interface ArticleQueryData { data: ArticleData; } diff --git a/src/layouts/articleLayout.tsx b/src/layouts/articleLayout.tsx index aaa74c3e27..c7384f9094 100644 --- a/src/layouts/articleLayout.tsx +++ b/src/layouts/articleLayout.tsx @@ -15,19 +15,19 @@ const ArticleLayout = ({ data, ...props }: ArticleLayoutProps) => { return null; } const { - mdx: { - fields: { slug }, - frontmatter: { title, metaTitle, metaDescription, langSwitcher, dbSwitcher }, - // context: { - // slug, - // title, - // frontmatter: { title: fTitle, metaTitle, metaDescription, langSwitcher, dbSwitcher }, - // parentPath, - // parentSlug, - // body, - // }, - body, - parent, + sitePage: { + // fields: { slug }, + // frontmatter: { title, metaTitle, metaDescription, langSwitcher, dbSwitcher }, + context: { + slug, + title, + frontmatter: { title: fTitle, metaTitle, metaDescription, langSwitcher, dbSwitcher }, + parentPath, + parentSlug, + body, + }, + // body, + // parent, }, site: { siteMetadata: { docsLocation }, @@ -64,68 +64,68 @@ const ArticleLayout = ({ data, ...props }: ArticleLayoutProps) => { slug={slug} langSwitcher={langSwitcher} dbSwitcher={dbSwitcher} - onChangeParam={changeSEODetails} - // parentSlug={parentSlug} + // onChangeParam={changeSEODetails} + parentSlug={parentSlug} /> {body} - +
); }; export default ArticleLayout; -// export const query = graphql` -// query($path: String!) { -// site { -// siteMetadata { -// docsLocation -// } -// } -// sitePage(path: { eq: $path }) { -// context { -// slug -// title -// frontmatter { -// title -// metaTitle -// metaDescription -// langSwitcher -// dbSwitcher -// } -// parentPath -// parentSlug -// body -// } -// } -// } -// `; - export const query = graphql` - query($slug: String!) { + query($path: String!) { site { siteMetadata { docsLocation } } - mdx(fields: { slug: { eq: $slug } }) { - fields { + sitePage(path: { eq: $path }) { + context { slug - } - body - parent { - ... on File { - relativePath - } - } - frontmatter { title - metaTitle - metaDescription - langSwitcher - dbSwitcher + frontmatter { + title + metaTitle + metaDescription + langSwitcher + dbSwitcher + } + parentPath + parentSlug + body } } } `; + +// export const query = graphql` +// query($slug: String!) { +// site { +// siteMetadata { +// docsLocation +// } +// } +// mdx(fields: { slug: { eq: $slug } }) { +// fields { +// slug +// } +// body +// parent { +// ... on File { +// relativePath +// } +// } +// frontmatter { +// title +// metaTitle +// metaDescription +// langSwitcher +// dbSwitcher +// } +// } +// } +// `; From c25a5676b37c7810006ec339f38ba583c5f57552 Mon Sep 17 00:00:00 2001 From: Nilu Date: Wed, 22 Apr 2020 11:19:27 +0200 Subject: [PATCH 4/8] layout --- gatsby-node.js | 2 +- src/components/topSection.tsx | 4 +- src/interfaces/Article.interface.ts | 32 ++--- src/layouts/articleLayout.tsx | 173 ++++++++++++++++++---------- 4 files changed, 128 insertions(+), 83 deletions(-) diff --git a/gatsby-node.js b/gatsby-node.js index 0d475d1804..a07f6b8fa7 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -53,7 +53,7 @@ exports.createPages = ({ graphql, actions }) => { path: `${node.fields.slug.replace(/\d+-/g, '')}-${lang}`, component: path.resolve(`./src/layouts/articleLayout.tsx`), context: { - slug: `${node.fields.slug}-${lang}`, + slug: node.fields.slug + '-' +lang, title: `${node.frontmatter.title}-${lang}`, frontmatter: node.frontmatter, parentSlug: node.fields.slug.replace(/\d+-/g, ''), diff --git a/src/components/topSection.tsx b/src/components/topSection.tsx index 450ecb02b1..46c62fc3bb 100644 --- a/src/components/topSection.tsx +++ b/src/components/topSection.tsx @@ -59,7 +59,7 @@ const TopSection = ({ location, title, slug, indexPage, langSwitcher, dbSwitcher console.log(newParams); if (!(location.pathname.includes(urlGenerator(slug)) && location.pathname.includes(newParams))) { - redirectTo(`${parentSlug}-${newParams}`); + redirectTo(`${urlGenerator(parentSlug)}-${newParams}`); //redirectTo(`http://localhost:8000/getting-started/quickstart-${newParams}`) } }; @@ -147,7 +147,7 @@ const TopSection = ({ location, title, slug, indexPage, langSwitcher, dbSwitcher /> )} - {/* {!indexPage && } */} + {!indexPage && } ); }; diff --git a/src/interfaces/Article.interface.ts b/src/interfaces/Article.interface.ts index c6d7282337..c14aa6a567 100644 --- a/src/interfaces/Article.interface.ts +++ b/src/interfaces/Article.interface.ts @@ -13,23 +13,12 @@ export interface ArticleFrontmatter { experimental?: boolean; } -// export interface ArticleData { -// mdx: { -// fields: ArticleFields; -// body: string; -// parent: any; -// frontmatter: ArticleFrontmatter; -// }; -// site: { -// siteMetadata: { -// docsLocation: string; -// }; -// }; -// } - export interface ArticleData { - sitePage: { - context: any; + mdx: { + fields: ArticleFields; + body: string; + parent: any; + frontmatter: ArticleFrontmatter; }; site: { siteMetadata: { @@ -38,6 +27,17 @@ export interface ArticleData { }; } +// export interface ArticleData { +// sitePage: { +// context: any; +// }; +// site: { +// siteMetadata: { +// docsLocation: string; +// }; +// }; +// } + export interface ArticleQueryData { data: ArticleData; } diff --git a/src/layouts/articleLayout.tsx b/src/layouts/articleLayout.tsx index c7384f9094..ef0e18f309 100644 --- a/src/layouts/articleLayout.tsx +++ b/src/layouts/articleLayout.tsx @@ -7,6 +7,8 @@ import PageBottom from '../components/pageBottom'; import SEO from '../components/seo'; import { graphql } from 'gatsby'; import MDXRenderer from 'gatsby-plugin-mdx/mdx-renderer'; +import {useLocation} from '@reach/router'; +import {urlGenerator} from '../utils/urlGenerator'; type ArticleLayoutProps = ArticleQueryData & RouterProps; @@ -15,40 +17,51 @@ const ArticleLayout = ({ data, ...props }: ArticleLayoutProps) => { return null; } const { - sitePage: { - // fields: { slug }, - // frontmatter: { title, metaTitle, metaDescription, langSwitcher, dbSwitcher }, - context: { - slug, - title, - frontmatter: { title: fTitle, metaTitle, metaDescription, langSwitcher, dbSwitcher }, - parentPath, - parentSlug, - body, - }, - // body, - // parent, + mdx: { + fields: { slug }, + frontmatter: { title, metaTitle, metaDescription, langSwitcher, dbSwitcher }, + // context: { + // slug, + // title, + // frontmatter: { title: fTitle, metaTitle, metaDescription, langSwitcher, dbSwitcher }, + // parentPath, + // parentSlug, + // body, + // }, + body, + parent, }, + // allMdx, site: { siteMetadata: { docsLocation }, }, } = data; + // const location = useLocation(); + // const mdx = allMdx.edges.find((item:any) => location.pathname.includes(urlGenerator(item.node.fields.slug))); + // console.log(location.pathname) + // const { + // node: {fields: { slug }, + // frontmatter: { title, metaTitle, metaDescription, langSwitcher, dbSwitcher }, + // body, + // parent} + // } = mdx; + const [seoDetails, setSEODetails] = React.useState({ seoTitle: metaTitle || title, seoUrl: slug, }); - const changeSEODetails = (newParams: string) => { - const lang = new URLSearchParams(newParams).get('lang'); - const db = new URLSearchParams(newParams).get('db'); + // const changeSEODetails = (newParams: string) => { + // const lang = new URLSearchParams(newParams).get('lang'); + // const db = new URLSearchParams(newParams).get('db'); - console.log(lang, db) - setSEODetails({ - seoTitle: title + `-${lang}-${db}`, - seoUrl: slug + newParams, - }); - }; + // console.log(lang, db) + // setSEODetails({ + // seoTitle: title + `-${lang}-${db}`, + // seoUrl: slug + newParams, + // }); + // }; return ( @@ -65,67 +78,99 @@ const ArticleLayout = ({ data, ...props }: ArticleLayoutProps) => { langSwitcher={langSwitcher} dbSwitcher={dbSwitcher} // onChangeParam={changeSEODetails} - parentSlug={parentSlug} + parentSlug={slug} /> {body} - + ); }; export default ArticleLayout; -export const query = graphql` - query($path: String!) { - site { - siteMetadata { - docsLocation - } - } - sitePage(path: { eq: $path }) { - context { - slug - title - frontmatter { - title - metaTitle - metaDescription - langSwitcher - dbSwitcher - } - parentPath - parentSlug - body - } - } - } -`; - // export const query = graphql` -// query($slug: String!) { +// query($path: String!) { // site { // siteMetadata { // docsLocation // } // } -// mdx(fields: { slug: { eq: $slug } }) { -// fields { +// sitePage(path: { eq: $path }) { +// context { // slug -// } -// body -// parent { -// ... on File { -// relativePath +// title +// frontmatter { +// title +// metaTitle +// metaDescription +// langSwitcher +// dbSwitcher // } +// parentPath +// parentSlug +// body // } -// frontmatter { -// title -// metaTitle -// metaDescription -// langSwitcher -// dbSwitcher +// } +// } +// `; + +// export const query = graphql` +// query { +// site { +// siteMetadata { +// docsLocation +// } +// } +// allMdx(sort: {fields: fields___slug}) { +// edges { +// node { +// frontmatter { +// metaTitle +// metaDescription +// title +// langSwitcher +// dbSwitcher +// } +// fields { +// slug +// } +// body +// parent { +// ... on File { +// relativePath +// } +// } +// } // } // } // } // `; + +export const query = graphql` + query($slug: String!) { + site { + siteMetadata { + docsLocation + } + } + mdx(fields: { slug: { eq: $slug } }) { + fields { + slug + } + body + parent { + ... on File { + relativePath + } + } + frontmatter { + title + metaTitle + metaDescription + langSwitcher + dbSwitcher + } + } + } +`; From c853237b6c051f8f5bb0273ce4ad4f56ab7d2b29 Mon Sep 17 00:00:00 2001 From: Nilu Date: Thu, 23 Apr 2020 15:28:00 +0200 Subject: [PATCH 5/8] Tech pages --- .prettierrc | 3 +- content/01-getting-started/04-example.mdx | 12 +- .../03-is-prisma-an-orm.mdx | 14 +- .../02-understand-prisma/04-data-modeling.mdx | 28 +-- .../01-prisma-schema-file.mdx | 6 +- .../01-prisma-schema/05-models.mdx | 14 +- .../02-prisma-client/01-api.mdx | 12 +- .../02-generating-prisma-client.mdx | 16 +- .../03-configuring-the-prisma-client-api.mdx | 4 +- .../02-prisma-client/05-relation-queries.mdx | 62 +++---- .../02-prisma-client/06-field-selection.mdx | 118 ++++++------- .../07-raw-database-access.mdx | 16 +- .../08-connection-management.mdx | 10 +- .../09-advanced-usage-of-generated-types.mdx | 52 +++--- .../02-prisma-client/15-error-formatting.mdx | 4 +- .../02-prisma-client/16-transactions.mdx | 20 +-- .../02-prisma-client/18-query-engine.mdx | 2 +- .../05-foreign-keys/02-mysql.mdx | 14 +- .../07-data-validation/01-postgresql.mdx | 30 ++-- .../02-deploying-to-aws-lambda.mdx | 4 +- content/05-more/05-faq.mdx | 2 +- gatsby-config.js | 2 +- gatsby-node.js | 79 +++++++-- src/components/customMdx/button.tsx | 44 ++--- src/components/customMdx/code.tsx | 46 ++--- src/components/customMdx/codeBlock.tsx | 28 +-- src/components/customMdx/collapsible.tsx | 35 ++-- src/components/customMdx/copy.tsx | 28 +-- src/components/customMdx/index.tsx | 16 +- src/components/customMdx/switchTech.tsx | 16 +- src/components/customMdx/table.tsx | 14 +- src/components/footer.tsx | 46 ++--- src/components/header.tsx | 38 ++--- src/components/image.tsx | 14 +- src/components/layout.tsx | 42 ++--- src/components/link.tsx | 14 +- src/components/newsletter/index.tsx | 56 +++--- src/components/newsletter/mailChimp.ts | 4 +- src/components/newsletter/valid.ts | 8 +- src/components/pageBottom.tsx | 72 ++++---- src/components/parentTitleComp.tsx | 24 +-- src/components/search/hitComps.tsx | 18 +- src/components/search/index.tsx | 34 ++-- src/components/search/input.tsx | 52 +++--- src/components/search/overlay.tsx | 26 +-- src/components/select.tsx | 48 +++--- src/components/seo.tsx | 66 +++---- src/components/sidebar/index.tsx | 28 +-- src/components/sidebar/tree.tsx | 96 +++++------ src/components/sidebar/treeNode.tsx | 55 +++--- src/components/techSwitcher.tsx | 64 +++---- src/components/toc.tsx | 50 +++--- src/components/topSection.tsx | 161 +++++++++--------- src/hooks/useAllArticlesQuery.ts | 10 +- src/hooks/useLayoutQuery.ts | 10 +- src/hooks/useTOCQuery.ts | 10 +- src/icons/ArrowDown.tsx | 4 +- src/icons/ArrowEmail.tsx | 4 +- src/icons/ArrowRight.tsx | 4 +- src/icons/Clear.tsx | 4 +- src/icons/Copy.tsx | 4 +- src/icons/Down.tsx | 4 +- src/icons/Email.tsx | 4 +- src/icons/Facebook.tsx | 4 +- src/icons/Git.tsx | 4 +- src/icons/GitGrey.tsx | 4 +- src/icons/HashLink.tsx | 4 +- src/icons/Logo.tsx | 4 +- src/icons/PrismaLogoGrey.tsx | 4 +- src/icons/Search.tsx | 4 +- src/icons/Slack.tsx | 4 +- src/icons/Twitter.tsx | 4 +- src/icons/Up.tsx | 4 +- src/icons/Youtube.tsx | 4 +- src/icons/technologies/Flow.tsx | 4 +- src/icons/technologies/Go.tsx | 4 +- src/icons/technologies/JS.tsx | 4 +- src/icons/technologies/MongoDB.tsx | 4 +- src/icons/technologies/MySQL.tsx | 4 +- src/icons/technologies/NodeJS.tsx | 4 +- src/icons/technologies/PostgreSQL.tsx | 4 +- src/icons/technologies/SQLite.tsx | 4 +- src/icons/technologies/Typescript.tsx | 4 +- src/interfaces/AllArticles.interface.ts | 8 +- src/interfaces/Article.interface.ts | 38 ++--- src/interfaces/EdgeNode.interface.ts | 10 +- src/interfaces/Layout.interface.ts | 32 ++-- src/interfaces/TOC.interface.ts | 18 +- src/layouts/articleLayout.tsx | 139 +++------------ src/pages/404.tsx | 12 +- src/utils/parentTitle.ts | 24 +-- src/utils/slug.ts | 2 +- src/utils/stringify.ts | 20 +-- src/utils/urlGenerator.ts | 4 +- 94 files changed, 1094 insertions(+), 1118 deletions(-) diff --git a/.prettierrc b/.prettierrc index e33248810f..9ff89a5444 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,5 +3,6 @@ "jsxBracketSameLine": false, "singleQuote": true, "tabWidth": 2, - "trailingComma": "es5" + "trailingComma": "es5", + "semi": false } diff --git a/content/01-getting-started/04-example.mdx b/content/01-getting-started/04-example.mdx index c26cd3b9b2..5182cb59c2 100644 --- a/content/01-getting-started/04-example.mdx +++ b/content/01-getting-started/04-example.mdx @@ -1,9 +1,17 @@ --- title: 'Example' -metaTitle: '' -metaDescription: '' +metaTitle: 'Example metaTitle' +metaDescription: 'Example meta desc' langSwitcher: ['node', 'typescript'] dbSwitcher: ["postgres", "mysql"] +techMetaTitles: [ + {name: 'node-mysql', value: 'Example-Node-MySQL'}, + {name: 'typescript-mysql', value: 'Example-typescript-MySQL'} +] +techMetaDescriptions: [ + {name: 'node-mysql', value: 'Example-Node-MySQL desc'}, + {name: 'typescript-mysql', value: 'Example-typescript-MySQL desc'} +] --- ## Overview diff --git a/content/02-understand-prisma/03-prisma-in-your-stack/03-is-prisma-an-orm.mdx b/content/02-understand-prisma/03-prisma-in-your-stack/03-is-prisma-an-orm.mdx index 044fc8cb85..21ed5d4216 100644 --- a/content/02-understand-prisma/03-prisma-in-your-stack/03-is-prisma-an-orm.mdx +++ b/content/02-understand-prisma/03-prisma-in-your-stack/03-is-prisma-an-orm.mdx @@ -135,10 +135,10 @@ Model instances represent database records and contain three important things: You can fetch and update a model instance with Sequelize as follows: ```js -const ada = await User.findOne({ where: { firstName: 'Ada' } }); -ada.lastName = 'Lovelace'; -await ada.save(); -ada.getFullName(); // Ada Lovelace +const ada = await User.findOne({ where: { firstName: 'Ada' } }) +ada.lastName = 'Lovelace' +await ada.save() +ada.getFullName() // Ada Lovelace ``` #### Schema migrations @@ -184,12 +184,12 @@ module.exports = { birthDate: { type: Sequelize.DATE, }, - }); + }) }, down: (queryInterface, Sequelize) => { - return queryInterface.dropTable('Users'); + return queryInterface.dropTable('Users') }, -}; +} ``` 2. Create the corresponding model as in the previous section. diff --git a/content/02-understand-prisma/04-data-modeling.mdx b/content/02-understand-prisma/04-data-modeling.mdx index fe0bee00bd..fdf2bbfdaf 100644 --- a/content/02-understand-prisma/04-data-modeling.mdx +++ b/content/02-understand-prisma/04-data-modeling.mdx @@ -70,10 +70,10 @@ There often is a strong correlation between the tables in your database and the ```js class User { constructor(user_id, name, email, isAdmin) { - this.user_id = user_id; - this.name = name; - this.email = email; - this.isAdmin = isAdmin; + this.user_id = user_id + this.name = name + this.email = email + this.isAdmin = isAdmin } } ``` @@ -94,9 +94,9 @@ Notice how the `User` model in both cases has the same properties as the `users` With this setup, you can retrieve records from the `users` table and store them instances of your `User` type. The following example code snippet uses [`pg`](https://node-postgres.com/) as the driver for PostgreSQL and creates a `User` instance based on the above defined JavaScript class: ```js -const resultRows = await client.query('SELECT * FROM users WHERE user_id = 1'); -const userData = resultRows[0]; -const user = new User(userData.user_id, userData.name, userData.email, userData.isAdmin); +const resultRows = await client.query('SELECT * FROM users WHERE user_id = 1') +const userData = resultRows[0] +const user = new User(userData.user_id, userData.name, userData.email, userData.isAdmin) // user = { // user_id: 1, // name: "Alice", @@ -134,7 +134,7 @@ User.init( isAdmin: Sequelize.BOOLEAN, }, { sequelize, modelName: 'user' } -); +) ``` To get an example with this `User` class to work, you still need to create the corresponding table in the database. With Sequelize, you have two ways of doing this: @@ -145,7 +145,7 @@ To get an example with this `User` class to work, you still need to create the c Note that you'll never instantiate the `User` class manually (using `new User(...)`) as was shown in the previous section, but rather call _static_ methods on the `User` class which then return the `User` model instances: ```js -const user = await User.findByPk(42); +const user = await User.findByPk(42) ``` The call to `findByPk` creates a SQL statement to retrieve the `User` record that's identified by the ID value `42`. @@ -178,11 +178,11 @@ Prisma Client uses TypeScript [type aliases](http://www.typescriptlang.org/docs/ ```ts export declare type User = { - id: number; - name: string | null; - email: string; - isAdmin: boolean; -}; + id: number + name: string | null + email: string + isAdmin: boolean +} ``` In addition to the generated types, Prisma Client also provides a data access API that you can use once you've installed the `@prisma/client` package: diff --git a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/01-prisma-schema-file.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/01-prisma-schema-file.mdx index 960bd6ae9d..d80c9d5846 100644 --- a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/01-prisma-schema-file.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/01-prisma-schema-file.mdx @@ -153,10 +153,10 @@ When running any command that needs to access the database defined via the `data If you want environment variables to be evaluated at runtime, you need to load them manually in your application code, e.g. using [`dotenv`](https://github.com/motdotla/dotenv): ```ts -import * as dotenv from 'dotenv'; +import * as dotenv from 'dotenv' -dotenv.config(); // load the environment variables -console.log(`The connection URL is ${process.env.DATABASE_URL}`); +dotenv.config() // load the environment variables +console.log(`The connection URL is ${process.env.DATABASE_URL}`) ``` ## Comments diff --git a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/05-models.mdx b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/05-models.mdx index 1af7665134..906feeb1c9 100644 --- a/content/03-reference/01-tools-and-interfaces/01-prisma-schema/05-models.mdx +++ b/content/03-reference/01-tools-and-interfaces/01-prisma-schema/05-models.mdx @@ -184,8 +184,8 @@ const newUser = await prisma.user.create({ data: { name: 'Alice', }, -}); -const allUsers = await prisma.user.findMany(); +}) +const allUsers = await prisma.user.findMany() ``` ### Type definitions @@ -200,11 +200,11 @@ For example, the type definition for the `User` model from above would look as f ```ts export type User = { - id: number; - email: string; - name: string | null; - role: string; -}; + id: number + email: string + name: string | null + role: string +} ``` Note that the relation fields `posts` and `profile` are not included in the type definion by default. However, if you need variations of the `User` type you can still define them using some of [Prisma Client's generated helper types](../prisma-client/generating-prisma-client) (in this case, these helper types would be called `UserGetIncludePayload` and `UserGetSelectPayload`). diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-api.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-api.mdx index 71afea8f2f..0c9493f1e1 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-api.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/01-api.mdx @@ -94,18 +94,18 @@ Note that this command also run the `prisma generate` command which generates th ### 3. Use Prisma Client to send queries to your database ```js -import { PrismaClient } from '@prisma/client'; +import { PrismaClient } from '@prisma/client' -const prisma = new PrismaClient(); +const prisma = new PrismaClient() // use `prisma` in your application to read and write data in your DB ``` or ```js -const { PrismaClient } = require('@prisma/client'); +const { PrismaClient } = require('@prisma/client') -const prisma = new PrismaClient(); +const prisma = new PrismaClient() // use `prisma` in your application to read and write data in your DB ``` @@ -118,8 +118,8 @@ const newUser = await prisma.user.create({ name: 'Alice', email: 'alice@prisma.io', }, -}); -const users = await prisma.user.findMany(); +}) +const users = await prisma.user.findMany() ``` ### 4. Evolving your application diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-generating-prisma-client.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-generating-prisma-client.mdx index 01013ce562..79c3314127 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-generating-prisma-client.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/02-generating-prisma-client.mdx @@ -38,18 +38,18 @@ Note also that `prisma generate` is _automatically_ invoked when you're installi Once generated, you can import and instantiate Prisma Client in your code as follows: ```js -import { PrismaClient } from '@prisma/client'; +import { PrismaClient } from '@prisma/client' -const prisma = new PrismaClient(); +const prisma = new PrismaClient() // use `prisma` in your application to read and write data in your DB ``` or ```js -const { PrismaClient } = require('@prisma/client'); +const { PrismaClient } = require('@prisma/client') -const prisma = new PrismaClient(); +const prisma = new PrismaClient() // use `prisma` in your application to read and write data in your DB ``` @@ -123,9 +123,9 @@ After running `prisma generate` for that schema file, the Prisma Client package By generating Prisma Client into `node_modules/@prisma/client`, you can import it and instantiate it in your code as follows: ```js -import { PrismaClient } from '@prisma/client'; +import { PrismaClient } from '@prisma/client' -const prisma = new PrismaClient(); +const prisma = new PrismaClient() // use `prisma` in your application to read and write data in your DB ``` @@ -133,9 +133,9 @@ const prisma = new PrismaClient(); or ```js -const { PrismaClient } = require('@prisma/client'); +const { PrismaClient } = require('@prisma/client') -const prisma = new PrismaClient(); +const prisma = new PrismaClient() // use `prisma` in your application to read and write data in your DB ``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-configuring-the-prisma-client-api.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-configuring-the-prisma-client-api.mdx index 8e5b27b2c7..607ffd1422 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-configuring-the-prisma-client-api.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/03-configuring-the-prisma-client-api.mdx @@ -240,14 +240,14 @@ const profile = await prisma.profile.create({ }, }, }, -}); +}) // Fluent API const userByProfile = await prisma.profile .findOne({ where: { id: 1 }, }) - .user(); + .user() ``` > **Warning**: `@map` and `@@map` attributes are removed when you run `prisma introspect` again. You therefore might want to back up your Prisma schema with these attributes in order to not having to annotate everything from scratch again after a re-introspection. diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-relation-queries.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-relation-queries.mdx index 14b54ec396..0f458d3340 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-relation-queries.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/05-relation-queries.mdx @@ -63,7 +63,7 @@ This query returns all `Post` records by a specific `User`: ```ts const postsByUser: Post[] = await prisma.user .findOne({ where: { email: 'alice@prisma.io' } }) - .posts(); + .posts() ``` Note that this call is equivalent to this Prisma Client query: @@ -71,7 +71,7 @@ Note that this call is equivalent to this Prisma Client query: ```ts const postsByUser = await prisma.post.findMany({ where: { author: { email: 'alice@prisma.io' } }, -}); +}) ``` The main difference between the two is that the fluent API call is translated into two separate database queries while the other one only generates a single query (see this [GitHub issue](https://github.com/prisma/prisma/issues/1984)). @@ -79,7 +79,7 @@ The main difference between the two is that the fluent API call is translated in This request returns all categories by a specific post: ```ts -const categoriesOfPost: Category[] = await prisma.post.findOne({ where: { id: 1 } }).categories(); +const categoriesOfPost: Category[] = await prisma.post.findOne({ where: { id: 1 } }).categories() ``` Note that you can chain as many queries as you like. In this example, the chanining starts at `Profile` and goes over `User` to `Post`: @@ -119,7 +119,7 @@ const posts: Post[] = await prisma.user where: { title: { startsWith: 'Hello' }, }, - }); + }) ``` Note that this query is _equivalent_ to the following one which is initiated via the `post` instead of the `user` field (i.e. it doesn't use the fluent API): @@ -130,8 +130,8 @@ const posts = await prisma.post.findMany({ author: { email: 'bob@prisma.io' }, title: { startsWith: 'Hello' }, }, -}); -console.log(posts); +}) +console.log(posts) ``` The main difference between the two is that the fluent API call is translated into two separate database queries while the other one only generates a single query (see this [GitHub issue](https://github.com/prisma/prisma/issues/1984)). @@ -187,7 +187,7 @@ const user = await prisma.user.create({ create: { bio: 'Hello World' }, }, }, -}); +}) ``` This example uses the `user` model property, but you could also run the query from the `profile` side: @@ -200,7 +200,7 @@ const user = await prisma.profile.create({ create: { email: 'alice@prisma.io' }, }, }, -}); +}) ``` **Create a new `Profile` record and connect it to an existing `User` record** @@ -213,7 +213,7 @@ const user = await prisma.profile.create({ connect: { email: 'alice@prisma.io' }, }, }, -}); +}) ``` Note that this requires that a `User` record with an `email` of `"alice@prisma.io"` already exists in the database. If that's not the case, the query will fail with an exception. @@ -228,7 +228,7 @@ const user = await prisma.profile.create({ connect: { id: 42 }, }, }, -}); +}) ``` **Update an existing `User` record by creating a new `Profile` record** @@ -241,7 +241,7 @@ const user = await prisma.user.update({ create: { bio: 'Hello World' }, }, }, -}); +}) ``` **Update an existing `User` record by connecting it to an existing `Profile` record** @@ -254,7 +254,7 @@ const user = await prisma.user.update({ connect: { id: 24 }, }, }, -}); +}) ``` **Update an existing `User` record by updating the `Profile` record it's connected to** @@ -267,7 +267,7 @@ const user = await prisma.user.update({ update: { bio: 'Hello World' }, }, }, -}); +}) ``` **Update an existing `User` record by updating the `Profile` record it's connected to or creating a new one (_upsert_)** @@ -283,7 +283,7 @@ const user = await prisma.user.update({ }, }, }, -}); +}) ``` **Update an existing `User` record by deleting the `Profile` record it's connected to** @@ -296,7 +296,7 @@ const user = await prisma.user.update({ delete: true, }, }, -}); +}) ``` **Update an existing `User` record by disconnecting the `Profile` record it's connected to** @@ -309,7 +309,7 @@ const user = await prisma.user.update({ disconnect: true, }, }, -}); +}) ``` Note that this query is actually illegal with the data model from above because the `user` field on `Profile` is required. In order to make this query succeed, you'd need to make both relation fields optional: @@ -372,7 +372,7 @@ const user = await prisma.user.create({ create: { title: 'Hello World' }, }, }, -}); +}) ``` This example uses the `user` model property, but you could also run the query from the `post` side: @@ -385,7 +385,7 @@ const user = await prisma.post.create({ create: { email: 'alice@prisma.io' }, }, }, -}); +}) ``` **Create a new `User` record with two new `Post` records**: @@ -400,7 +400,7 @@ const user = await prisma.user.create({ create: [{ title: 'This is my first post' }, { title: 'Here comes a second post' }], }, }, -}); +}) ``` **Create a new `Post` record and connect it to an existing `User` record** @@ -413,7 +413,7 @@ const user = await prisma.post.create({ connect: { email: 'alice@prisma.io' }, }, }, -}); +}) ``` Note that this requires that a `User` record with an `email` of `"alice@prisma.io"` already exists in the database. If that's not the case, the query will fail with an exception. @@ -428,7 +428,7 @@ const user = await prisma.post.create({ connect: { id: 42 }, }, }, -}); +}) ``` **Update an existing `User` record by creating a new `Post` record** @@ -441,7 +441,7 @@ const user = await prisma.user.update({ create: { title: 'Hello World' }, }, }, -}); +}) ``` **Update an existing `User` record by connecting it to two existing `Post` records** @@ -454,7 +454,7 @@ const user = await prisma.user.update({ connect: [{ id: 24 }, { id: 42 }], }, }, -}); +}) ``` **Update an existing `User` record by updating two `Post` records it's connected to** @@ -476,7 +476,7 @@ const user = await prisma.user.update({ ], }, }, -}); +}) ``` **Update an existing `User` record by updating two `Post` record it's connected to or creating new ones (_upsert_)** @@ -500,7 +500,7 @@ const user = await prisma.user.update({ ], }, }, -}); +}) ``` **Update an existing `User` record by deleting two `Post` records it's connected to** @@ -513,7 +513,7 @@ const user = await prisma.user.update({ delete: [{ id: 34 }, { id: 36 }], }, }, -}); +}) ``` **Update an existing `User` record by disconnecting two `Post` records it's connected to** @@ -526,7 +526,7 @@ const user = await prisma.user.update({ disconnect: [{ id: 44 }, { id: 46 }], }, }, -}); +}) ``` **Update an existing `User` record by disconnecting any previous `Post` records and connect two other exiting ones** @@ -539,7 +539,7 @@ const user = await prisma.user.update({ set: [{ id: 32 }, { id: 42 }], }, }, -}); +}) ``` ## Nested reads @@ -556,7 +556,7 @@ const users = await prisma.user.findMany({ posts: true, profile: true, }, -}); +}) ``` **Include the `posts` relation on the returned objects when creating a new `User` record with two `Post` records** @@ -570,7 +570,7 @@ const user = await prisma.user.create({ }, }, include: { posts: true }, -}); +}) ``` **Retrieve deeply nested data by loading several levels of relations** @@ -588,5 +588,5 @@ const users = await prisma.user.findMany({ }, }, }, -}); +}) ``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-field-selection.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-field-selection.mdx index cd1c078cbf..536a99758e 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-field-selection.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/06-field-selection.mdx @@ -46,7 +46,7 @@ Consider the following example `findOne` invocation: ```ts const result = await prisma.user.findOne({ where: { id: 1 }, -}); +}) ``` The `result` of this API call is a plain old JavaScript object that might look similar to this: @@ -93,7 +93,7 @@ const result = await prisma.user.findMany({ }, }, }, -}); +}) ``` And the following one is not allowed because `select` and `include` appear on the same level of nesting right next to each other: @@ -107,7 +107,7 @@ const result = await prisma.user.findMany({ include: { posts: true, }, -}); +}) ``` This case would be caught with the following exceptions: @@ -150,42 +150,42 @@ The type of the `select` option is custom for each model. For example, for the ` ```ts export type UserSelect = { - id?: boolean; - name?: boolean; - email?: boolean; - role?: boolean; - coinflips?: boolean; - profileViews?: boolean; - posts?: boolean | FindManyPostArgs; -}; + id?: boolean + name?: boolean + email?: boolean + role?: boolean + coinflips?: boolean + profileViews?: boolean + posts?: boolean | FindManyPostArgs +} export type PostSelect = { - id?: boolean; - title?: boolean; - published?: boolean; - author?: boolean | UserArgs; -}; + id?: boolean + title?: boolean + published?: boolean + author?: boolean | UserArgs +} ``` The types also contain relation fields which can be even further controlled with specific arguments: ```ts export type UserArgs = { - select?: UserSelect | null; - include?: UserInclude | null; -}; + select?: UserSelect | null + include?: UserInclude | null +} export type FindManyPostArgs = { - select?: PostSelect | null; - include?: PostInclude | null; - where?: PostWhereInput | null; - orderBy?: PostOrderByInput | null; - skip?: number | null; - after?: PostWhereUniqueInput | null; - before?: PostWhereUniqueInput | null; - first?: number | null; - last?: number | null; -}; + select?: PostSelect | null + include?: PostInclude | null + where?: PostWhereInput | null + orderBy?: PostOrderByInput | null + skip?: number | null + after?: PostWhereUniqueInput | null + before?: PostWhereUniqueInput | null + first?: number | null + last?: number | null +} ``` ### Examples @@ -199,7 +199,7 @@ const result = await prisma.user.findOne({ name: true, profileViews: true, }, -}); +}) ``` The `result` object now looks as follows: @@ -219,13 +219,13 @@ const result = await prisma.user.findMany({ email: true, role: true, }, -}); +}) ``` Since `findMany` returns an array of objects, `result` would now look as follows: ```js -[ +;[ { email: 'alice@prisma.io', role: 'ADMIN', @@ -234,7 +234,7 @@ Since `findMany` returns an array of objects, `result` would now look as follows email: 'bob@prisma.io', role: 'USER', }, -]; +] ``` Here's how you can include additional fields of a relation: @@ -251,13 +251,13 @@ const result = await prisma.user.findMany({ }, }, }, -}); +}) ``` In this case, the result might look as follow: ```ts -[ +;[ { id: 1, name: 'Alice', @@ -271,7 +271,7 @@ In this case, the result might look as follow: name: 'Bob', posts: [], }, -]; +] ``` You can also nest the `include` option inside of the `select` option: @@ -287,13 +287,13 @@ const result = await prisma.user.findMany({ }, }, }, -}); +}) ``` This would result in the following structure for the `result` object: ```js -[ +;[ { id: 1, name: 'Alice', @@ -326,7 +326,7 @@ This would result in the following structure for the `result` object: }, ], }, -]; +] ``` Note that the `author` contains all fields of the `User` model's default selection set (scalars, arrays/scalar lists, enums). @@ -341,33 +341,33 @@ The type of the `include` option is custom for each model. For example, for the ```ts export type UserInclude = { - posts?: boolean | FindManyPostArgs; -}; + posts?: boolean | FindManyPostArgs +} export type PostInclude = { - author?: boolean | UserArgs; -}; + author?: boolean | UserArgs +} ``` The types contain only relation fields which can be even further controlled with specific arguments: ```ts export type UserArgs = { - select?: UserSelect | null; - include?: UserInclude | null; -}; + select?: UserSelect | null + include?: UserInclude | null +} export type FindManyPostArgs = { - select?: PostSelect | null; - include?: PostInclude | null; - where?: PostWhereInput | null; - orderBy?: PostOrderByInput | null; - skip?: number | null; - after?: PostWhereUniqueInput | null; - before?: PostWhereUniqueInput | null; - first?: number | null; - last?: number | null; -}; + select?: PostSelect | null + include?: PostInclude | null + where?: PostWhereInput | null + orderBy?: PostOrderByInput | null + skip?: number | null + after?: PostWhereUniqueInput | null + before?: PostWhereUniqueInput | null + first?: number | null + last?: number | null +} ``` ### Examples @@ -376,7 +376,7 @@ export type FindManyPostArgs = { const result = await prisma.user.findOne({ where: { id: 1 }, include: { posts: true }, -}); +}) ``` The `result` object in this case contains the default selection set of the `User` model _plus_ its `posts` relation: @@ -417,7 +417,7 @@ const result = await prisma.user.findOne({ }, }, }, -}); +}) ``` This would lead to the following structure of the `result` object: @@ -466,7 +466,7 @@ const result = await prisma.user.findOne({ }, }, }, -}); +}) ``` In this case, the `result` object would look as follows: diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-raw-database-access.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-raw-database-access.mdx index ac2cd41a33..0ef392711d 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-raw-database-access.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/07-raw-database-access.mdx @@ -9,16 +9,16 @@ metaDescription: 'Learn how you can send raw SQL queries to your database using You can send raw SQL queries to your database using the `raw` function that's exposed by your `PrismaClient` instance. It returns the query results as plain old JavaScript objects: ```ts -const result = await prisma.raw('SELECT * FROM User;'); +const result = await prisma.raw('SELECT * FROM User;') ``` `result` is an array where each object corresponds to a retrieved database record: ```js -[ +;[ { id: 1, email: 'sarah@prisma.io', name: 'Sarah' }, { id: 2, email: 'alice@prisma.io', name: 'Alice' }, -]; +] ``` ## Tagged templates @@ -26,7 +26,7 @@ const result = await prisma.raw('SELECT * FROM User;'); The `raw` method is implemented as a [tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates). Therefore, you can also call `raw` as follows: ```ts -const result = await prisma.raw`SELECT * FROM User;`; +const result = await prisma.raw`SELECT * FROM User;` ``` ## Setting variables @@ -34,8 +34,8 @@ const result = await prisma.raw`SELECT * FROM User;`; To include variables in your SQL query, you can use JavaScript string interpolation with [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals): ```ts -const userId = 42; -const result = await prisma.raw`SELECT * FROM User WHERE id = ${userId};`; +const userId = 42 +const result = await prisma.raw`SELECT * FROM User WHERE id = ${userId};` ``` ## Typing `raw` results @@ -50,9 +50,9 @@ The return type of `raw` is a `Promise` for the [generic](https://www.typescript ```ts // import the generated `User` type from the `@prisma/client` module -import { User } from '@prisma/client'; +import { User } from '@prisma/client' -const result = await prisma.raw('SELECT * FROM User;'); +const result = await prisma.raw('SELECT * FROM User;') // result is of type: `User[]` ``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-connection-management.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-connection-management.mdx index 7224c68c0f..a53fa5bceb 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-connection-management.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/08-connection-management.mdx @@ -16,10 +16,10 @@ Unless you want to employ a specific optimization, calling `prisma.connect()` is If you need the first request to respond instantly and can't wait for the lazy connection to be established, you can explicitly call `prisma.connect()` to establish a connection to the Prisma data source: ```ts -const prisma = new PrismaClient(); +const prisma = new PrismaClient() // run inside `async` function -await prisma.connect(); +await prisma.connect() ``` **IMPORTANT**: It is recommended to always explicitly call `prisma.disconnect()` in your code. Also, be sure to disconnect even when an exception is thrown: @@ -27,11 +27,11 @@ await prisma.connect(); ```ts main() .catch(e => { - throw e; + throw e }) .finally(async () => { - await prisma.disconnect(); - }); + await prisma.disconnect() + }) ``` ## `connect` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-advanced-usage-of-generated-types.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-advanced-usage-of-generated-types.mdx index 2e8fbddde0..50d407bb55 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-advanced-usage-of-generated-types.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/09-advanced-usage-of-generated-types.mdx @@ -34,10 +34,10 @@ The Prisma Client code that's generated from this schema contains this represent ```ts export declare type User = { - id: string; - email: string; - name: string | null; -}; + id: string + email: string + name: string | null +} ``` ### Problem: Using variations of the generated model type @@ -59,33 +59,33 @@ One way of achieving this would be to define these types manually in your applic ```ts // Define a type that includes the relation to `Post` type UserWithPosts = { - id: string; - email: string; - name: string | null; - posts: Post[]; -}; + id: string + email: string + name: string | null + posts: Post[] +} // Define a type that only contains a subset of the scalar fields type UserPersonalData = { - email: string; - name: string | null; -}; + email: string + name: string | null +} ``` While this is certainly feasible, this approach increases the maintenance burden upon changes to the Prisma schema as you need to manually maintain the types. A cleaner solution to this is to use the `UserGetPayload` type that is generated and exposed by Prisma Client: ```ts -import { UserGetPayload } from '@prisma/client'; +import { UserGetPayload } from '@prisma/client' // Define a type that includes the relation to `Post` type UserWithPosts = UserGetPayload<{ - include: { posts: true }; -}>; + include: { posts: true } +}> // Define a type that only contains a subset of the scalar fields type UserPersonalData = UserGetPayload<{ - select: { email: true; name: true }; -}>; + select: { email: true; name: true } +}> ``` The main benefits of the latter approach are: @@ -102,8 +102,8 @@ When doing [`select`](./field-selectio#select) or [`include`](./field-selectio#i ```ts // Function definition that returns a partial structure async function getUsersWithPosts() { - const users = await prisma.user.findMany({ include: { posts: true } }); - return users; + const users = await prisma.user.findMany({ include: { posts: true } }) + return users } ``` @@ -112,16 +112,16 @@ Extracting the type that represents "users with posts" from the above code snipp ```ts // Function definition that returns a partial structure async function getUsersWithPosts() { - const users = await prisma.user.findMany({ include: { posts: true } }); - return users; + const users = await prisma.user.findMany({ include: { posts: true } }) + return users } // Extract `UsersWithPosts` type with -type ThenArg = T extends PromiseLike ? U : T; -type UsersWithPosts = ThenArg>; +type ThenArg = T extends PromiseLike ? U : T +type UsersWithPosts = ThenArg> // run inside `async` function -const usersWithPosts: UsersWithPosts = await getUsersWithPosts(); +const usersWithPosts: UsersWithPosts = await getUsersWithPosts() ``` #### Solution @@ -129,7 +129,7 @@ const usersWithPosts: UsersWithPosts = await getUsersWithPosts(); With the `PromiseReturnType` that is exposed by Prisma Client, you can solve this more elegantly: ```ts -import { PromiseReturnType } from '@prisma/client'; +import { PromiseReturnType } from '@prisma/client' -type UsersWithPosts = PromiseReturnType; +type UsersWithPosts = PromiseReturnType ``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-error-formatting.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-error-formatting.mdx index b4d9863eb3..c2cc6afc6b 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-error-formatting.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/15-error-formatting.mdx @@ -42,11 +42,11 @@ It can be used like so: ```ts const prisma = new PrismaClient({ errorFormat: 'minimal', -}); +}) ``` As the `errorFormat` property is optional, you still can just instantiate Prisma Client like this: ```ts -const prisma = new PrismaClient(); +const prisma = new PrismaClient() ``` diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-transactions.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-transactions.mdx index 2c74acd0ff..e2767401a6 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-transactions.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/16-transactions.mdx @@ -44,7 +44,7 @@ const newUser: User = await prisma.user.create({ ], }, }, -}); +}) ``` ```ts @@ -56,7 +56,7 @@ const updatedPost: Post = await prisma.post.update({ connect: { email: 'alice@prisma.io' }, }, }, -}); +}) ``` ## Future transaction support in Prisma Client @@ -71,11 +71,11 @@ Transactions are a commonly used feature in relational as well as non-relational The first use case of sending multiple operations in bulk could be implemented with an API similar to this: ```ts -const write1 = prisma.user.create(); -const write2 = prisma.orders.create(); -const write3 = prisma.invoices.create(); +const write1 = prisma.user.create() +const write2 = prisma.orders.create() +const write3 = prisma.invoices.create() -await prisma.transaction([write1, write2, write3]); +await prisma.transaction([write1, write2, write3]) ``` Instead of immediately awaiting the result of each operation when it's performed, the operation itself is stored in a variable first which later is submitted to the database via a method called `transaction`. Prisma Client will ensure that either all three `create`-operations or none of them succeed. @@ -88,16 +88,16 @@ The second use case of longer-running transactions where operations can depend o prisma.transaction(async tx => { const user = await tx.users.create({ data: { email: 'alice@prisma.io' }, - }); + }) const order = await tx.orders.create({ data: { customer: { connect: { id: user.id }, }, }, - }); - await tx.commit(); -}); + }) + await tx.commit() +}) ``` In this case, the API provides a way to wrap a sequence of operations in a callback which gets executed as a transaction, therefore is guaranteed to either succeed or fail as a whole. diff --git a/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-query-engine.mdx b/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-query-engine.mdx index 7e270e63f7..f08a1dd236 100644 --- a/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-query-engine.mdx +++ b/content/03-reference/01-tools-and-interfaces/02-prisma-client/18-query-engine.mdx @@ -73,7 +73,7 @@ You can also get more visibility into the SQL queries that are generated by the ```ts const prisma = new PrismaClient({ log: ['query'], -}); +}) ``` Learn more in the [Debugging](./debugging) and [Logging](./logging) pages of the docs. diff --git a/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx b/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx index 475e229c17..946fe98325 100644 --- a/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx +++ b/content/04-guides/01-database-workflows/05-foreign-keys/02-mysql.mdx @@ -217,9 +217,9 @@ Now you can use Prisma Client to send database queries in Node.js. Create a new file called `index.js` and add the following code to it: ```js -const { PrismaClient } = require('@prisma/client'); +const { PrismaClient } = require('@prisma/client') -const prisma = new PrismaClient(); +const prisma = new PrismaClient() async function main() { const userWithPost = await prisma.user.create({ @@ -234,8 +234,8 @@ async function main() { include: { Post: true, }, - }); - console.log(userWithPost); + }) + console.log(userWithPost) const anotherUserWithPost = await prisma.anotherUser.create({ data: { @@ -250,11 +250,11 @@ async function main() { include: { AnotherPost: true, }, - }); - console.log(anotherUserWithPost); + }) + console.log(anotherUserWithPost) } -main(); +main() ``` In this code, you're creating two `User` records, each with a related `Post` record. diff --git a/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx b/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx index 5a474e28dd..c87d999f4f 100644 --- a/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx +++ b/content/04-guides/01-database-workflows/07-data-validation/01-postgresql.mdx @@ -344,21 +344,21 @@ Now you can use Prisma Client to send database queries in Node.js. Create a new file called `index.js` and add the following code to it: ```js -const { PrismaClient } = require('@prisma/client'); +const { PrismaClient } = require('@prisma/client') -const prisma = new PrismaClient(); +const prisma = new PrismaClient() async function main() { const newProduct = await prisma.product.create({ data: { price: 0.0, }, - }); + }) - console.log(newProduct); + console.log(newProduct) } -main(); +main() ``` In this code, you're creating a product with a price of `0.00`, which does not meet the check constraint configured for the `price` column. @@ -379,9 +379,9 @@ ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error To validate the multi-column check constraint, replace the code in `index.js` with the following: ```js -const { PrismaClient } = require('@prisma/client'); +const { PrismaClient } = require('@prisma/client') -const prisma = new PrismaClient(); +const prisma = new PrismaClient() async function main() { const newProduct = await prisma.anotherproduct.create({ @@ -389,12 +389,12 @@ async function main() { price: 50.0, reducedprice: 100.0, }, - }); + }) - console.log(newProduct); + console.log(newProduct) } -main(); +main() ``` In this code, you're creating a product where the reduced price is higher than the actual price. @@ -415,9 +415,9 @@ ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(Error Finally, modify the script to include multiple check constraint violations: ```js -const { PrismaClient } = require('@prisma/client'); +const { PrismaClient } = require('@prisma/client') -const prisma = new PrismaClient(); +const prisma = new PrismaClient() async function main() { const newProduct = await prisma.secondtolastproduct.create({ @@ -428,12 +428,12 @@ async function main() { price: 90.0, reducedprice: 100.0, }, - }); + }) - console.log(newProduct); + console.log(newProduct) } -main(); +main() ``` In this code, you're creating a product where the reduced price is higher than the actual price, and omitting the required `product` tag. diff --git a/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx b/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx index 88a2506f3a..07845dbb2c 100644 --- a/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx +++ b/content/04-guides/02-deployment/02-deploying-to-aws-lambda.mdx @@ -178,7 +178,7 @@ The names of the relation fields are used in the client to access those relation const postAuthor = await prisma.post.findOne({ where: { id: 1 }, include: { User: true }, -}); +}) ``` If you rename the `User` field in the `Post` model to `author`, you'll be able to access it as follows: @@ -187,7 +187,7 @@ If you rename the `User` field in the `Post` model to `author`, you'll be able t const postAuthor = await prisma.post.findOne({ where: { id: 1 }, include: { author: true }, -}); +}) ``` Based on that logic, rename the relation fields to better adhere to the [naming conventions](../../reference/tools-and-interfaces/prisma-schema/models#naming-fields): diff --git a/content/05-more/05-faq.mdx b/content/05-more/05-faq.mdx index 37b3115e79..21a0e5b8ea 100644 --- a/content/05-more/05-faq.mdx +++ b/content/05-more/05-faq.mdx @@ -29,7 +29,7 @@ You can view generated SQL queries by providing the `log` option to the `PrismaC ```ts const prisma = new PrismaClient({ log: ['query'], -}); +}) ``` Learn more on the [Debugging](../reference/tools-and-interfaces/prisma-client/debugging) page in the docs. diff --git a/gatsby-config.js b/gatsby-config.js index 0df30aaf47..718ea64398 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -18,7 +18,6 @@ const gatsbyRemarkPlugins = [ { resolve: `gatsby-remark-images`, }, - 'gatsby-plugin-react-helmet' ]; if (process.env.NODE_ENV === 'development') { @@ -40,6 +39,7 @@ module.exports = { docsLocation: config.siteMetadata.docsLocation, }, plugins: [ + 'gatsby-plugin-react-helmet', 'gatsby-transformer-sharp', 'gatsby-plugin-sharp', 'gatsby-plugin-typescript', diff --git a/gatsby-node.js b/gatsby-node.js index a07f6b8fa7..748c03e688 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -14,11 +14,27 @@ exports.onCreateNode = ({ node, getNode, actions }) => { name: `slug`, value: `/${value}`, }); + createNodeField({ + node, + name: 'id', + value: node.id, + }); } }; exports.createPages = ({ graphql, actions }) => { const { createPage } = actions; + + const getTitle = (frontmatter, lang, db) => { + let pageSeoTitle = frontmatter.metaTitle || frontmatter.title + if (lang || db) { + const titleEntry = frontmatter.techMetaTitles ? frontmatter.techMetaTitles.find(item => item.name === `${lang}-${db}`) : null + pageSeoTitle = titleEntry ? titleEntry.value : pageSeoTitle + } + + return pageSeoTitle + } + return new Promise((resolve, reject) => { graphql(` { @@ -27,6 +43,7 @@ exports.createPages = ({ graphql, actions }) => { node { fields { slug + id } frontmatter { title @@ -34,6 +51,14 @@ exports.createPages = ({ graphql, actions }) => { metaDescription langSwitcher dbSwitcher + techMetaTitles { + name + value + } + techMetaDescriptions { + name + value + } } body parent { @@ -48,17 +73,41 @@ exports.createPages = ({ graphql, actions }) => { `).then(result => { result.data.allMdx.edges.forEach(({ node }) => { if (node.frontmatter.langSwitcher) { - node.frontmatter.langSwitcher.forEach(lang => + if (node.frontmatter.dbSwitcher) { + node.frontmatter.langSwitcher.forEach(lang => + node.frontmatter.dbSwitcher.forEach(db => + createPage({ + path: `${node.fields.slug.replace(/\d+-/g, '')}-${lang}-${db}`, + component: path.resolve(`./src/layouts/articleLayout.tsx`), + context: { + id: node.fields.id, + seoTitle: getTitle(node.frontmatter, lang, db) + }, + }) + ) + ); + } else { + node.frontmatter.langSwitcher.forEach(lang => + createPage({ + path: `${node.fields.slug.replace(/\d+-/g, '')}-${lang}`, + component: path.resolve(`./src/layouts/articleLayout.tsx`), + context: { + id: node.fields.id, + seoTitle: `${node.frontmatter.title}-${lang}` + }, + }) + ); + } + } + + if (node.frontmatter.dbSwitcher && !node.frontmatter.langSwitcher) { + node.frontmatter.dbSwitcher.forEach(db => createPage({ - path: `${node.fields.slug.replace(/\d+-/g, '')}-${lang}`, + path: `${node.fields.slug.replace(/\d+-/g, '')}-${db}`, component: path.resolve(`./src/layouts/articleLayout.tsx`), context: { - slug: node.fields.slug + '-' +lang, - title: `${node.frontmatter.title}-${lang}`, - frontmatter: node.frontmatter, - parentSlug: node.fields.slug.replace(/\d+-/g, ''), - parentPath: node.parent.relativePath, - body: node.body, + id: node.fields.id, + seoTitle: `${node.frontmatter.title}-${db}` }, }) ); @@ -67,12 +116,8 @@ exports.createPages = ({ graphql, actions }) => { path: node.fields.slug ? node.fields.slug.replace(/\d+-/g, '') : '/', component: path.resolve(`./src/layouts/articleLayout.tsx`), context: { - slug: node.fields.slug, - title: node.frontmatter.title, - frontmatter: node.frontmatter, - parentSlug: node.fields.slug.replace(/\d+-/g, ''), - parentPath: node.parent.relativePath, - body: node.body, + id: node.fields.id, + seoTitle: getTitle(node.frontmatter) }, }); }); @@ -92,3 +137,9 @@ exports.onCreateWebpackConfig = ({ actions }) => { }, }); }; + +// title: `${node.frontmatter.title}-${lang}`, +// frontmatter: node.frontmatter, +// parentSlug: node.fields.slug.replace(/\d+-/g, ''), +// parentPath: node.parent.relativePath, +// body: node.body, diff --git a/src/components/customMdx/button.tsx b/src/components/customMdx/button.tsx index bbc17d195f..19470edab2 100644 --- a/src/components/customMdx/button.tsx +++ b/src/components/customMdx/button.tsx @@ -1,29 +1,29 @@ -import React from 'react'; -import styled from 'styled-components'; -import ArrowRight from '../../icons/ArrowRight'; -import { darken } from 'polished'; -import withProps from 'styled-components-ts'; +import React from 'react' +import styled from 'styled-components' +import ArrowRight from '../../icons/ArrowRight' +import { darken } from 'polished' +import withProps from 'styled-components-ts' export interface ButtonProps { - href?: string; - target?: string; - block?: boolean; - color?: ButtonColor; - disabled?: boolean; - arrow?: boolean; - children?: any; - onClick?: any; - arrowLeft?: boolean; + href?: string + target?: string + block?: boolean + color?: ButtonColor + disabled?: boolean + arrow?: boolean + children?: any + onClick?: any + arrowLeft?: boolean } -type ButtonColor = 'red' | 'green' | 'grey' | 'grey-bg' | 'dark'; +type ButtonColor = 'red' | 'green' | 'grey' | 'grey-bg' | 'dark' const colorMap = { red: 'white', green: 'white', grey: '#3D556B', 'grey-bg': 'white', dark: 'white', -}; +} const backgroundColorMap = { red: '#ff4f56', @@ -31,7 +31,7 @@ const backgroundColorMap = { grey: 'white', 'grey-bg': '#8fa6b2', dark: 'rgb(12, 52, 75)', -}; +} export const ButtonWrapper = withProps(styled.a)` padding: 11px 14px; @@ -65,7 +65,7 @@ export const ButtonWrapper = withProps(styled.a)` &:focus { background: ${p => darken(0.07, backgroundColorMap[p.color || 'green'])}; } - `; + ` const ButtonLink = (props: ButtonProps) => ( @@ -73,15 +73,15 @@ const ButtonLink = (props: ButtonProps) => ( {props.children} {props.arrow && } -); +) const StyledArrow = styled(ArrowRight)` margin-left: 12px; -`; +` const StyledArrowLeft = styled(ArrowRight)` margin-right: 12px; transform: rotate(180deg); -`; +` -export default ButtonLink; +export default ButtonLink diff --git a/src/components/customMdx/code.tsx b/src/components/customMdx/code.tsx index d3c378af07..13d281092a 100644 --- a/src/components/customMdx/code.tsx +++ b/src/components/customMdx/code.tsx @@ -1,39 +1,39 @@ -import React from 'react'; -import Highlight, { defaultProps } from 'prism-react-renderer'; -import theme from 'prism-react-renderer/themes/github'; -import CopyButton from './copy'; -import Copy from '../../icons/Copy'; -import { stringify } from '../../utils/stringify'; -import styled from 'styled-components'; +import React from 'react' +import Highlight, { defaultProps } from 'prism-react-renderer' +import theme from 'prism-react-renderer/themes/github' +import CopyButton from './copy' +import Copy from '../../icons/Copy' +import { stringify } from '../../utils/stringify' +import styled from 'styled-components' interface CodeProps { - copy?: boolean; + copy?: boolean } -type PreCodeProps = CodeProps & React.ReactNode; +type PreCodeProps = CodeProps & React.ReactNode function cleanTokens(tokens: any[]) { - const tokensLength = tokens.length; + const tokensLength = tokens.length if (tokensLength === 0) { - return tokens; + return tokens } - const lastToken = tokens[tokensLength - 1]; + const lastToken = tokens[tokensLength - 1] if (lastToken.length === 1 && lastToken[0].empty) { - return tokens.slice(0, tokensLength - 1); + return tokens.slice(0, tokensLength - 1) } - return tokens; + return tokens } const Code = ({ children, className, ...props }: PreCodeProps) => { - let language = className && className.replace(/language-/, ''); + let language = className && className.replace(/language-/, '') if (language === 'prisma') { - language = 'sql'; + language = 'sql' } else if (language == undefined) { - language = 'shell'; + language = 'shell' } - const code = stringify(children); + const code = stringify(children) return ( <> @@ -62,10 +62,10 @@ const Code = ({ children, className, ...props }: PreCodeProps) => { - ); -}; + ) +} -export default Code; +export default Code const AbsoluteCopyButton = styled.div` transition: opacity 100ms ease; @@ -77,7 +77,7 @@ const AbsoluteCopyButton = styled.div` right: -8px; top: -2px; } -`; +` export const Pre = styled.pre` margin-top: 2rem; @@ -94,4 +94,4 @@ export const Pre = styled.pre` height: 1.3rem; font-size: 15px; } -`; +` diff --git a/src/components/customMdx/codeBlock.tsx b/src/components/customMdx/codeBlock.tsx index 6deae26f75..c51f2a8b25 100644 --- a/src/components/customMdx/codeBlock.tsx +++ b/src/components/customMdx/codeBlock.tsx @@ -1,23 +1,23 @@ -import React from 'react'; -import styled from 'styled-components'; +import React from 'react' +import styled from 'styled-components' interface CodeProps { - languages?: string[]; + languages?: string[] } -type CodeBlockProps = CodeProps & React.ReactNode; +type CodeBlockProps = CodeProps & React.ReactNode const CodeBlock = ({ languages, children }: CodeBlockProps) => { - const [activeIndex, setActiveIndex] = React.useState(0); - const child: any = React.Children.toArray(children)[activeIndex]; - const code = child && child.props && child.props.children; + const [activeIndex, setActiveIndex] = React.useState(0) + const child: any = React.Children.toArray(children)[activeIndex] + const code = child && child.props && child.props.children return ( {languages && Array.isArray(languages) && ( {languages.map((lang, index) => { - const setCurrentActive = () => setActiveIndex(index); + const setCurrentActive = () => setActiveIndex(index) return (
{ > {lang}
- ); + ) })}
)} {code}
- ); -}; + ) +} -export default CodeBlock; +export default CodeBlock const Tabs = styled.div` display: flex; @@ -50,8 +50,8 @@ const Tabs = styled.div` font-weight: 600; color: #1a202c; } -`; +` const Wrapper = styled.div` margin-top: 2rem; position: relative; -`; +` diff --git a/src/components/customMdx/collapsible.tsx b/src/components/customMdx/collapsible.tsx index e7c649802b..9da98eaaf8 100644 --- a/src/components/customMdx/collapsible.tsx +++ b/src/components/customMdx/collapsible.tsx @@ -1,18 +1,17 @@ -import React from 'react'; -import styled from 'styled-components'; -import ArrowRight from '../../icons/ArrowRight'; +import React from 'react' +import styled from 'styled-components' +import ArrowRight from '../../icons/ArrowRight' -type CollapseProps = React.ReactNode; -let index = 0; +type CollapseProps = React.ReactNode +let index = 0 const getRemainingChildren = (children: any) => - children.filter((child: any) => !(child.props && child.props.originalType === 'summary')); + children.filter((child: any) => !(child.props && child.props.originalType === 'summary')) const CollapseBox = ({ children, ...props }: CollapseProps) => { const titleChild = - children && - children.find((child: any) => child.props && child.props.originalType === 'summary'); - const title = titleChild && titleChild.props.children; + children && children.find((child: any) => child.props && child.props.originalType === 'summary') + const title = titleChild && titleChild.props.children return ( @@ -22,14 +21,14 @@ const CollapseBox = ({ children, ...props }: CollapseProps) => { {getRemainingChildren(children)} - ); -}; + ) +} -export default CollapseBox; +export default CollapseBox const Wrapper = styled.div` padding-bottom: 24px; -`; +` const Tab = styled.div` position: relative; @@ -49,7 +48,7 @@ const Tab = styled.div` p { margin-top: 8px; } -`; +` const Label = styled.label` position: relative; @@ -59,7 +58,7 @@ const Label = styled.label` line-height: 2; padding-left: 36px; cursor: pointer; -`; +` const TabContent = styled.div` max-height: 0; @@ -68,7 +67,7 @@ const TabContent = styled.div` transition: max-height 0.35s, padding 0.35s; padding-left: 36px; padding-bottom: 0; -`; +` const Input = styled.input` position: absolute; @@ -78,7 +77,7 @@ const Input = styled.input` max-height: 2000px; padding-bottom: 8px; } -`; +` const StyledArrow = styled(ArrowRight)` position: absolute; @@ -88,4 +87,4 @@ const StyledArrow = styled(ArrowRight)` input:checked + & { transform: rotate(90deg); } -`; +` diff --git a/src/components/customMdx/copy.tsx b/src/components/customMdx/copy.tsx index 67b6b6d105..27c10c0cac 100644 --- a/src/components/customMdx/copy.tsx +++ b/src/components/customMdx/copy.tsx @@ -1,21 +1,21 @@ -import React from 'react'; -import styled from 'styled-components'; -import * as CopyToClipboard from 'react-copy-to-clipboard'; +import React from 'react' +import styled from 'styled-components' +import * as CopyToClipboard from 'react-copy-to-clipboard' interface CopyProps { - text: string; + text: string } -type CopyButtonProps = CopyProps & React.ReactNode; +type CopyButtonProps = CopyProps & React.ReactNode const CopyButton = ({ text, children }: CopyButtonProps) => { - const [copied, setCopied] = React.useState(false); - let copyTimer: any; + const [copied, setCopied] = React.useState(false) + let copyTimer: any const onCopyContent = () => { - setCopied(true); - copyTimer = window.setTimeout(() => setCopied(false), 500); - }; + setCopied(true) + copyTimer = window.setTimeout(() => setCopied(false), 500) + } return ( @@ -28,10 +28,10 @@ const CopyButton = ({ text, children }: CopyButtonProps) => { {children} - ); -}; + ) +} -export default CopyButton; +export default CopyButton const CopyComponent = styled.div` font-family: 'Open Sans'; @@ -60,4 +60,4 @@ const CopyComponent = styled.div` transform: translate(-50%, 0); animation: copying 700ms linear; } -`; +` diff --git a/src/components/customMdx/index.tsx b/src/components/customMdx/index.tsx index bcd6c6ae5a..98ade7cc50 100644 --- a/src/components/customMdx/index.tsx +++ b/src/components/customMdx/index.tsx @@ -1,10 +1,10 @@ -import React from 'react'; -import SwitchTech from './switchTech'; -import CodeBlock from './codeBlock'; -import Code from './code'; -import CollapseBox from './collapsible'; -import Table from './table'; -import ButtonLink from './button'; +import React from 'react' +import SwitchTech from './switchTech' +import CodeBlock from './codeBlock' +import Code from './code' +import CollapseBox from './collapsible' +import Table from './table' +import ButtonLink from './button' export default { h1: () =>

, @@ -22,4 +22,4 @@ export default { ), -}; +} diff --git a/src/components/customMdx/switchTech.tsx b/src/components/customMdx/switchTech.tsx index 18cad8d61f..8802636917 100644 --- a/src/components/customMdx/switchTech.tsx +++ b/src/components/customMdx/switchTech.tsx @@ -1,17 +1,17 @@ -import React from 'react'; -import styled from 'styled-components'; +import React from 'react' +import styled from 'styled-components' interface CodeProps { - technologies?: string[]; + technologies?: string[] } -type CodeBlockProps = CodeProps & React.ReactNode; +type CodeBlockProps = CodeProps & React.ReactNode const SwitchTech = ({ technologies, children }: CodeBlockProps) => { - return {children}; -}; + return {children} +} -export default SwitchTech; +export default SwitchTech const SwitchWrapper = styled.section` display: none; @@ -20,4 +20,4 @@ const SwitchWrapper = styled.section` &.show { display: block; } -`; +` diff --git a/src/components/customMdx/table.tsx b/src/components/customMdx/table.tsx index 9fbacf7774..1cc23b4538 100644 --- a/src/components/customMdx/table.tsx +++ b/src/components/customMdx/table.tsx @@ -1,18 +1,18 @@ -import React from 'react'; -import styled from 'styled-components'; +import React from 'react' +import styled from 'styled-components' -type TableProps = React.ReactNode; +type TableProps = React.ReactNode const Table = ({ children, ...props }: TableProps) => { return ( {children}
- ); -}; + ) +} -export default Table; +export default Table const TableWrapper = styled.div` overflow-x: auto; -`; +` diff --git a/src/components/footer.tsx b/src/components/footer.tsx index 83aac2fea0..329c86ac62 100644 --- a/src/components/footer.tsx +++ b/src/components/footer.tsx @@ -1,19 +1,19 @@ -import Link from '../components/link'; -import * as React from 'react'; -import styled from 'styled-components'; -import PrismaLogoGrey from '../icons/PrismaLogoGrey'; -import NewsLetter from '../components/newsletter'; -import Twitter from '../icons/Twitter'; -import Youtube from '../icons/Youtube'; -import Slack from '../icons/Slack'; -import Github from '../icons/GitGrey'; -import Facebook from '../icons/Facebook'; - -import { FooterProps } from '../interfaces/Layout.interface'; +import Link from '../components/link' +import * as React from 'react' +import styled from 'styled-components' +import PrismaLogoGrey from '../icons/PrismaLogoGrey' +import NewsLetter from '../components/newsletter' +import Twitter from '../icons/Twitter' +import Youtube from '../icons/Youtube' +import Slack from '../icons/Slack' +import Github from '../icons/GitGrey' +import Facebook from '../icons/Facebook' + +import { FooterProps } from '../interfaces/Layout.interface' type FooterViewProps = { - footerProps: FooterProps; -}; + footerProps: FooterProps +} const FooterWrapper = styled.div` background: transparent; @@ -34,7 +34,7 @@ const FooterWrapper = styled.div` display: flex; justify-content: space-between; } -`; +` const LinkList = styled.ul` list-style: none; @@ -65,7 +65,7 @@ const LinkList = styled.ul` } } } -`; +` const Title = styled.span` font-size: 1.2rem; @@ -73,11 +73,11 @@ const Title = styled.span` font-weight: bold; line-height: 100%; letter-spacing: -0.02em; -`; +` const LogoContainer = styled.div` padding-right: 0.75rem; -`; +` const SocialWrapper = styled.div` max-width: 350px; @@ -109,7 +109,7 @@ const SocialWrapper = styled.div` margin-top: 2rem; } } -`; +` const Footer = ({ footerProps }: FooterViewProps) => { const { @@ -121,7 +121,7 @@ const Footer = ({ footerProps }: FooterViewProps) => { company, newsletter, findus, - } = footerProps; + } = footerProps return (
@@ -210,7 +210,7 @@ const Footer = ({ footerProps }: FooterViewProps) => {
- ); -}; + ) +} -export default Footer; +export default Footer diff --git a/src/components/header.tsx b/src/components/header.tsx index 74f77fecc0..dea3451183 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -1,14 +1,14 @@ -import Link from '../components/link'; -import * as React from 'react'; -import styled from 'styled-components'; -import HeaderLogo from '../icons/Logo'; -import Github from '../icons/Git'; -import Search from '../components/search'; -import { HeaderProps } from '../interfaces/Layout.interface'; +import Link from '../components/link' +import * as React from 'react' +import styled from 'styled-components' +import HeaderLogo from '../icons/Logo' +import Github from '../icons/Git' +import Search from '../components/search' +import { HeaderProps } from '../interfaces/Layout.interface' type HeaderViewProps = { - headerProps: HeaderProps; -}; + headerProps: HeaderProps +} const HeaderWrapper = styled.div` background: radial-gradient( @@ -29,13 +29,13 @@ const HeaderWrapper = styled.div` .container { width: 1110px; } -`; +` const HeaderNav = styled.div` display: flex; align-items: center; justify-content: space-between; -`; +` const Title = styled.span` font-size: 1.2rem; @@ -44,17 +44,17 @@ const Title = styled.span` font-weight: bold; line-height: 100%; letter-spacing: -0.02em; -`; +` const LogoContainer = styled.div` padding-right: 0.75rem; -`; +` const SearchComponent = styled(Search)` position: absolute; top: 12px; left: 12px; -`; +` const NavLinks = styled.div` display: flex; @@ -70,7 +70,7 @@ const NavLinks = styled.div` } margin: 0 10rem 0; -`; +` const Header = ({ headerProps }: HeaderViewProps) => ( @@ -116,11 +116,9 @@ const Header = ({ headerProps }: HeaderViewProps) => ( -
- -
+
{/* */}
-); +) -export default Header; +export default Header diff --git a/src/components/image.tsx b/src/components/image.tsx index 9d948f0083..0e66970865 100644 --- a/src/components/image.tsx +++ b/src/components/image.tsx @@ -1,6 +1,6 @@ -import { graphql, useStaticQuery } from 'gatsby'; -import Img from 'gatsby-image'; -import * as React from 'react'; +import { graphql, useStaticQuery } from 'gatsby' +import Img from 'gatsby-image' +import * as React from 'react' /* * This component is built using `gatsby-image` to automatically serve optimized @@ -24,8 +24,8 @@ const Image = () => { } } } - `); + `) - return ; -}; -export default Image; + return +} +export default Image diff --git a/src/components/layout.tsx b/src/components/layout.tsx index 67a54d90b4..372d3d60fd 100644 --- a/src/components/layout.tsx +++ b/src/components/layout.tsx @@ -1,28 +1,28 @@ -import { RouterProps } from '@reach/router'; -import * as React from 'react'; -import styled, { ThemeProvider } from 'styled-components'; -import { useLayoutQuery } from '../hooks/useLayoutQuery'; -import Header from './header'; -import Footer from './footer'; +import { RouterProps } from '@reach/router' +import * as React from 'react' +import styled, { ThemeProvider } from 'styled-components' +import { useLayoutQuery } from '../hooks/useLayoutQuery' +import Header from './header' +import Footer from './footer' -import { MDXProvider } from '@mdx-js/react'; -import customMdx from '../components/customMdx'; -import './layout.css'; -import Sidebar from './sidebar'; +import { MDXProvider } from '@mdx-js/react' +import customMdx from '../components/customMdx' +import './layout.css' +import Sidebar from './sidebar' interface ThemeProps { - colorPrimary: string; + colorPrimary: string } const theme: ThemeProps = { colorPrimary: '#663399', -}; +} -type LayoutProps = React.ReactNode & RouterProps; +type LayoutProps = React.ReactNode & RouterProps const Layout: React.FunctionComponent = ({ children }) => { - const { site } = useLayoutQuery(); - const { header, footer } = site.siteMetadata; + const { site } = useLayoutQuery() + const { header, footer } = site.siteMetadata const Wrapper = styled.div` display: flex; @@ -32,7 +32,7 @@ const Layout: React.FunctionComponent = ({ children }) => { // @media only screen and (max-width: 767px) { // display: block; // } - `; + ` const Content = styled.article` max-width: 880px; @@ -41,7 +41,7 @@ const Layout: React.FunctionComponent = ({ children }) => { // @media only screen and (max-width: 1023px) { // padding-left: 0; // } - `; + ` const MaxWidth = styled.div` // @media only screen and (max-width: 50rem) { @@ -58,7 +58,7 @@ const Layout: React.FunctionComponent = ({ children }) => { padding-top: 40px; } } - `; + ` return ( @@ -73,7 +73,7 @@ const Layout: React.FunctionComponent = ({ children }) => {