Skip to content

Instantly share code, notes, and snippets.

@ekafyi
Last active June 12, 2020 19:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ekafyi/ab7b6b50518d78ffa0b657cb6300a4f9 to your computer and use it in GitHub Desktop.
Save ekafyi/ab7b6b50518d78ffa0b657cb6300a4f9 to your computer and use it in GitHub Desktop.
How I made the example portfolio site for Gatsby Theme Web Monetization

How I made the example portfolio site with Gatsby Theme Web Monetization

In this site, I combine gatsby-theme-web-monetization with the excellent Emilia Theme by LekoArts using its starter site. Then I continue with the steps below.

  1. Install the theme.
yarn add gatsby-theme-web-monetization
# or npm install --save gatsby-theme-web-monetization
  1. Add theme to gatsby-config. The order does not matter with the plugins used in this repo. If you use this with other plugins and encounter issues, you may have to do some trial and error regarding the plugins order.
// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-theme-web-monetization`,
      options: {
        // Replace with your wallet's payment pointer
        paymentPointer: "$wallet.example.com/eka",
      },
    },
    // ... other themes
  ]
}
  1. As shown in the basic example, we can use the theme’s components in MDX pages without importing anything. Additionally, we can also use them in our components outside of MDX by importing them.

In this example, I import the WebMonetizedStatus component and add it to the header.

// src/@lekoarts/gatsby-theme-emilia/components/header.js

// ... other imports
import { WebMonetizedStatus } from "gatsby-theme-web-monetization";

// Pass your message/content as props to the WebMonetizedStatus component
const customActive = "String or component to render if Web Monetization is active";
const customInactive = "String or component to render if Web Monetization is not active";

const Header = () => {
  return (
    <>
      {/* ... header component code */}
      <WebMonetizedStatus
        active={customActive}
        inactive={customInactive}
      />
      {/* ... more header component code */}
    </>
  );
};

export default Header;
  • See theme documentation for the list of components you can use.
  • In the full code, I use the sx props for styling with Theme UI. You can use any other styling methods (Styled Components, CSS Modules, add Tailwind CSS class names, etc).
  • This file structure comes from “shadowing” the Emilia theme, ie. overriding the theme’s Header component with my modified one. You can use the gatsby-theme-web-monetization components anywhere, regardless of the theme shadowing concept.

Now for each photograph, I want to do these:

  • Display hi-res image download link only to web monetized users
  • Display call to action/message to non-web monetized users

I can achieve it this way in an MDX page. (This is a barebones simplified example which has not addressed CSS styling.)

---
title: My test post
date: 2020-06-03
---

![Description of the photo](./images/some-source.jpg)

<figcaption>Some image caption here</figcaption>

<IfWebMonetized>

[Download hi-res image](https://dropbox.com/some-download-link)

</IfWebMonetized>

<WebMonetizedPaywall>

👋🏼 Want this photo? Hi-res image download is available for web monetized users. [Learn more.](https://coil.com)

</WebMonetizedPaywall>

But it’s tedious, messy, and impractical to repeat these lines for every photograph and every series page. We can abstract these away into a reusable component, as shown in the next step.

  1. Create a Photo component that renders an image from the specified source, a download link for monetized users, and a message for non-monetized users.
// src/components/photo.js (truncated to relevant parts)

// ... other imports
import { WebMonetizedPaywall } from "gatsby-theme-web-monetization";
import { IfWebMonetized } from "react-web-monetization";

import ButtonDownload from "./button-download";
import Cta from "./cta";
import CustomImg from "./custom-img";

const Photo = ({ src, alt, caption, isFree, downloadUrl }) => {
  return (
    <>
      <CustomImg src={src} alt={alt || ""} />
      {caption && <figcaption>{caption}</figcaption>}
      {downloadUrl &&
        (isFree ? (
          <ButtonDownload href={downloadUrl} />
        ) : (
          <>
            <IfWebMonetized>
              <ButtonDownload href={downloadUrl} />
            </IfWebMonetized>
            <WebMonetizedPaywall>
              <Cta />
            </WebMonetizedPaywall>
          </>
        ))}
    </>
  );
};

export default Photo;
  • We import WebMonetizedPaywall and IfWebMonetized (the latter from react-web-monetization, which is a dependency of this theme; you don’t need to install it yourself to import the components).
  • We create and import UI components ButtonDownload (the “Download” button) and Cta (the call-to-action message). We also have utility component CustomImg to query for image and process it through Gatsby’s Sharp image library (which has neat capabilities like lazy loading, auto resizing, srcset attribute, etc). These are just an example; you can use any approach, styling decisions, and add or remove any functionalities.
  • We add ButtonDownload inside IfWebMonetized to display to web monetized users, and add Cta inside WebMonetizedPaywall for non web monetized users.
  • In case I want to make some of my photos downloadable by all users, I also have an isFree prop.

This Photo component is not yet available for use in MDX pages. We can either import it (which will also be tedious as we have to do it on every page), or we can create our own MDX Provider and pass the Photo component there, which will allow us to use Photo in our MDX pages without importing.

  1. Create a custom MDXProvider component and pass our Photo component there. I’m calling it MyMdxProvider.
import React from "react";
import { MDXProvider } from "@mdx-js/react";
import Photo from "./photo";

const components = { Photo };

const MyMdxProvider = ({ children }) => (
  <MDXProvider components={components}>{children}</MDXProvider>
);

export default MyMdxProvider;

If you build your Gatsby site without a theme, add the Photo component to your existing MDXProvider instead, and skip the next step. Learn more about MDX Provider.

  1. We need to wrap our project content with our new MyMdxProvider so we can use the Photo component without importing. We can do so by shadowing the Emilia theme’s project page layout.
// src/@lekoarts/gatsby-theme-emilia/components/project.js

// ...other imports
import MyMdxProvider from "../../../components/my-mdx-provider";

const Project = ({ data: { project } }) => {
  return (
    <Layout>
      <SEO // ... props
      />
      <MyMdxProvider>
        <HeaderProject
          title={project.title}
          description={project.body}
          areas={[]}
          date={project.date}
        />
      </MyMdxProvider>
    </Layout>
  );
};

export default Project;
  1. Finally, we use the Photo component in MDX pages.
---
title: Sleeping Cats
date: 2020-06-03
---

<Photo
  src="sleeping-cats/images/sc1.jpg"
  caption="This is not an apple"
  alt="Gray tabby kitten sleeping in a wooden storage box that said 'Apples' atop of a pile of newspapers. The handle is full of scratches."
  downloadUrl="https://www.dropbox.com/s/nu0xrsje9npbdlx/full_sc1.jpg?dl=0"
/>
  • (Nothing to do with gatsby-theme-web-monetization, just how this Photo component works.) Due to how the GraphQL file query works, the photo src value is relative to the projects path, NOT the MDX file. For instance, for image file located in content/projects/sleeping-cats/images/sc1.jpg, we write src="sleeping-cats/images/sc1.jpg".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment