GithubHelp home page GithubHelp logo

olavea / rubys-timeship Goto Github PK

View Code? Open in Web Editor NEW
0.0 3.0 0.0 230.59 MB

Ruby's TimeShip

Home Page: https://timeship1.gatsbyjs.io/

JavaScript 99.97% CSS 0.03%
gatsby gatsby-functions outseta stripe-checkout

rubys-timeship's Introduction

Gatsby

My New Gatsby Blog

πŸš€

  1. I Created a Gatsby site.

    With the Gatsby and the minimal starter.

    npm init gatsby
  2. I wanted a little developing.

    Because I want to keep up on my daily writing habit

  3. Open the code and start customizing!

    Your site is now running at http://localhost:8000!

    Edit src/pages/index.js to see your site update in real-time!

  4. Learn more

πŸš€ Quick start (Netlify)

Deploy this starter with one click on Netlify:

Deploy to Netlify

rubys-timeship's People

Contributors

olavea avatar

Watchers

 avatar  avatar

rubys-timeship's Issues

fix: onRenderBody into gatsby-browser πŸ˜ΊπŸ‘ #22

fix: onRenderBody into gatsby-browser πŸ˜ΊπŸ‘ #22

// gatsby-browser.js πŸ˜ΊπŸ‘
import React from 'react';
import Layout from './src/components/Layout';
import { onRenderBody } from "./gatsby-ssr";

export function wrapPageElement({ element, props }) {
  return <Layout {...props}>{onRenderBody, element}</Layout>;
}

and

πŸ˜ΊπŸ‘
// gatsby-ssr.js
import React from "react";
import Layout from "./src/components/Layout";

const OusetaScriptComponent = () => {
  return (
    <script
      key="outseta-script"
      id="outseta-script"
      src="https://cdn.outseta.com/outseta.min.js"
      data-options="o_options"
    />
  );
};

const OusetaConfigComponent = () => {
  const config = {
    domain: "queen.outseta.com",
    monitorDom: true,
  };
  return (
    <script
      key="outseta-config"
      id="outseta-config"
      dangerouslySetInnerHTML={{
        __html: `var o_options = ${JSON.stringify(config, null, 2)}`,
      }}
    />
  );
};



// B. Body setHead on body

const onRenderBody = ({ setHeadComponents }) => {
  return setHeadComponents([OusetaConfigComponent(), OusetaScriptComponent()]);
};


export function wrapPageElement({ element, props }) {
  return <Layout {...props}>{onRenderBody, element}</Layout>;
}

Storyblok, Programmatically create pages from data

npm install storyblok-rich-text-react-renderer

npm install --save gatsby-source-storyblok

GATSBY / gatsby-config.js
    {
      resolve: 'gatsby-source-storyblok',
      options: {
        accessToken: 'YOUR_TOKEN',
        version: 'draft',
      }
    }
GATSBY / gatsby-node.js
const path = require('path')

exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions

  return new Promise((resolve, reject) => {
    const blogPostTemplate = path.resolve('./src/templates/blog-entry.js')

      resolve(
        graphql(
          `{
            posts: allStoryblokEntry(filter: {field_component: {eq: "Post"}}) {// πŸ‘ˆ the name of your component name
              edges {
                node {
                  id
                  name
                  slug
                  field_component
                  full_slug
                  content
                }
              }
            }
          }`
        ).then(result => {
          if (result.errors) {
            console.log(result.errors)
            reject(result.errors)
          }

          const allPosts = result.data.posts.edges

          allPosts.forEach((entry) => {
            // πŸ‘‡ the name of content type
            if(entry.slug !== "blog") {
              const page = {
                  path: `/${entry.node.full_slug}`,
                  component: blogPostTemplate,
                  context: {
                    story: entry.node
                  }
              }
              createPage(page)
            }
          })
        })
      )
    })
}

Add a sign up and log in with Outseta

What:

Add
βš“ Log in βš“
πŸƒ Sign up πŸƒ
to // src / pages / index.js

Why:

Stop Lizabeth's enemies from stealing Ruby's TimeShip. (See all the way at the bottom)
This is how it should look. (show webapp)

How:

Plan
A. Add βš“ Anchors and a head script
B. Body setHead on body

C. Config
D. Domain

E. Error
F. Finish

G. Get it on Github and Gatsby cloud
https://timeship1.gatsbyjs.io/

Let's start coding.

A. Add βš“ Anchors and a head script

