{"id":28052,"date":"2021-06-24T14:29:10","date_gmt":"2021-06-24T14:29:10","guid":{"rendered":"http:\/\/How-to-build-a-Gatsby-Image-Gallery-Theme"},"modified":"2021-06-24T14:29:10","modified_gmt":"2021-06-24T14:29:10","slug":"how-to-build-a-gatsby-image-gallery-theme","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/","title":{"rendered":"How to build a Gatsby Image Gallery Theme"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>In this media jam, we will build a <a href=\"https:\/\/www.gatsbyjs.com\/docs\/themes\/what-are-gatsby-themes\/\">Gatsby Theme<\/a> for an <a href=\"https:\/\/gatsby-theme-cloudinary-gallery.vercel.app\">Image Gallery<\/a>. The images will be stored and fetched from Cloudinary. We will conclude this jam by publishing our theme to the npm registry.<\/p>\n<p>If you want to jump right into the code, check out the <a href=\"https:\/\/github.com\/lelouchB\/gatsby-theme-cloudinary-gallery\">GitHub Repo here<\/a> and the <a href=\"https:\/\/www.npmjs.com\/package\/gatsby-theme-cloudinary-gallery\">NPM package here<\/a>.<\/p>\n<h2>Code Sandbox<\/h2>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/gatsby-theme-cloudinary-gallery-oxqo1?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=%2Fgatsby-theme-cloudinary-gallery%2Fsrc%2Fpages%2Findex.js&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"gatsby-theme-cloudinary-gallery\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><h2>What are Gatsby Themes?<\/h2>\n<p><a href=\"https:\/\/www.gatsbyjs.com\/docs\/themes\/what-are-gatsby-themes\/\">Gatsby Themes<\/a> are plugins that include a <code>gatsby-config.js<\/code> file and pre-configured functionalities, UI design. These themes are Node.js packages that implement Gatsby APIs and are commonly installed through a registry like <code>npm<\/code>.<\/p>\n<h2>How to setup Yarn workspace<\/h2>\n<p>Make sure you have <code>yarn<\/code> installed on your local dev machine. You can read more about yarn installation <a href=\"https:\/\/classic.yarnpkg.com\/en\/docs\/install#windows-stable\">here<\/a>.<\/p>\n<p>You will also need to install the Gatsby command-line tool (CLI). The <code>gatsby-cli<\/code> is the main entry point for getting up and running with a Gatsby application. You can read more about <code>gatsby-cli<\/code> <a href=\"https:\/\/www.gatsbyjs.com\/docs\/reference\/gatsby-cli\/\">here<\/a>.<\/p>\n<p>Run the following command in the terminal to install <code>yarn<\/code> and <code>gatsby-cli<\/code> globally.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">npm install --<span class=\"hljs-keyword\">global<\/span> yarn\nnpm install -g gatsby-cli\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Run the following command to create a <code>package.json<\/code> in your root directory.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">touch<\/span> <span class=\"hljs-selector-tag\">package<\/span><span class=\"hljs-selector-class\">.json<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Add the following code to <code>package.json<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json shcb-wrap-lines\">{\n    <span class=\"hljs-attr\">\"private\"<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-attr\">\"workspaces\"<\/span>: &#91;<span class=\"hljs-string\">\"gatsby-theme-cloudinary-gallery\"<\/span>, <span class=\"hljs-string\">\"demo\"<\/span>]\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You will create two workspaces named <code>gatsby-theme-cloudinary-gallery<\/code> and <code>demo<\/code>. Here <code>gatsby-theme-cloudinary-gallery<\/code> is the Gatsby Theme, and the <code>demo<\/code> is the Gatsby site to test the theme.<\/p>\n<p>The <code>gatsby-theme-cloudinary-gallery<\/code> will be installed as a dependency in the <code>demo<\/code> workspace to test the theme before publishing it to the npm registry.<\/p>\n<p>Run the following command in your project\u2019s root directory.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">mkdir gatsby-theme-cloudinary-gallery\nmkdir demo\ncd gatsby-theme-cloudinary-gallery\nnpm init -y\ncd ..\ncd demo\nnpm init -y\ncd ..\n<\/code><\/span><\/pre>\n<p>The above commands will create two directories named <code>gatsby-theme-cloudinary-gallery<\/code> and <code>demo<\/code>\u2014each with a <code>package.json<\/code> in it.<\/p>\n<p>Your file tree will look like this.<\/p>\n<pre class=\"js-syntax-highlighted\"><code>.\n\u251c\u2500\u2500 gatsby-theme-cloudinary-gallery\n\u2502   \u2514\u2500\u2500 package.json\n\u251c\u2500\u2500 demo\n\u2502   \u2514\u2500\u2500 package.json\n\u2514\u2500\u2500 package.json\n<\/code><\/pre>\n<p>Update <code>gatsby-theme-cloudinary-gallery\/package.json<\/code> like this.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json shcb-wrap-lines\">{\n    <span class=\"hljs-attr\">\"name\"<\/span>: <span class=\"hljs-string\">\"gatsby-theme-cloudinary-gallery\"<\/span>,\n    <span class=\"hljs-attr\">\"version\"<\/span>: <span class=\"hljs-string\">\"1.0.0\"<\/span>,\n    <span class=\"hljs-attr\">\"description\"<\/span>: <span class=\"hljs-string\">\"\"<\/span>,\n    <span class=\"hljs-attr\">\"main\"<\/span>: <span class=\"hljs-string\">\"index.js\"<\/span>,\n    <span class=\"hljs-attr\">\"scripts\"<\/span>: {\n        <span class=\"hljs-attr\">\"build\"<\/span>: <span class=\"hljs-string\">\"gatsby build\"<\/span>,\n        <span class=\"hljs-attr\">\"develop\"<\/span>: <span class=\"hljs-string\">\"gatsby develop\"<\/span>,\n        <span class=\"hljs-attr\">\"clean\"<\/span>: <span class=\"hljs-string\">\"gatsby clean\"<\/span>\n    },\n    <span class=\"hljs-attr\">\"keywords\"<\/span>: &#91;\n        <span class=\"hljs-string\">\"gatsby\"<\/span>,\n        <span class=\"hljs-string\">\"gatsby-theme\"<\/span>,\n        <span class=\"hljs-string\">\"gatsby-plugin\"<\/span>,\n        <span class=\"hljs-string\">\"react\"<\/span>,\n        <span class=\"hljs-string\">\"images\"<\/span>,\n        <span class=\"hljs-string\">\"cloudinary\"<\/span>,\n        <span class=\"hljs-string\">\"gallery\"<\/span>,\n        <span class=\"hljs-string\">\"cloudinary-gallery\"<\/span>\n],\n    <span class=\"hljs-attr\">\"author\"<\/span>: <span class=\"hljs-string\">\"\"<\/span>,\n    <span class=\"hljs-attr\">\"license\"<\/span>: <span class=\"hljs-string\">\"MIT\"<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Inside the <code>gatsby-theme-cloudinary-gallery<\/code> directory, create a file named <code>index.js<\/code>. Run the following command to create it.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">touch gatsby-theme-cloudinary-gallery\/index.js\n<\/code><\/span><\/pre>\n<p>This file is needed since it is present as the main entry point in the <code>package.json<\/code>. You can leave it empty for now; you will update it in the last section to export the <code>Gallery<\/code> component.<\/p>\n<p>Update <code>demo\/package.json<\/code> like this.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json shcb-wrap-lines\">{\n    <span class=\"hljs-attr\">\"name\"<\/span>: <span class=\"hljs-string\">\"demo\"<\/span>,\n    <span class=\"hljs-attr\">\"version\"<\/span>: <span class=\"hljs-string\">\"1.0.0\"<\/span>,\n    <span class=\"hljs-attr\">\"description\"<\/span>: <span class=\"hljs-string\">\"\"<\/span>,\n    <span class=\"hljs-attr\">\"main\"<\/span>: <span class=\"hljs-string\">\"index.js\"<\/span>,\n    <span class=\"hljs-attr\">\"scripts\"<\/span>: {\n        <span class=\"hljs-attr\">\"build\"<\/span>: <span class=\"hljs-string\">\"gatsby build\"<\/span>,\n        <span class=\"hljs-attr\">\"develop\"<\/span>: <span class=\"hljs-string\">\"gatsby develop\"<\/span>,\n        <span class=\"hljs-attr\">\"clean\"<\/span>: <span class=\"hljs-string\">\"gatsby clean\"<\/span>\n    },\n    <span class=\"hljs-attr\">\"keywords\"<\/span>: &#91;],\n    <span class=\"hljs-attr\">\"author\"<\/span>: <span class=\"hljs-string\">\"\"<\/span>,\n    <span class=\"hljs-attr\">\"license\"<\/span>: <span class=\"hljs-string\">\"MIT\"<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Run the following command to add dependencies to the <code>gatsby-theme-cloudinary-gallery<\/code> and <code>demo<\/code> workspace.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn workspace demo add gatsby react react-dom gatsby-theme-cloudinary-gallery@*\nyarn workspace gatsby-theme-cloudinary-gallery add -P gatsby react react-dom\nyarn workspace gatsby-theme-cloudinary-gallery add -D gatsby react react-dom\n<\/code><\/span><\/pre>\n<p>You install <code>gatsby<\/code>, <code>react<\/code>, and <code>react-dom<\/code> in the <code>demo<\/code> workspace to set up a Gatsby site. You also install the <code>gatsby-theme-cloudinary-gallery<\/code> in the <code>demo<\/code> workspace as a dependency.<\/p>\n<p>In the <code>gatsby-theme-cloudinary-gallery<\/code> workspace, you install <code>gatsby<\/code>, <code>react<\/code>, and <code>react-dom<\/code> as both dev dependencies and peer dependencies.<\/p>\n<p>Dev dependencies are the packages you need during project development.<\/p>\n<p>Peer dependencies are used to specify that your package is compatible with a specific version of the npm package.<\/p>\n<p>During installation, if the package already exists in the <code>node_modules<\/code> directory, it will do nothing. But if it is not present, a warning will be shown to the user.<\/p>\n<p>Since <code>gatsby<\/code>, <code>react<\/code>, and <code>react-dom<\/code> will be present in every Gatsby site, it is unlikely that this warning will be shown to the user.<\/p>\n<p>Run the following command to check <code>demo<\/code> is using the <code>gatsby-theme-cloudinary-gallery<\/code> from the workspace.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn workspaces info\n<\/code><\/span><\/pre>\n<p>You should see an output similar to this.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json shcb-wrap-lines\">{\n  <span class=\"hljs-attr\">\"gatsby-theme-cloudinary-gallery\"<\/span>: {\n    <span class=\"hljs-attr\">\"location\"<\/span>: <span class=\"hljs-string\">\"gatsby-theme-cloudinary-gallery\"<\/span>,\n    <span class=\"hljs-attr\">\"workspaceDependencies\"<\/span>: &#91;],\n    <span class=\"hljs-attr\">\"mismatchedWorkspaceDependencies\"<\/span>: &#91;]\n  },\n  <span class=\"hljs-attr\">\"demo\"<\/span>: {\n    <span class=\"hljs-attr\">\"location\"<\/span>: <span class=\"hljs-string\">\"demo\"<\/span>,\n    <span class=\"hljs-attr\">\"workspaceDependencies\"<\/span>: &#91;\n      **<span class=\"hljs-string\">\"gatsby-theme-cloudinary-gallery\"<\/span>**\n    ],\n    <span class=\"hljs-attr\">\"mismatchedWorkspaceDependencies\"<\/span>: &#91;]\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In this jam, you will use Tailwind CSS to style your theme. Run the following command to install it.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\">\n<span class=\"hljs-selector-tag\">yarn<\/span> <span class=\"hljs-selector-tag\">workspace<\/span> <span class=\"hljs-selector-tag\">gatsby-theme-cloudinary-gallery<\/span> <span class=\"hljs-selector-tag\">add<\/span> <span class=\"hljs-selector-tag\">gatsby-plugin-postcss<\/span> <span class=\"hljs-selector-tag\">tailwindcss<\/span><span class=\"hljs-keyword\">@latest<\/span> postcss@latest autoprefixer@latest\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, run the following command to generate your <code>tailwind.config.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">cd gatsby-theme-cloudinary-gallery\nnpx tailwindcss init \n<\/code><\/span><\/pre>\n<p>The last command will generate a <code>tailwind.config.js<\/code> file in the <code>gatsby-theme-cloudinary-gallery<\/code> directory. Update the <code>tailwind.config.js<\/code> file like this.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-built_in\">module<\/span>.exports = {\n  <span class=\"hljs-attr\">purge<\/span>: &#91;<span class=\"hljs-string\">'.\/src\/**\/*.{js,jsx,ts,tsx}'<\/span>],\n    <span class=\"hljs-attr\">darkMode<\/span>: <span class=\"hljs-literal\">false<\/span>, <span class=\"hljs-comment\">\/\/ or 'media' or 'class'<\/span>\n  <span class=\"hljs-attr\">theme<\/span>: {\n    <span class=\"hljs-attr\">extend<\/span>: {},\n  },\n  <span class=\"hljs-attr\">variants<\/span>: {\n    <span class=\"hljs-attr\">extend<\/span>: {},\n  },\n  <span class=\"hljs-attr\">plugins<\/span>: &#91;],\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Run the following command to create a <code>global.css<\/code> file inside the <code>gatsby-theme-cloudinary-gallery<\/code> directory under the <code>src\/styles<\/code> folder.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">mkdir -p gatsby-theme-cloudinary-gallery\/src\/styles\ntouch gatsby-theme-cloudinary-gallery\/src\/styles\/<span class=\"hljs-keyword\">global<\/span>.css\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Add the following code to the <code>global.css<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-comment\">\/* gatsby-theme-cloudinary-gallery\/src\/styles\/global.css *\/<\/span>\n<span class=\"hljs-keyword\">@tailwind<\/span> base;\n<span class=\"hljs-keyword\">@tailwind<\/span> components;\n<span class=\"hljs-keyword\">@tailwind<\/span> utilities;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Create <code>gatsby-browser.js<\/code> and <code>gatsby-config.js<\/code> files in the <code>gatsby-theme-cloudinary-gallery<\/code> directory by running the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">touch gatsby-theme-cloudinary-gallery\/gatsby-browser.js\ntouch gatsby-theme-cloudinary-gallery\/gatsby-config.js\n<\/code><\/span><\/pre>\n<p>Add the following code to the <code>gatsby-browser.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'.\/src\/styles\/global.css'<\/span>;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Add the following code to the <code>gatsby-config.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-built_in\">module<\/span>.exports = {\n  <span class=\"hljs-attr\">siteMetadata<\/span>: {\n    <span class=\"hljs-attr\">title<\/span>: <span class=\"hljs-string\">\"Gatsby Theme Cloudinary Gallery\"<\/span>,\n    <span class=\"hljs-attr\">description<\/span>:\n      <span class=\"hljs-string\">\"Gatbsy Theme to add a Cloudinary Image Gallery to your Gatsby site.\"<\/span>,\n    <span class=\"hljs-attr\">social<\/span>: &#91;\n      {\n        <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"GitHub\"<\/span>,\n        <span class=\"hljs-attr\">url<\/span>: <span class=\"hljs-string\">\"https:\/\/github.com\/lelouchB\/gatsby-theme-cloudinary-gallery\"<\/span>,\n      },\n    ],\n  },\n  <span class=\"hljs-attr\">plugins<\/span>: &#91;\n    {\n      <span class=\"hljs-attr\">resolve<\/span>: <span class=\"hljs-string\">`gatsby-plugin-postcss`<\/span>,\n      <span class=\"hljs-attr\">options<\/span>: {\n        <span class=\"hljs-attr\">postCssPlugins<\/span>: &#91;<span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">\"tailwindcss\"<\/span>)],\n      },\n    },\n  ],\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You can refer to the <a href=\"https:\/\/tailwindcss.com\/docs\/guides\/gatsby\">official documentation for detailed instructions<\/a> on installing Tailwind CSS with Gatsby.<\/p>\n<h2>How to create Heading Component<\/h2>\n<p>In this section, you will create the <code>Heading<\/code> component that will show the following heading: <em><strong>Gatsby Theme Cloudinary Gallery<\/strong><\/em><\/p>\n<p>Run the following command to create a <code>components<\/code> folder in the <code>gatsby-theme-cloudinary-gallery\/src<\/code> directory.<\/p>\n<p>Inside the <code>components<\/code> directory, create a file named <code>Heading.js<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">mkdir gatsby-theme-cloudinary-gallery\/src\/components\ntouch gatsby-theme-cloudinary-gallery\/src\/components\/Heading.js \n<\/code><\/span><\/pre>\n<p>Add the following code to the <code>Heading.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> Heading = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-4xl md:text-5xl text-center text-gray-800 font-sans font-medium\"<\/span>&gt;<\/span>\n      Gatsby Theme Cloudinary Gallery\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span><\/span>\n  );\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Heading;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The above code creates a simple heading styled with Tailwind CSS.<\/p>\n<p>The next step is to create a page to use this <code>Heading<\/code> component. Run the following command to create a <code>index.js<\/code> file in the <code>src\/pages<\/code> sub-directory.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">mkdir gatsby-theme-cloudinary-gallery\/src\/pages\ntouch gatsby-theme-cloudinary-gallery\/src\/pages\/index.js \n<\/code><\/span><\/pre>\n<p>Add the following code to the <code>pages\/index.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Heading <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/components\/Heading.js\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> Homepage = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-gray-200 min-h-screen p-8\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Heading<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Homepage;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the above code, you first import the <code>Heading<\/code> component and then use it inside the <code>Homepage<\/code> component.<\/p>\n<p>The last step is to create a <code>gatsby-node.js<\/code> file that will create the page using Gatsby <code>createPages<\/code> method and the <code>pages\/index.js<\/code> file.<\/p>\n<p>Run the following command to create it.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">touch gatsby-theme-cloudinary-gallery\/gatsby-node.js\n<\/code><\/span><\/pre>\n<p>Add the following code to the <code>gatsby-node.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">exports.createPages = <span class=\"hljs-keyword\">async<\/span> ({ actions }, options) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> basePath = options.basePath || <span class=\"hljs-string\">\"\/\"<\/span>;\n\n  actions.createPage({\n    <span class=\"hljs-attr\">path<\/span>: basePath,\n    <span class=\"hljs-attr\">component<\/span>: <span class=\"hljs-built_in\">require<\/span>.resolve(<span class=\"hljs-string\">\".\/src\/pages\/index.js\"<\/span>),\n  });\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You export the <code>createPages<\/code> method to create your page. You can read more about <code>createPages<\/code> method <a href=\"https:\/\/www.gatsbyjs.com\/docs\/reference\/config-files\/gatsby-node\/#createPages\">here<\/a>.<\/p>\n<p>The above code creates a page dynamically at the <code>\/<\/code> route. The <code>options<\/code> object contains the props passed by the user when using the theme. You can read more about <code>createPage<\/code> action <a href=\"https:\/\/www.gatsbyjs.com\/docs\/reference\/config-files\/actions\/#createPage\">here<\/a>.<\/p>\n<p>By default, the <code>\/<\/code> route is used as the <code>basePath<\/code>. If the user passes a value to the <code>basePath<\/code> prop in the theme configuration, that value will be used instead.<\/p>\n<p>Start your development server by running the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn workspace gatsby-theme-cloudinary-gallery develop\n<\/code><\/span><\/pre>\n<p>Head over to <a href=\"http:\/\/localhost:8000\/\">http:\/\/localhost:8000\/<\/a> in your browser. Here is how your app will look like.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624259217\/e-603fc45fe6c0b4006873802f\/nz3jnqa7zgtmpzpso2vi.jpg\" alt=\"Heading\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1755\" height=\"861\"\/><\/p>\n<p>You can stop the development server by hitting <strong>CTRL+C<\/strong> in the terminal.<\/p>\n<p>You can also configure the <code>demo<\/code> workspace to show the heading or the theme. Create a file named <code>gatsby-config.js<\/code> in the <code>demo<\/code> directory by running the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">touch demo\/gatsby-config.js\n<\/code><\/span><\/pre>\n<p>Add the following code to <code>gatsby-config.js<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">\n<span class=\"hljs-built_in\">module<\/span>.exports = {\n  <span class=\"hljs-attr\">plugins<\/span>: &#91;\n    {\n      <span class=\"hljs-attr\">resolve<\/span>: <span class=\"hljs-string\">\"gatsby-theme-cloudinary-gallery\"<\/span>,\n      <span class=\"hljs-attr\">options<\/span>: {\n        <span class=\"hljs-attr\">basePath<\/span>:<span class=\"hljs-string\">\"\/gallery\"<\/span>,\n      },\n    },\n  ],\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Since you have passed <code>\/gallery<\/code> to the <code>basePath<\/code> prop, the theme or the heading will be displayed at the <code>\/gallery<\/code> route.<\/p>\n<p>Start the development server for the demo workspace.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn workspace demo develop\n<\/code><\/span><\/pre>\n<p>Head over to <a href=\"http:\/\/localhost:8000\/gallery\">http:\/\/localhost:8000\/gallery<\/a>  in the browser. Here is how your app will look like.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624259217\/e-603fc45fe6c0b4006873802f\/nz3jnqa7zgtmpzpso2vi.jpg\" alt=\"Heading\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1755\" height=\"861\"\/><\/p>\n<h2>How to create Gatsby Nodes from Images<\/h2>\n<p>In this section, you will fetch the images from Cloudinary and create Gatsby Nodes from them.<\/p>\n<p><strong>Nodes<\/strong> are the center of Gatsby\u2019s data system. All the data that is added to Gatsby is modeled using nodes. You can read more about them <a href=\"https:\/\/www.gatsbyjs.com\/docs\/reference\/graphql-data-layer\/node-interface\/\">here<\/a>.<\/p>\n<p>Nodes are created by calling the <code>createNode<\/code> action. Nodes can be any object. Each Node has to be <strong>structured in a pre-defined manner<\/strong>, each with <strong>a unique id<\/strong>.<\/p>\n<p>In <code>gatsby-node.js<\/code> file, create a function named <code>createNodeData<\/code>. This function will convert image resources into node data.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> createNodeData = <span class=\"hljs-function\">(<span class=\"hljs-params\">gatsby, image, options<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> {\n    <span class=\"hljs-attr\">id<\/span>: gatsby.createNodeId(<span class=\"hljs-string\">`cloudinary-gallery-<span class=\"hljs-subst\">${image.public_id}<\/span>`<\/span>),\n    <span class=\"hljs-attr\">parent<\/span>: <span class=\"hljs-literal\">null<\/span>,\n    <span class=\"hljs-attr\">public_id<\/span>: image.public_id,\n    <span class=\"hljs-attr\">cloud_name<\/span>: options.cloudName,\n    <span class=\"hljs-attr\">internal<\/span>: {\n      <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">\"CloudinaryGallery\"<\/span>,\n      <span class=\"hljs-attr\">content<\/span>: <span class=\"hljs-built_in\">JSON<\/span>.stringify(image),\n      <span class=\"hljs-attr\">contentDigest<\/span>: gatsby.createContentDigest(image),\n    },\n  };\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>createNodeData<\/code> function takes three arguments, <code>gatsby<\/code>, <code>image<\/code>, and the <code>options<\/code> object. Here <code>image<\/code> is the image resource fetched from Cloudinary.<\/p>\n<p><em>You are not creating a node in the above function, just structuring the data in the way needed to create the node.<\/em><\/p>\n<p>Each image resource has a <code>public_id<\/code> which is passed in the <code>public_id<\/code> key. The <code>cloudName<\/code> is passed as a prop to the theme by the user. This <code>cloudName<\/code> is accessed using the <code>options<\/code> object, similar to the <code>basePath<\/code> prop, and passed to the <code>cloud_name<\/code> key.<\/p>\n<p>The <code>createNodeId<\/code> is a utility function to generate globally unique and stable node IDs. You can read more about the <code>createNodeId<\/code> function <a href=\"https:\/\/www.gatsbyjs.com\/docs\/reference\/config-files\/node-api-helpers\/#createNodeId\">here<\/a>.<\/p>\n<p>The <code>parent<\/code> is a key reserved for plugins who wish to extend other nodes. It is not needed in this theme, so you pass <code>null<\/code> to it.<\/p>\n<p>The <code>type<\/code> is the globally unique node type. This will be used when running GraphQL queries.<\/p>\n<p>The <code>contentDigest<\/code> is a short digital summary of the content of this node, and the <code>content<\/code> exposes the raw content of this node that any transformation plugin can take and further process it.<\/p>\n<p>You can read more about Node Creation <a href=\"https:\/\/www.gatsbyjs.com\/docs\/node-creation\/\">here<\/a>.<\/p>\n<p>Navigate to your Cloudinary dashboard in the browser and copy your <strong>Cloudinary Cloud Name<\/strong>, <strong>API Key<\/strong>, and <strong>API Secret<\/strong> from there.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624259261\/e-603fc45fe6c0b4006873802f\/nmxjr09dscpfyfxm2ptn.png\" alt=\"Cloudinary Dashboard\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1330\" height=\"385\"\/><\/p>\n<p>The next step is to create a function to fetch the images from Cloudinary and create nodes from them. You will use the <code>cloudinary<\/code> npm package to do so.<\/p>\n<p>Run the following command to install <code>cloudinary<\/code> and <code>cloudinary-react<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn workspace gatsby-theme-cloudinary-gallery add cloudinary cloudinary-react\n<\/code><\/span><\/pre>\n<p>Import <code>cloudinary<\/code> at the top of the <code>gatsby-node.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ gatsby-theme-cloudinary-gallery\/gatsby-node.js<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> cloudinary = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">\"cloudinary\"<\/span>).v2;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Create a function named <code>createCloudinaryImageNodes<\/code> in the <code>gatsby-node.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> createCloudinaryImageNodes = <span class=\"hljs-function\">(<span class=\"hljs-params\">gatsby, cloudinary, options<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> cloudinaryOptions = {\n    <span class=\"hljs-attr\">type<\/span>: options.type || <span class=\"hljs-string\">\"upload\"<\/span>,\n    <span class=\"hljs-attr\">max_results<\/span>: options.maxResults || <span class=\"hljs-number\">10<\/span>,\n    <span class=\"hljs-attr\">prefix<\/span>: options.prefix || <span class=\"hljs-string\">''<\/span>,\n  };\n\n  <span class=\"hljs-keyword\">return<\/span> cloudinary.api.resources(cloudinaryOptions, (error, result) =&gt; {\n    result.resources.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">resource<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> nodeData = createNodeData(gatsby, resource, options);\n      gatsby.actions.createNode(nodeData);\n    });\n  });\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the above code, the <code>createCloudinaryImageNodes<\/code>  function takes <code>gatsby<\/code>, <code>cloudinary<\/code>, and <code>options<\/code> as arguments.<\/p>\n<p>You create a <code>cloudinaryOptions<\/code> object that contains the props to modify the Cloudinary fetch request. The user passes these props in the <code>gatsby-config.js<\/code> file similar to the <code>basePath<\/code> prop and is accessed using the <code>options<\/code> object.<\/p>\n<p>These props are:<\/p>\n<ul>\n<li>\n<code>type<\/code> -This is the storage type: <code>upload<\/code>, <code>private<\/code>, <code>authenticated<\/code>, <code>facebook<\/code>, <code>twitter<\/code>, etc. Defaults to <code>upload<\/code>.<\/li>\n<li>\n<code>maxResults<\/code> &#8211; Maximum number of assets to return. Default &#8211; <code>10<\/code>.<\/li>\n<li>\n<code>prefix<\/code> -Find all resources with a public ID that starts with the given prefix. This is helpful when you want to access the images present in a particular folder.<\/li>\n<\/ul>\n<p>The above props are optional, and hence a default value is passed in each of them. You can create other fields like <code>resource_type<\/code>, <code>tags<\/code>, <code>context<\/code>, etc., in the <code>cloudinaryOptions<\/code> object. In this jam, we will restrict to these three props only.<\/p>\n<p>You pass the <code>cloudinaryOptions<\/code> object in the <code>cloudinary.api.resources()<\/code> method. This method fetches the image resources from your Cloudinary account based on the <code>options<\/code> or the <code>cloudinaryOptions<\/code> object. You can read more about the <code>api.resources<\/code> method <a href=\"https:\/\/cloudinary.com\/documentation\/admin_api#get_resources\">here<\/a>.<\/p>\n<p>The <code>result.resources<\/code> array contains the data of each image which is passed to the <code>createNodeData<\/code> function to reformat the data in the way needed to create the node.<\/p>\n<p>The reformatted data is then passed to gatsby\u2019s <code>createNode()<\/code> action creating a new node. You can read more about this action <a href=\"https:\/\/www.gatsbyjs.com\/docs\/reference\/config-files\/actions\/#createNode\">here<\/a>.<\/p>\n<p>Finally, you use the <code>createCloudinaryImageNodes<\/code> function inside the <code>sourceNodes<\/code> Gatsby API to source the nodes.<\/p>\n<p>Add the following code for the <code>sourceNodes<\/code> function in the <code>gatsby-node.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">exports.sourceNodes = <span class=\"hljs-function\">(<span class=\"hljs-params\">gatsby, options<\/span>) =&gt;<\/span> {\n  cloudinary.config({\n    <span class=\"hljs-attr\">cloud_name<\/span>: options.cloudName,\n    <span class=\"hljs-attr\">api_key<\/span>: options.apiKey,\n    <span class=\"hljs-attr\">api_secret<\/span>: options.apiSecret,\n  });\n\n  <span class=\"hljs-keyword\">return<\/span> createCloudinaryImageNodes(gatsby, cloudinary, options);\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the <code>sourceNodes<\/code> function, you create the Cloudinary instance and pass the API keys to it. These API keys are passed as props to the theme by the user and accessed using the <code>options<\/code> object.<\/p>\n<p>You can read more about <code>sourceNodes<\/code> <a href=\"https:\/\/www.gatsbyjs.com\/docs\/reference\/config-files\/gatsby-node\/#sourceNodes\">here<\/a>.<\/p>\n<p>To test the image nodes, update the <code>demo\/gatsby-config.js<\/code> file like this. Make sure to add your API keys in the <code>options<\/code> object. You can also pass value to optional fields like <code>basePath<\/code>, <code>type<\/code>, etc.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">\/\/ demo\/gatsby-config.js\nmodule.exports = {\n  plugins: &#91;\n    {\n      resolve: \"gatsby-theme-cloudinary-gallery\",\n      options: {\n        cloudName: <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">YOUR-CLOUDINARY-CLOUDNAME<\/span>&gt;<\/span>,\n        apiKey: <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">YOUR-CLOUDINARY-API-KEY<\/span>&gt;<\/span>,\n        apiSecret: <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">YOUR-CLOUDIANRY-API-SECRET<\/span>&gt;<\/span>,\n      },\n    },\n  ],\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Start the development server by running the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn workspace demo develop\n<\/code><\/span><\/pre>\n<p>Navigate to <a href=\"http:\/\/localhost:8000\/___graphql\">localhost:8000\/___graphql<\/a> in your browser. You will see the GraphiQL playground.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624259306\/e-603fc45fe6c0b4006873802f\/wv7tmzpkpr5tnrifmsd1.png\" alt=\"GraphQL playground\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1755\" height=\"861\"\/><\/p>\n<p>Paste the following query in the GraphiQL playground.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">query MyQuery {\n  allCloudinaryGallery {\n    nodes {\n      id\n      cloud_name\n    }\n  }\n}\n<\/code><\/span><\/pre>\n<p>Run the query by clicking the <code>Run<\/code> icon.<\/p>\n<p>You will see your <code>cloudName<\/code> and <code>public_id<\/code> of the images in the result tab.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624259335\/e-603fc45fe6c0b4006873802f\/hu5nqnyzeywchsdgfp44.png\" alt=\"GraphQL playground with query\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1755\" height=\"861\"\/><\/p>\n<p>You have successfully created Nodes from the images fetched from Cloudinary.<\/p>\n<h2>How to create the Gallery Component<\/h2>\n<p>In this section, you will create the <code>Gallery<\/code> component to display the images in a grid layout.<\/p>\n<p>Create a file named <code>Gallery.js<\/code> inside the <code>gatsby-theme-cloudinary-gallery\/src\/components<\/code> directory by running the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">touch gatsby-theme-cloudinary-gallery\/src\/components\/Gallery.js\n<\/code><\/span><\/pre>\n<p>Add the following code to the <code>Gallery.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { Image, Transformation } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"cloudinary-react\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> Gallery = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ cloudinaryImages }<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"container mx-auto grid grid-cols-1 md:grid-cols-2\n      lg:grid-cols-3 gap-3 p-8\"<\/span>&gt;<\/span>\n      {cloudinaryImages.length &gt; 0 &amp;&amp;\n        cloudinaryImages.map((cloudinaryImage) =&gt; (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Image<\/span>\n            <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{cloudinaryImage.id}<\/span>\n            <span class=\"hljs-attr\">cloudName<\/span>=<span class=\"hljs-string\">{cloudinaryImage.cloud_name}<\/span>\n            <span class=\"hljs-attr\">publicId<\/span>=<span class=\"hljs-string\">{cloudinaryImage.public_id}<\/span>\n            <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full block mx-auto\"<\/span>\n          &gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Transformation<\/span>\n              <span class=\"hljs-attr\">fetchFormat<\/span>=<span class=\"hljs-string\">\"auto\"<\/span>\n              <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"800\"<\/span>\n              <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">\"800\"<\/span>\n              <span class=\"hljs-attr\">loading<\/span>=<span class=\"hljs-string\">\"lazy\"<\/span>\n              <span class=\"hljs-attr\">radius<\/span>=<span class=\"hljs-string\">\"20\"<\/span>\n              <span class=\"hljs-attr\">gravity<\/span>=<span class=\"hljs-string\">\"face\"<\/span>\n              <span class=\"hljs-attr\">crop<\/span>=<span class=\"hljs-string\">\"fill\"<\/span>\n            \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Image<\/span>&gt;<\/span>\n        ))}\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span><\/span>\n  );\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Gallery;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the above code, you take the images as a prop in the <code>Gallery<\/code> component. You map over the <code>cloudinaryImages<\/code> array to display the images using the <code>Image<\/code> component from the <code>cloudinary-react<\/code> package. Tailwind CSS is used to style the gallery and create the grid layout.<\/p>\n<p>You transform the images using the <code>Transformation<\/code> component. Here are all the default transformations applied to the images.<\/p>\n<figure class=\"table-wrapper\"><table>\n<thead>\n<tr>\n<th>Key<\/th>\n<th>Default<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>fetchFormat<\/td>\n<td><code>auto<\/code><\/td>\n<td>The format of the fetched image. Using <code>auto<\/code>, delivers the image in the most optimized format for each browser that requests it.  For more details see <a href=\"https:\/\/cloudinary.com\/documentation\/image_transformations#image_format_conversion\">image format conversion<\/a>.<\/td>\n<\/tr>\n<tr>\n<td>width<\/td>\n<td><code>800<\/code><\/td>\n<td>Width of the fetched image.<\/td>\n<\/tr>\n<tr>\n<td>height<\/td>\n<td><code>800<\/code><\/td>\n<td>Height of the fetched image.<\/td>\n<\/tr>\n<tr>\n<td>loading<\/td>\n<td><code>lazy<\/code><\/td>\n<td><a href=\"https:\/\/cloudinary.com\/documentation\/react_image_manipulation#lazy_loading\">Lazy Loading<\/a> to delay loading images if they are not yet visible on the screen.<\/td>\n<\/tr>\n<tr>\n<td>radius<\/td>\n<td><code>20<\/code><\/td>\n<td>Round the corner of the images.<\/td>\n<\/tr>\n<tr>\n<td>gravity<\/td>\n<td><code>face<\/code><\/td>\n<td>To automatically crop an image so that the detected face(s) is used as the center of the derived picture, set the gravity parameter to faces &#8211; the region of the image that includes all the faces detected.<\/td>\n<\/tr>\n<tr>\n<td>crop<\/td>\n<td><code>fill<\/code><\/td>\n<td>Resizes the image to fill the specified dimensions without distortion. The image may be cropped as a result.    For more details <a href=\"https:\/\/cloudinary.com\/documentation\/resizing_and_cropping#resize_and_crop_modes\">see<\/a>.<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/figure>\n<p>You can add more transformations in the above code as per the requirements of your theme.<\/p>\n<p>Update the <code>pages\/index.js<\/code> file like this.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { graphql, useStaticQuery } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"gatsby\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Gallery <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/components\/Gallery.js\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Heading <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/components\/Heading.js\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> Homepage = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> data = useStaticQuery(graphql<span class=\"hljs-string\">`\n    query {\n      allCloudinaryGallery {\n        nodes {\n          public_id\n          id\n          cloud_name\n        }\n      }\n    }\n  `<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> images = data.allCloudinaryGallery.nodes;\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-gray-200 min-h-screen p-8\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Heading<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Gallery<\/span> <span class=\"hljs-attr\">cloudinaryImages<\/span>=<span class=\"hljs-string\">{images}<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Homepage;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You use the <code>useStaticQuery<\/code> hook from Gatsby to fetch the data using the query discussed above. The <code>useStaticQuery<\/code>  hook fetches data using a GraphQL query. This fetched data is parsed and injected into your React components. You can read more about this hook <a href=\"https:\/\/www.gatsbyjs.com\/docs\/how-to\/querying-data\/use-static-query\/#how-to-use-usestaticquery-in-components\">here<\/a>.<\/p>\n<p>You pass the <code>images<\/code> array, which contains <code>id<\/code>, image\u2019s <code>public_id<\/code>, and <code>cloud_name<\/code>, to the <code>Gallery<\/code> component.<\/p>\n<p>Start the demo <code>workspace<\/code> development server and head over to <a href=\"http:\/\/localhost:8000\/\">http:\/\/localhost:8000\/<\/a> in the browser.<\/p>\n<p>Your app will look similar to this. The images may vary from the photos in your Cloudinary dashboard.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624259369\/e-603fc45fe6c0b4006873802f\/bdgirguqs6qqynup1iwg.png\" alt=\"Cloudinary Image Gallery\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1899\" height=\"1299\"\/><\/p>\n<p>What if the user wants to embed the image gallery in another page and not create a specific route for it. For this, you can export the <code>pages\/index.js<\/code> file in the <code>gatsby-theme-cloudinary-gallery\/index.js<\/code> file.<\/p>\n<p>Add the following code to the <code>gatsby-theme-cloudinary-gallery\/index.js<\/code> file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/gatsby-theme-cloudinary-gallery\/index.js<\/span>\n<span class=\"hljs-keyword\">export<\/span> { <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">as<\/span> Gallery } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/src\/pages\/index\"<\/span>;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now, you can import this <code>Gallery<\/code> component in any page of your Gatsby site and use the component inside it.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { Gallery } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"gatsby-theme-cloudinary-gallery\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> Homepage = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> (\n  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Gallery<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n);\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Homepage;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here is how the embed Image Gallery will look like.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624259402\/e-603fc45fe6c0b4006873802f\/yekt3qmdx3ufaojzzuly.jpg\" alt=\"Gallery Component\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1562\" height=\"1439\"\/><\/p>\n<h2>How to publish your theme to NPM<\/h2>\n<p>In this section, you will publish your Gatsby Theme to the npm registry.<\/p>\n<p>Create a <code>README.md<\/code> file in the <code>gatsby-theme-cloudinary-gallery<\/code> directory and create a simple documentation for your theme. You can refer to the <code>README.md<\/code> file of this project here.<\/p>\n<p>Update the <code>name<\/code> field in the <code>gatsby-theme-cloudinary-gallery\/package.json<\/code> with your GitHub handle like this.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">{\n<span class=\"hljs-string\">\"name\"<\/span>: <span class=\"hljs-string\">\"@lelouchb\/gatsby-theme-cloudinary-gallery\"<\/span>,\n...\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Create an NPM account if you haven\u2019t already from the <a href=\"https:\/\/www.npmjs.com\/signup\">NPM Signup page<\/a>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624259428\/e-603fc45fe6c0b4006873802f\/rvv26rlpgcuhpsrijuwr.png\" alt=\"NPM SignUp\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1519\" height=\"1016\"\/><\/p>\n<p>Login to your NPM account by runnning the following command in the terminal.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm adduser\n<\/code><\/span><\/pre>\n<p>You will be prompted for your username, password, and email id.<\/p>\n<p>Once you have logged in, run the following command in your project\u2019s root terminal to publish your theme.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">cd gatsby-theme-cloudinary-gallery\nnpm publish --access <span class=\"hljs-keyword\">public<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>After the theme has been published you will see a message similar to this in your terminal.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">notice<\/span> \n<span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">notice<\/span> \ud83d\udce6  <span class=\"hljs-keyword\">@lelouchb<\/span>\/gatsby-theme-cloudinary-gallery<span class=\"hljs-keyword\">@1<\/span>.0.0\nnpm notice === Tarball Contents === \nnpm notice <span class=\"hljs-number\">962<\/span>B    package.json\nnpm notice === Tarball Details ===\nnpm notice <span class=\"hljs-attribute\">name:<\/span>          @lelouchb\/gatsby-theme-cloudinary-gallery\nnpm notice <span class=\"hljs-attribute\">version:<\/span>       <span class=\"hljs-number\">1.0<\/span>.<span class=\"hljs-number\">0<\/span>\nnpm notice <span class=\"hljs-attribute\">filename:<\/span>      @lelouchb\/gatsby-theme-cloudinary-gallery-<span class=\"hljs-number\">1.0<\/span>.<span class=\"hljs-number\">0<\/span>.tgz\nnpm notice package <span class=\"hljs-attribute\">size:<\/span>  <span class=\"hljs-number\">531.7<\/span> kB\nnpm notice unpacked <span class=\"hljs-attribute\">size:<\/span> <span class=\"hljs-number\">1.7<\/span> MB\nnpm notice <span class=\"hljs-attribute\">shasum:<\/span>        e98761e3870f1f50fatWrERwybd5c6819e809548eaed82ef3\nnpm notice <span class=\"hljs-attribute\">integrity:<\/span>     sha512-wCSHgJpQcgprkJeo-Po+aG&#91;...]PJL3PXjK9ZkdA==\nnpm notice total <span class=\"hljs-attribute\">files:<\/span>   <span class=\"hljs-number\">237<\/span>\n\n+ @lelouchb\/gatsby-theme-cloudinary-gallery@<span class=\"hljs-number\">1.0<\/span>.<span class=\"hljs-number\">0<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You can view this theme on NPM <a href=\"https:\/\/www.npmjs.com\/package\/gatsby-theme-cloudinary-gallery\">here<\/a>.<\/p>\n<h2>Conclusion<\/h2>\n<p>In this media jam, we discussed how to create a Gatsby Theme for Image Gallery. We saw how to integrate Tailwind CSS with a Gatsby site.<\/p>\n<p>Finally, we published our Gatsby Theme to the npm registry.<\/p>\n<p>Here are a few resources that you might find helpful:<\/p>\n<ul>\n<li>\n<a href=\"https:\/\/cloudinary.com\/documentation\/admin_api\">Cloudinary Admin API Docs<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/www.gatsbyjs.com\/docs\/how-to\/plugins-and-themes\/shadowing\/\">Shadowing in Gatsby Themes<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/docs.npmjs.com\/cli\/v7\/commands\/npm-publish\">Publishing to NPM registry Docs<\/a>\n<\/li>\n<\/ul>\n<p>Happy coding!<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28053,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[378,134,370,371],"class_list":["post-28052","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-gatsbyjs","tag-guest-post","tag-image","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How to build a Gatsby Image Gallery Theme<\/title>\n<meta name=\"description\" content=\"In this media jam, we will build a Gatsby Theme for an Image Gallery. The images will be stored and fetched from Cloudinary. We will conclude this jam by publishing our theme to the npm registry.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to build a Gatsby Image Gallery Theme\" \/>\n<meta property=\"og:description\" content=\"In this media jam, we will build a Gatsby Theme for an Image Gallery. The images will be stored and fetched from Cloudinary. We will conclude this jam by publishing our theme to the npm registry.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-06-24T14:29:10+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"How to build a Gatsby Image Gallery Theme\",\"datePublished\":\"2021-06-24T14:29:10+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA\",\"keywords\":[\"GatsbyJS\",\"Guest Post\",\"Image\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2021\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/\",\"name\":\"How to build a Gatsby Image Gallery Theme\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA\",\"datePublished\":\"2021-06-24T14:29:10+00:00\",\"description\":\"In this media jam, we will build a Gatsby Theme for an Image Gallery. The images will be stored and fetched from Cloudinary. We will conclude this jam by publishing our theme to the npm registry.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA\",\"width\":1899,\"height\":1295},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to build a Gatsby Image Gallery Theme\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to build a Gatsby Image Gallery Theme","description":"In this media jam, we will build a Gatsby Theme for an Image Gallery. The images will be stored and fetched from Cloudinary. We will conclude this jam by publishing our theme to the npm registry.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/","og_locale":"en_US","og_type":"article","og_title":"How to build a Gatsby Image Gallery Theme","og_description":"In this media jam, we will build a Gatsby Theme for an Image Gallery. The images will be stored and fetched from Cloudinary. We will conclude this jam by publishing our theme to the npm registry.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/","og_site_name":"Cloudinary Blog","article_published_time":"2021-06-24T14:29:10+00:00","twitter_card":"summary_large_image","twitter_image":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/"},"author":{"name":"","@id":""},"headline":"How to build a Gatsby Image Gallery Theme","datePublished":"2021-06-24T14:29:10+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/"},"wordCount":8,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA","keywords":["GatsbyJS","Guest Post","Image","Under Review"],"inLanguage":"en-US","copyrightYear":"2021","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/","name":"How to build a Gatsby Image Gallery Theme","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA","datePublished":"2021-06-24T14:29:10+00:00","description":"In this media jam, we will build a Gatsby Theme for an Image Gallery. The images will be stored and fetched from Cloudinary. We will conclude this jam by publishing our theme to the npm registry.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA","width":1899,"height":1295},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/how-to-build-a-gatsby-image-gallery-theme\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to build a Gatsby Image Gallery Theme"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925548\/Web_Assets\/blog\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8\/3c098a81de4f05d65ec02cf291138c5e8869c2bc-1899x1295-1_28053f87f8.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28052","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28052"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28052\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28053"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28052"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28052"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28052"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}