1

So I generate conditional layouts with this code:

exports.onCreatePage = ({ page, actions }) => {
  const { createPage } = actions;

  if (page.path.match(/about/)) {
    page.context.layout = "special";
    createPage(page);
  }

  if (page.path.match(/projects/)) {
    page.context.layout = "projectsPage";
    createPage(page);
  }
};

I want to change the page.path.mathch(/projects/TO ALL PROJECT SLUGS/) but I can't write the correct syntax for the path.

Does anyone know how to get all the paths after the /projects/ ?

This is the full gatsby.node.js

const path = require("path");
const { createFilePath } = require(`gatsby-source-filesystem`);

exports.onCreatePage = ({ page, actions }) => {
  const { createPage } = actions;

  if (page.path.match(/about/)) {
    page.context.layout = "special";
    createPage(page);
  }

  if (page.path.match(/projects\/([^\/]+$)/)) {
    page.context.layout = "projectsPage";
    createPage(page);
  }
};

exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions;
  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode, basePath: `pages` });
    createNodeField({
      node,
      name: `slug`,
      value: slug,
    });
  }
};

exports.createPages = async function ({ graphql, actions }) {
  const { data } = await graphql(`
    query Projects {
      allMarkdownRemark {
        nodes {
          frontmatter {
            slug
          }
        }
      }
    }
  `);

  data.allMarkdownRemark.nodes.forEach((node) => {
    const slug = node.frontmatter.slug;
    actions.createPage({
      path: "/projects/" + slug,
      component: path.resolve("./src/templates/project-details.js"),
      context: { slug: slug },
    });
  });
};

And this is my template:

import React from "react";
import { AnimatePresence, motion } from "framer-motion";
import Navbar from "../components/Navbar/Navbar";
import Footer from "../components/Footer/Footer";
import FooterAbout from "../components/Footer/FooterAbout";

const duration = 0.5;

const variants = {
  initial: {
    opacity: 0,
  },
  enter: {
    opacity: 1,
    transition: {
      duration: duration,
      delay: duration,
      when: "beforeChildren",
    },
  },
  exit: {
    opacity: 0,
    transition: { duration: duration },
  },
};

export const Layout = ({ children, location, pageContext }) => {
  if (pageContext.layout === "projectsPage") {
    return (
      <main className="bg-black ">
        <AnimatePresence>
          <motion.main
            key={location.pathname}
            variants={variants}
            initial="initial"
            animate="enter"
            exit="exit"
            className="opacity-loader"
          >
            {children}
          </motion.main>
        </AnimatePresence>
      </main>
    );
  }
  if (pageContext.layout === "special") {
    return (
      <main className="bg-black ">
        <Navbar />
        <AnimatePresence>
          <motion.main
            key={location.pathname}
            variants={variants}
            initial="initial"
            animate="enter"
            exit="exit"
            className="opacity-loader"
          >
            {children}
          </motion.main>
        </AnimatePresence>
        <FooterAbout />
      </main>
    );
  }
  return (
    <main className="bg-black ">
      <Navbar />
      <AnimatePresence>
        <motion.main
          key={location.pathname}
          variants={variants}
          initial="initial"
          animate="enter"
          exit="exit"
          className="opacity-loader"
        >
          {children}
        </motion.main>
      </AnimatePresence>
      <Footer />
    </main>
  );
};

export default Layout;

It seems like I am missing something, it accepts the (/projects/) path but not (/projects/([^/]+$)/).

To make it more clear I only want to disable the layout in the subdirectory pages of projects not in the /projects/ page.

Dom V
  • 51
  • 7

1 Answers1

1

You can use the following regular expression:

projects\/([^\/]+$)

This will match everything after /projects/. So:

  if (page.path.match(/projects\/([^\/]+$)/)) {
    page.context.layout = "projectsPage";
    createPage(page);
  }

I've added a sandbox to test all scenarios: https://regex101.com/r/eQRJb4/1

Alternatively, you can try gatsby-plugin-create-client-paths what makes exactly the same job automatically. In your case:

{
  resolve: `gatsby-plugin-create-client-paths`,
  options: { prefixes: [`/projects/*`] },
},

You can achieve the same result more easily like:

  data.allMarkdownRemark.nodes.forEach((node) => {
    const slug = node.frontmatter.slug;
    actions.createPage({
      path: "/projects/" + slug,
      component: path.resolve("./src/templates/project-details.js"),
      context: { slug: slug, layout: "projectsPage" },
    });
  });
Ferran Buireu
  • 28,630
  • 6
  • 39
  • 67
  • Thank you @Ferran for your answer, I tried it and it accepts it's syntax but it's not working for a strange reason, if I write it like this: (/projects/) its working but it's not the result I want. Any suggestions why it's not working? – Dom V Oct 29 '21 at 13:35
  • Without seeing it it's difficult to guess. Try directly `/projects/*` or use the plugin I suggested in the edited answer. – Ferran Buireu Oct 29 '21 at 15:05
  • I installed the plugin and it kinda broke few things, it works in the subdirectories but also in the root folder /projects/ .I added it exactly like you commented as well. I added my whole code of gatsby.config.js and my template. – Dom V Oct 29 '21 at 22:45
  • 1
    Now that I have more context I've added a more intuitive way of adding a "layout" property to the projects in your `pageContext` – Ferran Buireu Oct 30 '21 at 06:21
  • 1
    Yes, that's working! Many thanks Ferran – Dom V Nov 01 '21 at 14:02