// src / pages / index.js
      <section>
        <a href="https://queen.outseta.com/auth?widgetMode=login#o-anonymous">
        βš“ Log in βš“
        </a>
        <a href="https://queen.outseta.com/auth?widgetMode=register#o-anonymous">
          πŸƒ Sign up πŸƒ
        </a>
      </section>

B. Body setHead on body

// gatsby-ssr.js
import React from "react";

const OusetaScriptComponent = () => {
  return (
    <script
      key="outseta-script"
      id="outseta-script"
      src="https://cdn.outseta.com/outseta.min.js"
//      data-options="o_options"
    />
  );
};

// B. Body setHead on body

const onRenderBody = ({ setHeadComponents }) => {
return setHeadComponents([/*OusetaConfigComponent(),*/ OusetaScriptComponent()]);
};

export { onRenderBody };

C. Config

// gatsby-ssr.js

const OusetaConfigComponent = () => {
  const config = {
    domain: "queen.outseta.com",
    monitorDom: true,
  };
  return (
    <script
      key="outseta-config"
      id="outseta-config"
      dangerouslySetInnerHTML={{
        __html: `var o_options = ${JSON.stringify(config, null, 2)}`,
      }}
    />
  );
};

D. Domain
Delete these comments.

// gatsby-ssr.js
//      data-options="o_options"
/*OusetaConfigComponent(),*/

E. Error is gone
F. Finished

G. Get it on Github and Gatsby cloud
https://timeship1.gatsbyjs.io/

Docs:
https://timeship.outseta.com/#/app/auth/embeds/quickstart

Mary_1-kopi
Mary 1
(Her Murderous Majesty of Britannia)

cat-fox-pink
Simona "Red Fox" Renard
(Queen Mary's Inquisitor)

and

Captain Kitten
(Famous baker apprentice)

Take donations to POW!

https://github.com/lillian-raae-vea/go-gatsby-funcjam-21/blob/main/src/api/time-ship.js

// The PiRATE_PRiNCESS we are looking for to team up with
const PiRATE_PRiNCESS = {
    age: "11",
    hairColor: "gold",
    skill: "gatsby_function_programming"
}
const stripe = require('stripe')(process.env.STRIPE_KEY);

async function timeShipHandler(req, res) {
    // Get the data from the query of req-the-bat πŸ¦‡
    const { city, year, price, cancelUrl } = req.query;
    // Create a Stripe checkout session
    // Copy / paste from stripe docs node.js thing
    const session = await stripe.checkout.sessions.create({
        success_url: `https://timeship.gatsbyjs.io/api/time-ship-landing-in?city=${city}&year=${year}&price=333${price}&session_id={CHECKOUT_SESSION_ID}`,
        cancel_url: "http://localhost:8000/?payment=cancelled",
        payment_method_types: ['card'],
        line_items: [
            {
                // price data object in stripe docs
                price_data: {
                    unit_amount: req.query.price * 100,
                    currency: "usd",
                    product: "prod_K7EsOmDy6JLRgx",
                },
                quantity: 1,
            },
        ],
        mode: 'payment',
      });
      // Get the url to send back to Ruby's TimeShip
      // Give the data to res-the-cat 😺 and
      res.status(200).json({
        message: `Copy this url into the browser, to test-pay $${price} for TimeShip gold-fuel ( πŸ΄β€β˜ οΈπŸ˜ΊπŸ‘ $${price} are free-test-$s). ${session.url}`,
    });
}

export default async function handler(req, res) {
    try {
        if (req.method === "GET") {
            await timeShipHandler(req, res);
        } else {
            res.status(405).json({ message: "Method not supported" });
        }
    } catch (error) {
        // Something went wrong, log it
        console.error(error.message);
        // if something went wrong
        res.status(500).json({
            message: `Faulty TimeShip`,
        });
    }
}

Adding Image CDN to Queen @raae 's gatsby-source-youtube-oembed

// My steps are G. - I. M. A. G. E. - C. D. N.
const axios = require("axios");
const {
  polyfillImageServiceDevRoutes,
  addRemoteFilePolyfillInterface,
} = require("gatsby-plugin-utils/polyfill-remote-file");

const SPLIT_ASCII = ">>>";
const IS_PROD = process.env.NODE_ENV === "production";
const REFRESH_INTERVAL = IS_PROD ? 0 : 60000 * 5; // 60000 ms === 1 min

exports.onCreateDevServer = ({ app }) => {
  polyfillImageServiceDevRoutes(app);
};

exports.pluginOptionsSchema = ({ Joi }) => {
  return Joi.object({
    youTubeIds: Joi.array().items(Joi.string()).required(),
    refreshInterval: Joi.number().min(0).default(REFRESH_INTERVAL),
    // Will not document splitAscii, only for internal use
    splitAscii: Joi.string().default(SPLIT_ASCII),
  });
};

const fetchEmbed = async (id) => {
  const youTubeUrl = `https://youtu.be/${id}`;
  const { data } = await axios.get("https://www.youtube.com/oembed", {
    params: {
      url: youTubeUrl,
    },
  });
  return { ...data, url: youTubeUrl };
};

const prepYouTubeNode = async (gatsbyUtils, pluginOptions, youTubeId) => {
  const {
    actions: { createNode, touchNode },
    createNodeId,
    createContentDigest,
    reporter,
    cache,
    getNode,
  } = gatsbyUtils;
  const { refreshInterval = REFRESH_INTERVAL, splitAscii } = pluginOptions;

  const youTubeCache = await cache.get(youTubeId);
  const [existingNodeId, timestamp] = youTubeCache?.split(splitAscii) || [];
  const existingNode = getNode(existingNodeId);
  const existingNodeAge = Date.now() - timestamp;

  if (existingNode && existingNodeAge <= refreshInterval) {
    // Node already exists, make sure it stays around
    touchNode(existingNode);
    reporter.info(`Touched YouTube Node for ${youTubeId}`);
  } else {
    // Fetch oEmbed data and create node
    const youTubeNodeId = createNodeId(`you-tube-${youTubeId}`);
    const embedData = await fetchEmbed(youTubeId);

    createNode({
      id: youTubeNodeId,
      youTubeId: youTubeId,
      oEmbed: embedData,
      internal: {
        type: `YouTube`,
        contentDigest: createContentDigest(embedData),
      },
    });

    await cache.set(youTubeId, `${youTubeNodeId}${splitAscii}${Date.now()}`);
    reporter.info(`Created YouTube Node for ${youTubeId}`);
  }
};

exports.sourceNodes = async (gatsbyUtils, pluginOptions) => {
  const { youTubeIds } = pluginOptions;
  await Promise.all(
    youTubeIds.map((id) => prepYouTubeNode(gatsbyUtils, pluginOptions, id))
  );
};

exports.onCreateNode = async (gatsbyUtils) => {
  const { node, actions, reporter, createNodeId } = gatsbyUtils;
  const { createNodeField, createNode } = actions;

  if (node.internal.type === `YouTube`) {
    const youTubeThumbnailNodeId = createNodeId(
      `you-tube-thumbnail-${node.youTubeId}`
    );

    createNode({
      id: youTubeThumbnailNodeId,
      parent: node.id,
      youTubeId: node.youTubeId,
      url: node.oEmbed.thumbnail_url,
      mimeType: "image/jpeg",
      filename: node.youTubeId + ".jpg",
      height: node.oEmbed.thumbnail_height,
      width: node.oEmbed.thumbnail_width,
      internal: {
        type: `YouTubeThumbnail`,
        contentDigest: node.internal.contentDigest,
      },
    });

    reporter.info(
      `Created YouTubeThumbnail Node for ${node.youTubeId} thumbnail`
    );
  }
};

exports.createSchemaCustomization = ({ actions, schema }) => {
  actions.createTypes([
    `
    type YouTube implements Node {
      thumbnail: YouTubeThumbnail @link(from: "youTubeId" by: "youTubeId")
    }
  `,
    addRemoteFilePolyfillInterface(
      schema.buildObjectType({
        name: `YouTubeThumbnail`,
        fields: {
          // fields You don't need
          youTubeId: "String!",
        },
        interfaces: [`Node`, `RemoteFile`],
      }),
      {
        schema,
        actions,
      }
    ),
  ]);
};

data something see PR #27

data something see PR #27

Hi Benedict

I am working on preparing some questions for you for Thursday.

So, let's say conference buddies can tag conferences with for example "vue"

Question 1
How will I set up the data structure for that inside supabase

Question 2
What if I want to know who created that tag also? Like the author of that tag.

Now I add the tags myself as an array in markdown.

I am working on showing a list of tags on a page, if a conference buddy clicks a tag only the conferences with that tag should show up.

Peek-a-boo Skill-Building-Session

This screenshot is the End?:

The Start:
A button for icons

              <Grid item xs={12}>
                <IconButton>πŸ‘οΈβ€πŸ—¨οΈπŸŽ©</IconButton>
              </Grid>

Add onClick handler

                <IconButton
                  aria-label="toggle password visibility"
                  onClick={handleClickShowPassword}
                >
                  πŸ‘οΈβ€πŸ—¨οΈπŸŽ©
                </IconButton>

Poke your eye

The old PasSword

              <Grid item xs={12}>
                <TextField
                  id="passwordInput"
                  variant="outlined"
                  margin="normal"
                  name="password"
                  label="{values.showPassword ? "
                  type="password"
                  autoComplete="new-password"
                  placeholder="<VisibilityOff /> : <Visibility />}"
                  InputLabelProps={{ shrink: true }}
                  // required
                  fullWidth
                />
              </Grid>

https://youtu.be/v00Uro6UQvY?t=422
Let's change type

                  type={values.showPassword ? "text" : "password"}

Let's look at handleClick

  const handleClickShowPassword = () => {
    setValues({
      showPassword: !values.showPassword,
    });
  };

Let's look at values

  const [values, setValues] = React.useState({
    showPassword: false,
  });

https://youtu.be/v00Uro6UQvY?t=693
Adornment

                  endAdornment={}

TextField is no good to us now

                <OutlinedInput

fix: create only markdown pages

// gatsby-node.js
const { createFilePath } = require("gatsby-source-filesystem");

async function slugifyMarkdownRemarkNode(gatsbyUtils) {
  const { actions, node, getNode } = gatsbyUtils;
  const { createNodeField } = actions;

  if (node.internal.type === "MarkdownRemark") {
    const slug = createFilePath({ node, getNode });

    createNodeField({
      name: "slug",
      node,
      value: slug,
    });
  }
}



// POW!-website/gatsby-node.js
// I will delete all these comments and rename everything after my
// livestream on Thursday Feb 24.
// badly baked GingerBreadPages 🏠
// Only bake pages for markdown pages πŸ“„ and not sections. γŠ™οΈ πŸ“Ÿ
// 0. Only index.md πŸ“„
async function bakeMarkdownNodesIntoPages({ graphql, actions }) {
  // 1. filter β˜•
  //    supplies: not allMarkdownRemark.nodes πŸ’°
  const { data } = await graphql(`
    {
      supplies: allMarkdownRemark(
        filter: { fileAbsolutePath: { regex: "/index.md/" } }
      ) {
        nodes {
          id
          fields {
            slug
          }
        }
      }
    }
  `);
  console.log(data.supplies.nodes);

  // 2. bakingsong 🎡 πŸ™€
  const bakingSong = require.resolve("./src/templates/pageTemplate.js");
  // 3. aromaNode 🍰
  // Loop over the supplies.nodes and forEach((aromaNode and bake a page
  data.supplies.nodes.forEach((aromaNode) => {
    console.log(aromaNode.fields.slug, "πŸ’€πŸ“„");

    const aromaNodePath =
      aromaNode.fields.slug === "/index/" ? "/" : aromaNode.fields.slug;

    actions.createPage({
      // A. aromaNodePath 🍰.πŸ“.πŸ›
      path: aromaNodePath,

      // B. bakingSong 🎡 πŸ™€
      component: bakingSong,

      // C. catsbyId πŸ˜ΌπŸ†”
      context: {
        catsbyId: aromaNode.id,
      },
    });
  });
}

exports.onCreateNode = async (gatsbyUtils) => {
  await Promise.all([slugifyMarkdownRemarkNode(gatsbyUtils)]);
};

// 1.2.3 – A.B.C. – Gingerbread house

// 1. Supplies: allMarkdownRemark.node
// 2. Bakingsong = bakingSong.js
// 3. Loop over the supply node and create a page

// A. Ahoy! Aroma path!
// B. BakingSong is a component
// C. Catsby node.id is context
exports.createPages = async (gatsbyUtils) => {
  await Promise.all([bakeMarkdownNodesIntoPages(gatsbyUtils)]);
};
// src / templates / pageTemplate.js

import React from "react";
import { graphql, Link } from "gatsby";

export default function PageTemplate({ data = {} }) {
  const { frontmatter, html } = data.markdownRemark || {};
  const { title, sections } = frontmatter || {};
  function createEmail(event) {
    event.preventDefault();
    alert("POW! You've got mail πŸ“§ πŸ“«");
  }
  return (
    <>
      <div className="container">
        <h1>{title}</h1>
        <div dangerouslySetInnerHTML={{ __html: html }} />
        {(sections || []).map((section) => {
          const { title, subtitle, body } = section || {};
          const { html } = body?.childMarkdownRemark || {};
          const { path, label } = section.cta || {};
          const { form } = section || {};
          return (
            <section>
              {title && <h2>{title}</h2>}
              {subtitle && <h3>{subtitle}</h3>}
              {html && <div dangerouslySetInnerHTML={{ __html: html }} />}
              {path && label && <Link to={path}>{label}</Link>}
              {form && (
                <form
                  onSubmit={createEmail}
                  action="https://forms.userlist.com/b199b263-3262-435f-a9bc-96a12aa9955d/submissions"
                  method="POST"
                  acceptCharset="UTF-8"
                >
                  <fieldset>
                    <label htmlFor="fields_first_name">Your first name </label>
                    <input
                      type="text"
                      id="fields_first_name"
                      name="fields[first_name]"
                    />
                  </fieldset>
                  <fieldset>
                    <label htmlFor="fields_email">Your email address </label>
                    <input
                      type="text"
                      id="fields_email"
                      name="fields[email]"
                      required
                    />
                  </fieldset>
                  <button type="submit">
                    Subscribe to the POW! Newsletter
                  </button>
                </form>
              )}
            </section>
          );
        })}
      </div>
    </>
  );
}

export const query = graphql`
  query($catsbyId: String) {
    markdownRemark(id: { eq: $catsbyId }) {
      html
      frontmatter {
        title
        sections {
          title
          subtitle
          form
          body {
            childMarkdownRemark {
              html
            }
          }
          cta {
            path
            label
          }
        }
      }
    }
  }
`;
// src/ content / newsletter / index.md


---
title: Join the POW! newsletter for updates about
sections:
  - title: Privacy, Menstrual Health and POW!
    subtitle: No menstruation experience needed ;)
    form: newsletter
---

fake-login.js

// fake-login.js
// 205 lines -> 80
import * as React from "react";
import Box from "@mui/material/Box";
import IconButton from "@mui/material/IconButton";
import Input from "@mui/material/Input";
import FilledInput from "@mui/material/FilledInput";
import OutlinedInput from "@mui/material/OutlinedInput";
import InputLabel from "@mui/material/InputLabel";
import InputAdornment from "@mui/material/InputAdornment";
import FormHelperText from "@mui/material/FormHelperText";
import FormControl from "@mui/material/FormControl";
import TextField from "@mui/material/TextField";
import Visibility from "@mui/icons-material/Visibility";
import VisibilityOff from "@mui/icons-material/VisibilityOff";

export default function InputAdornments() {
  const [values, setValues] = React.useState({
    amount: "",
    password: "",
    weight: "",
    weightRange: "",
    showPassword: false,
  });

  const handleChange = (prop) => (event) => {
    setValues({ ...values, [prop]: event.target.value });
  };

  const handleClickShowPassword = () => {
    setValues({
      ...values,
      showPassword: !values.showPassword,
    });
  };

  const handleMouseDownPassword = (event) => {
    event.preventDefault();
  };

  return (
    <Box sx={{ display: "flex", flexWrap: "wrap" }}>
      <div>
        <TextField
          label="Username"
          id="outlined-start-adornment"
          sx={{ m: 1, width: "25ch" }}
          InputProps={{
            startAdornment: (
              <InputAdornment position="start">Username</InputAdornment>
            ),
          }}
        />
        <FormControl sx={{ m: 1, width: "25ch" }} variant="outlined">
          <InputLabel htmlFor="outlined-adornment-password">
            Password
          </InputLabel>
          <OutlinedInput
            id="outlined-adornment-password"
            type={values.showPassword ? "text" : "password"}
            value={values.password}
            onChange={handleChange("password")}
            endAdornment={
              <InputAdornment position="end">
                <IconButton
                  aria-label="toggle password visibility"
                  onClick={handleClickShowPassword}
                  onMouseDown={handleMouseDownPassword}
                  edge="end"
                >
                  {values.showPassword ? <VisibilityOff /> : <Visibility />}
                </IconButton>
              </InputAdornment>
            }
            label="Password"
          />
        </FormControl>
      </div>
    </Box>
  );
}

New Sanity Backend

Private
Please note that while documents are private, assets (files and images) are still public

Run sanity install to reinstall dependencies

Success! Now what?

β–ͺ sanity docs to open the documentation in a browser
β–ͺ sanity manage to open the project settings in a browser
β–ͺ sanity help to explore the CLI manual
β–ͺ sanity start to run your studio

1 tag per page, not many tags

because .... reasons

Here is some gatsby-node.js code I will not be using

gatsby-node.js
//              9. Captain Granny Sharksby createPages hook ↩️
async function turnToppingsIntoPages({ graphql, actions }) {
//              10. bakingSong = Lilly the Bunny require the bakingSong from granny Shark's gingerbread Recipe
  const bakingToppingSong = require.resolve('./src/pages/pizzaTags.js')
// //              11. bakingSupplies: tags in markdown files
  const { data } = await graphql(`{
    bakingMarkdown: allMarkdownRemark {
      nodes {
        id
        toppings: frontmatter {
          tags
        }
      }
    }
  }`)
//              12. turn toppings into pages with
//              Cap'n Granny Sharksby's createPages hook
  data.bakingMarkdown.nodes.forEach((ahoyCookie) => {
    const toppingTreasure = ahoyCookie.toppings.tags
    toppingTreasure.map((topping) => (
      actions.createPage({
//              A. Β«Ahoy! Cookie?!Β»
//              Cap'n Fox shouts and embarks. 🦊
              path: `topping/${topping}`,
//              B. Bunny sings badly
//              and bakes baby sharks. 🐰
              component: bakingToppingSong,
//              C. Catsby looks tasty
//              Fox gets hungry for kitten. 🐯
              context: {
                topping: topping,
                toppingRegex: `/${topping}/`,
      //              TODO Regex for Topping
      //          toppingRegex: `/${ahoyCookie.frontmatter.tags}/i`,
              },
      })
    ))
  });
//              13. Pass tag data to pizzaTags.js
}

gatsby-source-sanity

  • npm i gatsby-source-sanity

  • + [email protected]

  • npm install gatsby@latest gatsby-plugin-image@latest gatsby-plugin-sharp@latest gatsby-transformer-sharp@latest

  • gatsbyImage

// templates / RecipeSong.js
import { graphql } from "gatsby";
import React from "react";
import { GatsbyImage } from "gatsby-plugin-image";

export default function SingleImagePage({ data }) {
  return (
    <>
      <div>
        <h2 className="mark"> {data.supplies.name}</h2>
        <GatsbyImage
          image={data.supplies.image.asset.gatsbyImage}
          alt={data.supplies.name}
        />
      </div>
    </>
  );
}

export const query = graphql`
  query MySQLQuery($catsby: String!) {
    supplies: sanityPizza(id: { eq: $catsby }) {
      id
      name
      image {
        asset {
          gatsbyImage(width: 1333, placeholder: BLURRED, formats: AUTO)
        }
      }
    }
  }
`;

success Building development bundle - 12.925s
success Writing page-data.json files to public directory - 0.252s - 0/52 206.74/s

30 minutes total work time

http://localhost:8000/_gatsby/image/aHR0cHM6Ly9jZG4uc2FuaXR5LmlvL2ltYWdlcy84Zzh3bG82Ny9wcm9kdWN0aW9uLzgzODg0MjNlNGI5YTc5OTFhMThhOTUxNzQzMWJiZDU4NTljZTVlZmMtMjAwMHgyNjY3LmpwZw==/dz0xMzMzJmg9MTc3OCZmbT1qcGcmcT03NQ==/Lego-tivoli-2.jpg

  • is that link proof of image CDN?

OlaCast 14

//              G. Gulls will 🐦 return oembed data from Axios River
//              U. url:  2X
//              S. Spread 

// G. Gulls will 🐦 return oembed data from Axios River

  const oembedVideo = "🐺 + 🐢"
const oembedVideo = await axios.get("πŸ“ΊπŸ πŸ›Œ ",
    {params: {

// U. url: 2X

"https://www.youtube.com/oembed",
        url: `https://youtu.🐝/${🦜}`,
        maxwidth: 1554
    }})

// S. Spread

...oembedVideo,
const axios = require("axios")

const POW_TUBE_ID = "UGq8cnNTbwI"
async function bakeOneNodeGetOneVideo({actions, createContentDigest}) {
    const oembedVideo = await axios.get("https://www.youtube.com/oembed",
    {params: {
        url: `https://youtu.be/${POW_TUBE_ID}`,
        maxwidth: 1554
    }})

    actions.createNode({
        ...oembedVideo,
        id: POW_TUBE_ID,
        internal: {
            contentDigest: createContentDigest(POW_TUBE_ID),
            type: "powTubeOemBed"
        }
    })
}

exports.sourceNodes = async (params) => {
    await Promise.all([bakeOneNodeGetOneVideo(params)]);
}
...oembedVideo,

Happy Birthday POW!

Habby-B-Day-POW! 1-kopi

Happy Birthday POW!

Your gift is a shiny new ....

Habby-B-Day-POW! 1-kopi

Crew Mate!

Captain Ola has been recruiting in stealth mode for 47 days.

Habby-B-Day-POW!-2-kopi

Every morning Captain Ola has been building in public, coding on the new POW! website. BUT after lunch ....

Firstly Captain Ola asked himself "Self, who is your Number 1 Favourite Crew Mate?

Captain Ola wrote a Top 10 List.

Habby-B-Day-POW!-3-kopi

Secondly, Captain Ola started interviewing from the top of his Top 10 List. Number 1: Ola's old friend from summer camp deep in the backwoods of upstate New York, back in 1993. A soft spoken Dev with rock solid UX skills.

Habby-B-Day-POW!-4-kopi

Half way into that first interview Captain Ola just KNEW "Jed Wood IS the man I want in my crew on this Life-Long Treasure Hunt of building POW! into a useful tool for devs who also happen to menstruate."

Thirdly, after 3 interviews Jed Wood finally said "yes" to join our POW! crew.

Question 1 to self: Self, how crazy is it to add ANOTHER Dev to a two-dev team?! On a scale from 1-to-11?

Answer: 11 maybe... Madness

Question 2 to self: Madness? MADNESS?! This. Is. POW!

Fourthly, we need users of menstrual cycle tracker apps to do user interviews with. We need BETA testers. Please join our 33 BETA testers by sending an email to Queen Benedicte Raae at [email protected] or send a DM on twitter to Queen Benedicte @raae

Fifthly, Captain Ola must get back to writing another Top 10 List. Our POW! Crew needs a marketer! Right?! POW! needs a Crew Mate who will become our expert on women's health so we can give you all som super content filled with tips and tricks and deep dives into women's health.

Can tags be the backbone of navigation in Lillian's webapp?

OlaCast:
–Skill Builder Sunday for dev-daughters and dev-dads (and no dev-Queens allowed, just kidding)
–Can tags be the backbone of navigation in Lillian's webapp?

My tags are NOT creating pages in build. What to do to find the bug?

  1. async await says Queen Raae -> no, doesn't look like that is the problem
  2. fix: defer: index + 1 > 14, not 2 -> no, didn't fix it #37
  3. sanity deploy, https://lillian.sanity.studio/, but is netlify seeing this?

Look like 2. was a fix, in a way

Onward

fix: same in gatsby-ssr.js as gatsby-browser

// gatsby-ssr.js
import React from 'react';
import Layout from './src/components/Layout';

export function wrapPageElement({ element, props }) {
  return <Layout {...props}>{element}</Layout>;
}

that didn't help

Pass tool tag to the photos.js page to get a list of tool-tags

Deep Dives

// 1.2.3 – A.B.C. – Gingerbread house
// 0. gatsbyUtils πŸ”§
// 1. filter β˜•
// 2. bakingSong 🎡 🦒
// 3. aromaNode πŸ°πŸ’°

// A. aromaNodePath 🍰.πŸ“.πŸ›
// B. bakingSong 🎡 πŸ™€
// C. catsbyId πŸ˜ΌπŸ†”
exports.createPages = async (gatsbyUtils) => {
  bakeMarkdownNodesIntoPages(gatsbyUtils);
};
async function bakeMarkdownNodesIntoPages({ graphql, actions }) {

};
  const { data } = await graphql(`
    {
      supplies: allMarkdownRemark(
        filter: { fileAbsolutePath: { regex: "/index.md/" } }
      ) {
        nodes {
          id
          fields {
            slug
          }
        }
      }
    }
  `);
  console.log(data.supplies.nodes);
  const bakingSong = require.resolve("./src/templates/pageTemplate.js");
  // Loop over the supplies.nodes and 
  // forEach((aromaNode 
  // bake a page
  data.supplies.nodes.forEach((aromaNode) => {
    console.log(aromaNode.fields.slug, "πŸ’€πŸ“„");

    actions.createPage({
      // A. aromaNodePath 🍰.πŸ“.πŸ›

    });
  });
    const aromaNodePath =
      aromaNode.fields.slug === "/index/" ? "/" : aromaNode.fields.slug;



    });
      path: aromaNode.fields.slug,
      component: bakingSong,
      context: {
        catsbyId: aromaNode.id,
      },

Full gatsby-node.js code

Full gatsby-node.js code

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

async function slugifyMarkdownRemarkNode({ actions, node, getNode }) {
  const { createNodeField } = actions;
  if (node.internal.type === "MarkdownRemark") {
    const slug = createFilePath({ node, getNode });
    createNodeField({
      name: "slug",
      node,
      value: slug,
    });
  }
}

// POW!-website/gatsby-node.js

// 1.2.3 – A.B.C. – Gingerbread house
// 0. gatsbyUtils πŸ”§
async function bakeMarkdownNodesIntoPages({ graphql, actions }) {
  // 1. filter β˜• first
  const { data } = await graphql(`
    {
      supplies: allMarkdownRemark(
        filter: { fileAbsolutePath: { regex: "/index.md/" } }
      ) {
        nodes {
          id
          fileAbsolutePath
          fields {
            slug
          }
        }
      }
    }
  `);
  // 2. bakingSong 🎡 🦒
  const bakingSong = require.resolve("./src/templates/pageTemplate.js");
  // 3. aromaNode πŸ°πŸ’°
  // Loop over the supplies.nodes and
  // forEach((aromaNode
  // bake a page
  // I forgot the supplies
  data.supplies.nodes.forEach((aromaNode) => {
    console.log(aromaNode.fields.slug, "πŸ’€πŸ“„");
    const aromaNodePath =
      aromaNode.fields.slug === "/index/" ? "/" : aromaNode.fields.slug;
    actions.createPage({
      // A. aromaNodePath 🍰.πŸ“.πŸ›
      path: aromaNodePath,
      // B. bakingSong 🎡 πŸ™€
      component: bakingSong,
      // C. catsbyId πŸ˜ΌπŸ†”
      context: {
        catsbyId: aromaNode.id,
      },
    });
  });
}

exports.onCreateNode = async (gatsbyUtils) => {
  slugifyMarkdownRemarkNode(gatsbyUtils);
};

exports.createPages = async (gatsbyUtils) => {
  await bakeMarkdownNodesIntoPages(gatsbyUtils);
};
import React from "react";
import { graphql, Link } from "gatsby";

export default function PageTemplate({ data = {} }) {
  const { frontmatter, html } = data.markdownRemark || {};
  const { title, sections } = frontmatter || {};
  return (
    <>
      <div className="container">
        <h1>{title}</h1>
        <div dangerouslySetInnerHTML={{ __html: html }} />
        {(sections || []).map((section) => {
          const { title } = section || {};
          const { html } = section.body.childMarkdownRemark || {};
          const { path, label } = section.cta || {};
          return (
            <section>
              {title && <h2>{title}</h2>}
              {html && <div dangerouslySetInnerHTML={{ __html: html }} />}
              {path && label && <Link to={path}>{label}</Link>}
            </section>
          );
        })}
      </div>
    </>
  );
}

export const query = graphql`
  query($catsbyId: String) {
    markdownRemark(id: { eq: $catsbyId }) {
      html
      frontmatter {
        title
        sections {
          title
          body {
            childMarkdownRemark {
              html
            }
          }
          cta {
            path
            label
          }
        }
      }
    }
  }
`;

G.i.G.G.L.E.S OlaCast 13

OlaCast: Sunday Skill-Builder Sessions

Who:

Cap'n Ola Β· @OlaHolstVea
Tom Erik StΓΈwer Β· Ghostly Guest and Data Dev Dad Β·testower

What:

We create 1 node with the id from 1 youtube video,

Why:

To prepare for sourcing only our favourite videos from youtube. Because youtube is NOT a safe tool for Lillian (7 πŸ΄β€β˜ οΈπŸ‘Έ) and her skill-builder friends.

How:

G.i. of G.i.G.G.L.E.S.

G. Get data later, create node now
i. = I a.c.t.i.o.n.s

Let's G.i. Go πŸ“Ί !

G. Get data later, create node now

exports.sourceNodes = async (params) => {
  // Get 1 video ready to be sourced into our GraphQL-Gatsby-data river without sinking
  await Promise.all([bakeOneNodeGetOneVideo(params)]);
}
async function bakeOneNodeGetOneVideo() {

}

I. id

  const POW_TUBE_ID = "UGq8cnNTbwI"
  const nodeID = {
    id: POW_TUBE_ID,
  }
  console.log('β›΅πŸ’€ Yo-Ho Yo-Ho a PiRATEs nodeID πŸ’°', nodeID);

a. actions

  actions.createNode({

c. contentDigest

      contentDigest: createContentDigest(),

t. type

      type: "powTubeOemBed"
         i. internal, because it is NOT polite to have `contentDigest` and `type` under `id`
    internal: {

o. (POW_TUBE_ID)

POW_TUBE_ID

n. node

Go look at our node in GraphiQL

s. Singing

Show drawing of Woolly Goatsby singing

Here is a screenshot of the video I am using the id from and which I will be sourcing some other Sunday
OlaCast-13- Sid and Giggles-24

The POW code on Github:
https://github.com/olavea/POW/

Sign up for the newsletter:

The original POW website:
https://www.usepow.com/

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.