{
    "componentChunkName": "component---src-pages-index-js",
    "path": "/",
    "result": {"data":{"site":{"siteMetadata":{"title":"Danniel Hansel","description":"Hi, I'm Danniel Hansel. I'm a Software Engineer based in Dallas, Texas. I write blogs about my thoughts, life experiences, solving problems as well as all technology related things.","canonicalUrl":"https://dannielhansel.com","image":"images/logo.svg","author":{"name":"Danniel Hansel"},"organization":{"name":"Danniel Hansel Tech LLC","url":"https://dannielhansel.com","logo":"images/logo.svg"},"social":{"twitter":"@dehanz13"}}},"hero":{"edges":[{"node":{"body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"intro\": \"Hi, my name is\",\n  \"title\": \"Danniel Hansel\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `I’m a full-stack software engineer based in Dallas Texas.`));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"intro":"Hi, my name is","title":"Danniel Hansel"}}}]},"about":{"edges":[{"node":{"slug":"about/about","body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"title\": \"About Me\",\n  \"category\": \"short-bio\",\n  \"author\": \"Danniel Hansel\",\n  \"caption\": \"Dallas, Texas\",\n  \"description\": \"Learn about Danniel Hansel and what he does\",\n  \"profileUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1639887422/dannielhansel.com/danniel-headshot-webp-4_xb4nbr.webp\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `I am Danniel Hansel, a frontend software engineer and freelance full-stack developer with an intense passion for software engineering, particularly in the world of architecture, functional development and enhancing developer productivity & user experience.`), mdx(\"p\", null, `My obsession with learning about the latest and greatest, as well as collaborating with others, provide me with more options when building solutions to solve real-world problems. Whether that'd be language, pattern, process, or technologies.`), mdx(\"p\", null, `Lately? I've been building web applications using React, developing infrastructure tooling, and architecting elegant client-side & server-side solutions. I fell in love with and have been primarily using React in web applicatons. For static sites, I love using Gatsby for creating blazing fast, SEO-driven headless frontend user interfaces.`), mdx(\"p\", null, `Whether you're a business owner looking to get started on a app or web development project with a freelance web developer, a developer looking to collaborate on something cool, or just wanting to say hi, shoot me a message and let's work together.`));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"title":"About Me","caption":"Dallas, Texas","description":"Learn about Danniel Hansel and what he does","author":"Danniel Hansel","profileUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639887422/dannielhansel.com/danniel-headshot-webp-4_xb4nbr.webp","category":"short-bio"}}}]},"testimonial":{"edges":[{"node":{"body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"title\": \"Testimonial 1\",\n  \"thumbnailUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1639922323/dannielhansel.com/content/testimonial/maggie-webp_eoinzi.webp\",\n  \"author\": \"Maggie\",\n  \"company\": \"Crab Station\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `Danniel is quick to iterate on feedback and has a knack for understanding the genre you expect in design. I would highly recommend him to anyone who is looking to build a great website.`));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"title":"Testimonial 1","author":"Maggie","company":"Crab Station","thumbnailUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639922323/dannielhansel.com/content/testimonial/maggie-webp_eoinzi.webp"}}}]},"project":{"edges":[{"node":{"body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"title\": \"The Crab Station & Oyster Bar\",\n  \"category\": \"Featured Project\",\n  \"thumbnailUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1639921559/dannielhansel.com/content/project/crabs-webp_sl5o0q.webp\",\n  \"github\": \"https://github.com/dehanz13\",\n  \"external\": \"https://crabstationodessatexas.com/\",\n  \"tags\": [\"React\", \"GatsbyJS\", \"Bootstrap\", \"Contentful\", \"Netlify\", \"AWS\"],\n  \"visible\": \"true\",\n  \"position\": 1,\n  \"live\": \"true\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `A Seafood Restaurant web application with online order feature designed to help client increase sales and traffic.`));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"title":"The Crab Station & Oyster Bar","visible":"true","tags":["React","GatsbyJS","Bootstrap","Contentful","Netlify","AWS"],"position":1,"live":"true","github":"https://github.com/dehanz13","external":"https://crabstationodessatexas.com/","category":"Featured Project","thumbnailUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639921559/dannielhansel.com/content/project/crabs-webp_sl5o0q.webp"}}},{"node":{"body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"title\": \"Smart POS Web App\",\n  \"category\": \"Featured Project\",\n  \"thumbnailUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1639921559/dannielhansel.com/content/project/admin-dash-webp_o5f6oq.webp\",\n  \"github\": \"https://github.com/d-m-enterprise/pos-webapp\",\n  \"external\": \"https://nextjs-pos-webapp.vercel.app/\",\n  \"tags\": [\"React\", \"NextJS\", \"Tailwind\", \"Firebase\", \"Firestore\", \"NodeJS\", \"OpenShift\"],\n  \"visible\": \"true\",\n  \"position\": 2,\n  \"live\": \"false\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `A Point-of-Sale system to match your business needs. Comes with admin dashboard, employee management, kitchen management, product management & menu building, online ordering and mobile ordering (for dine-ins). (Currently in-progress)`));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"title":"Smart POS Web App","visible":"true","tags":["React","NextJS","Tailwind","Firebase","Firestore","NodeJS","OpenShift"],"position":2,"live":"false","github":"https://github.com/d-m-enterprise/pos-webapp","external":"https://nextjs-pos-webapp.vercel.app/","category":"Featured Project","thumbnailUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639921559/dannielhansel.com/content/project/admin-dash-webp_o5f6oq.webp"}}},{"node":{"body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"title\": \"E-Commerce Web App\",\n  \"category\": \"Featured Project\",\n  \"thumbnailUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1639921560/dannielhansel.com/content/project/ecommerce-webp_effebd.webp\",\n  \"github\": \"https://github.com/dehanz13/react-mui-ecommerce\",\n  \"external\": \"https://dannielstore.netlify.app/\",\n  \"tags\": [\"React\", \"Material UI\", \"Commerce.js\", \"Stripe\"],\n  \"visible\": \"true\",\n  \"position\": 3,\n  \"live\": \"false\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `An E-Commerce store that lets users purchase clothing products with a payment gateway integrated.`));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"title":"E-Commerce Web App","visible":"true","tags":["React","Material UI","Commerce.js","Stripe"],"position":3,"live":"false","github":"https://github.com/dehanz13/react-mui-ecommerce","external":"https://dannielstore.netlify.app/","category":"Featured Project","thumbnailUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639921560/dannielhansel.com/content/project/ecommerce-webp_effebd.webp"}}}]},"featured":{"edges":[{"node":{"id":"6f5b7bcc-efa4-5084-8b34-cec1b0506f16","fields":{"slug":"/blog/my-favorite-tech-podcasts/"},"frontmatter":{"date":"January 15, 2022","title":"My Favorite Tech Podcasts","description":"I've compiled a list of my favorite tech and non-tech podcasts."},"excerpt":"Over the last years, I’ve been listening to podcasts more often than before. Typically, I’ll put on an episode when I’m driving by myself…","body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"slug\": \"my-favorite-tech-podcasts\",\n  \"title\": \"My Favorite Tech Podcasts\",\n  \"date\": \"2022-01-15\",\n  \"author\": \"Danniel Hansel\",\n  \"description\": \"I've compiled a list of my favorite tech and non-tech podcasts.\",\n  \"published\": true,\n  \"featured\": true,\n  \"categories\": [\"productivity\"],\n  \"tags\": [\"personal\", \"productivity\"],\n  \"bannerUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1644037050/dannielhansel.com/content/blog/my-favorite-podcasts_ksnqce.jpg\",\n  \"bannerCredit\": \"Photo by [Mohammad Metri](https://unsplash.com/photos/1oKxSKSOowE) on [Unsplash](https://unsplash.com)\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `Over the last years, I’ve been listening to podcasts more often than before. Typically, I’ll put on an episode when I’m driving by myself, having morning shower, or just doing daily chores. The selection on which I’m choosing is based a lot of things like my mood, or things that I’m really interested in learning.`), mdx(\"p\", null, `My intention most of the time is to learn new things and trends in software development. Other times, well besides going deeper into a specific subject, it’s usually just for pure entertainment. I was asked by a few friends on what podcasts I listen to the most. So, here I am sharing it with you all. Enjoy! 🎉`), mdx(\"p\", null, `If you’d like to suggest me your favorite podcasts or episodes, I would love to `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/contact/\"\n  }, `hear about it`), `!`), mdx(\"h2\", null, `Tech Podcasts`), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://softwareengineeringdaily.com/\"\n  }, `Software Daily`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://reactpodcast.simplecast.com/\"\n  }, `React Podcast`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://reactnativeradio.com/\"\n  }, `React Native Radio`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://developertea.com/\"\n  }, `Developer Tea`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://syntax.fm/\"\n  }, `Syntax.fm`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://shoptalk.com/\"\n  }, `ShopTalk`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://www.frontendhappyhour.com/\"\n  }, `Front End Happy Hour`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://fullstackradio.com/\"\n  }, `Full Stack Radio`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://javascriptjabber.com/\"\n  }, `JavaScript Jabber`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://www.bikeshed.fm/\"\n  }, `The Bike Shed`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://scrimba.com/podcast/\"\n  }, `The Scrimba Podcast`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://www.arresteddevops.com/\"\n  }, `Arrested DevOps`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://www.softwaredefinedtalk.com/\"\n  }, `Software Defined Talk`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://softskills.audio/\"\n  }, `Soft Skills Engineering`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://kentcdodds.com/chats/04\"\n  }, `Chats with Kent C. Dodds`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://open.spotify.com/show/50scOU4lU3jX4TGxoSUAK6\"\n  }, `3 Minutes with Kent`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://kentcdodds.com/calls\"\n  }, `Call Kent C. Dodds`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://open.spotify.com/show/3vjuOCwZ7kfUgm80xSpZmK\"\n  }, `Epic React Podcast`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://www.npr.org/podcasts/510311/embedded\"\n  }, `Embedded`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://open.spotify.com/show/4FKWy0vjNbt6uFwAzwd7XF\"\n  }, `egghead.io developer chats`))), mdx(\"h2\", null, `Non-Tech Podcasts`), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://www.npr.org/sections/money/\"\n  }, `Planet Money`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://www.biggerpockets.com/podcast\"\n  }, `Bigger Pockets`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://open.spotify.com/show/7qZAVw03FuurfYnWIWwkHY\"\n  }, `Naval`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://open.spotify.com/show/6SZVsPIxPfVs6aavqM1peY\"\n  }, `Gary Vaynerchuk`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://impacttheory.com/episodes/\"\n  }, `Impact Theory`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://open.spotify.com/show/6fZXOzehJ9JtOyFjirF3qt\"\n  }, `Tony Robbins`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://mixergy.com/\"\n  }, `Startup Stories - Mixergy`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://hbr.org/2018/01/podcast-ideacast\"\n  }, `HBR IdeaCast`)), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://gimletmedia.com/shows/reply-all\"\n  }, `Reply-All`))));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":1}},{"node":{"id":"b86814e4-5866-5e31-91ff-d0a8b9ea363b","fields":{"slug":"/blog/handling-external-links-for-mdx-files-in-gatsby/"},"frontmatter":{"date":"December 10, 2021","title":"Handling External Links for MDX files in Gatsby","description":"The easiest way to open links in a new tab when using gatsby-plugin-mdx."},"excerpt":"Typically, when you’re writing markdown files, you’d sometimes want to include a link that takes the user from your current page to some…","body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"slug\": \"handling-external-links-for-mdx-files-in-gatsby\",\n  \"title\": \"Handling External Links for MDX files in Gatsby\",\n  \"date\": \"2021-12-10\",\n  \"author\": \"Danniel Hansel\",\n  \"description\": \"The easiest way to open links in a new tab when using gatsby-plugin-mdx.\",\n  \"published\": true,\n  \"featured\": true,\n  \"categories\": [\"web-development\"],\n  \"tags\": [\"ssg\", \"react\", \"gatsby\"],\n  \"bannerUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1640453751/dannielhansel.com/content/blog/external-link_roctbf.webp\",\n  \"bannerCredit\": \"Photo by [Eric Mclean](https://unsplash.com/photos/sxiSod0tyYQ) on [Unsplash](https://unsplash.com)\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `Typically, when you’re writing markdown files, you’d sometimes want to include a link that takes the user from your current page to some other page. Sometimes, these links can be internal (i.e. redirects user to a page on your site) or external (i.e. `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.twitter.com\"\n  }, `https://www.twitter.com`), `). What is the best way to set this up globally so that you don’t have to manually configure it on every markdown files?`), mdx(\"h2\", null, `Option #1: Creating the Link component`), mdx(\"p\", null, `This component basically checks if the link is prefixed with your site’s url or “/”. Then decides if it should open in a new tab or not:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `const ExternalLink = props => {\n  if (\n    props.href.includes(\"https://dannielhansel.com/\") ||\n    props.href[0] === \"/\"\n  ) {\n    return (\n      <a {...props} href={props.href}>\n        {props.children}\n      </a>\n    )\n  }\n  return (\n    <a {...props} href={props.href} target=\"_blank\" rel=\"noopener noreferrer\">\n      {props.children}\n    </a>\n  )\n}\n`)), mdx(\"h2\", null, `Pass the component object into MDXProvider`), mdx(\"p\", null, `Then, you can pass it into the MDXProvider so every markdown link syntax can be controlled:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `const components = {\n    a: ExternalLink,\n}\n\nconst ExampleLayout = ({children}) => (\n    <>\n        <MDXProvider components={components}>\n            <MDXRenderer>{body}</MDXRenderer>\n        </MDXProvider>\n    <>\n)\n`)), mdx(\"h2\", null, `Option #2: Using DRY principle`), mdx(\"p\", null, `Another way is to create a reusable component and just import it whenever you need it. You can also use this outside of your markdown files (i.e. your social links on your site).`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// inside /src/components/link.js\nimport * as React from \"react\"\nimport { Link as GatsbyLink } from \"gatsby\"\n\n// Since DOM elements <a> cannot receive activeClassName\n// and partiallyActive, destructure the prop here and\n// pass it only to GatsbyLink\nconst Link = ({ children, to, activeClassName, partiallyActive, ...other }) => {\n  // Tailor the following test to your environment.\n  // This regex assumes that any internal link (intended for Gatsby)\n  // will start with exactly one slash, and that anything else is external.\n  const internal = /^\\\\/(?!\\\\/)/.test(to)\n\n  // Use Gatsby Link for internal links, and <a> for others\n  if (internal) {\n    return (\n      <GatsbyLink\n        to={to}\n        activeClassName={activeClassName}\n        partiallyActive={partiallyActive}\n        {...other}\n      >\n        {children}\n      </GatsbyLink>\n    )\n  }\n\n  return (\n    <a href={to} {...other} target=\"_blank\" rel=\"noopener noreferrer\">\n      {children}\n    </a>\n  )\n}\n\nexport default Link\n`)), mdx(\"p\", null, `Then you can import this component in your markdown file just like a regular javascript file.`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// inside /content/handling-external-links-for-mdx-files-in-gatsby.mdx\n\nimport Link from \"../../src/components/link\"\n\n// ---\n// ... frontmatter stuff\n// ---\n;<Link to=\"https://twitter.com\">Twitter</Link>\n`)), mdx(\"h2\", null, `Option #3: Use the component as shortcode`), mdx(\"p\", null, `Another way is to kind of combine option 1 and 2, or known as “shortcode”. It’s basically a component that is available in every markdown file without you having to import it every time.`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `import Link from '../components/link'\n\nconst components = {\n    Link: ({children, to, ...props}) => (\n        <Link to={href} {...props}>\n            {children}\n        </Link>\n    ),\n}\n\nconst ExampleLayout = ({children}) => (\n    <>\n        <MDXProvider components={components}>\n            <MDXRenderer>{body}</MDXRenderer>\n        </MDXProvider>\n    <>\n)\n`)), mdx(\"p\", null, `Then in your markdown file:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// inside /content/handling-external-links-for-mdx-files-in-gatsby.mdx\n\n// ---\n// ... frontmatter stuff\n// ---\n\n<Link to=\"https://twitter.com\">Twitter</Link>\n`)), mdx(\"h2\", null, `Recap:`), mdx(\"p\", null, `Here’s what your Post template would look like:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// in your templates/post.js\n\nconst ExternalLink = props => {\n  if (\n    props.href.includes(\"https://dannielhansel.com/\") ||\n    props.href[0] === \"/\"\n  ) {\n    return (\n      <a\n        {...props}\n        href={props.href}\n        className=\"font-semibold text-accent hover:underline hover:underline-offset-4 cursor-pointer\"\n      >\n        {props.children}\n      </a>\n    )\n  }\n  return (\n    <a\n      {...props}\n      href={props.href}\n      className=\"font-semibold text-accent hover:underline hover:underline-offset-4 cursor-pointer\"\n      target=\"_blank\"\n      rel=\"noopener noreferrer\"\n    >\n      {props.children}\n    </a>\n  )\n}\n\nconst components = {\n    // other components ...\n    a: ExternalLink,\n}\n\nconst BlogPostTemplate = ({children}) => {\n    const { frontmatter, body, timeToRead, excerpt, fields } = data.mdx\n    return (\n        <>\n            <MDXProvider components={components}>\n                <MDXRenderer>{body}</MDXRenderer>\n            </MDXProvider>\n        <>\n    )\n}\n\nexport const pageQuery = graphql\\`\n  query BlogPostQuery($id: String) {\n\n    mdx(id: { eq: $id }) {\n      id\n      excerpt(pruneLength: 160)\n      body\n      timeToRead\n      fields {\n        slug\n      }\n      frontmatter {\n        slug\n        title\n        author\n        tags\n        description\n        date(formatString: \"Do MMM YYYY\")\n      }\n    }\n  }\n\\`\nexport default blogPost\n`)));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":1}},{"node":{"id":"f5e43818-6b9e-539f-b958-b022a7c84719","fields":{"slug":"/blog/image-types-vector-vs-pixel/"},"frontmatter":{"date":"December 03, 2021","title":"Image types: Vector vs. Pixel","description":"Why you should go for Vector vs. Pixel."},"excerpt":"When choosing images for a logo or any design on a project, most people typically just go with pixel based images since they appear as more…","body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"slug\": \"image-types-vector-vs-pixel\",\n  \"title\": \"Image types: Vector vs. Pixel\",\n  \"date\": \"2021-12-03\",\n  \"author\": \"Danniel Hansel\",\n  \"description\": \"Why you should go for Vector vs. Pixel.\",\n  \"published\": true,\n  \"featured\": true,\n  \"categories\": [\"image-optimization\"],\n  \"tags\": [\"performance\"],\n  \"bannerUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1644037300/dannielhansel.com/content/blog/pixal-vs-vector_dkaxg1.jpg\",\n  \"bannerCredit\": \"Photo by [Umberto](https://unsplash.com/photos/deb2EnbWPr8) on [Unsplash](https://unsplash.com)\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `When choosing images for a logo or any design on a project, most people typically just go with pixel based images since they appear as more “Photogenic”. But actually, there are some major differences that most people miss.`), mdx(\"p\", null, `If you plan on designing any digital artwork, it’s important to understand the difference between the 2 types: Pixel/Raster images and Vector images.`), mdx(\"h1\", null, `Pixel and Raster Images`), mdx(\"h2\", null, `Pixel`), mdx(\"p\", null, `The idea of pixel was to create a photograph using a grid-based system of colors and tones. These are called “picture elements”, which are the building blocks of all digital artwork, simple or complex. Pixels on monitors are collections of Red, Green and Blue points of light, combined with Brightnesses to create what is called “RGB” color model.`), mdx(\"h2\", null, `Raster`), mdx(\"p\", null, `Similarly, Raster/rasterization is the process of turning non-pixel based image into a digital pixel-based image. When comparing pixels to vetor graphics, we are talking exclusively about raster graphic pixels, not the pixels that your monitor displays.`), mdx(\"p\", null, `Pixel-based images are also called Bitmaps and they’re made up of thousands of itty-bitty pixels or dots. Each pixel/block can store a different color and the overall pattern makes up the image on your screen. That’s why sometimes when we try to enlarge a photo, it gets blurry. And these are the usual .JPEGs, .GIFs, .PNGs files that we normally use.`), mdx(\"h1\", null, `Vector Images`), mdx(\"p\", null, `Vector images on the other hand, are basically paths/objects created by math calculations. The points (primitives) that these vectors make are a combination of lines, curves, and polygons on an algebraic grid. They operate independently of image resolution as they can be stretched and blown up without losing qualty.`), mdx(\"p\", null, `Simple logos, icons, typography and cartoons/illustrations usually are best in Vector because they have a lot less information and they load a whole lot faster. When you have a pixel-based image, you can convert them into Vector by using tools like Photoshop, Adobe Illustrator, and many more. These are exported as .SVGs, .AIs, .PDFs, and .EPS.`), mdx(\"h1\", null, `Conclusion`), mdx(\"p\", null, `The important distinction here is that pixels exist in the more literal space whereas vectors exists in a mathematical space. Pixels are all equal size and have a predefined position (just try to zoom in on one and you’ll see that those blocks will start to show), and Vectors exists as points on the math grid and doesn’t have any limitation (try to zoom in on a vector image and you’ll notice that the image and colors don’t change as it gets enlarged.)`));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":2}},{"node":{"id":"b15e2892-c0b8-5bbc-966d-3bfb10cac6c2","fields":{"slug":"/blog/fetching-data-from-firestore/"},"frontmatter":{"date":"November 08, 2021","title":"Fetching data from Firestore","description":"This quick guide shows you how to create a React custom hook to fetch data from Cloud Firestore."},"excerpt":"This quick guide shows you how to fetch data from Cloud Firestore. Assuming you already have a collection with a list of documents. Note…","body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"slug\": \"fetching-data-from-firestore\",\n  \"title\": \"Fetching data from Firestore\",\n  \"date\": \"2021-11-08\",\n  \"author\": \"Danniel Hansel\",\n  \"description\": \"This quick guide shows you how to create a React custom hook to fetch data from Cloud Firestore.\",\n  \"published\": true,\n  \"featured\": true,\n  \"categories\": [\"database\"],\n  \"tags\": [\"react\", \"ssr\", \"database\", \"nextjs\", \"database\"],\n  \"bannerUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602322/dannielhansel.com/content/blog/fetching-data-from-firestore_zalbof.jpg\",\n  \"bannerCredit\": \"Photo by [Tobias Fischer](https://unsplash.com/photos/PkbZahEG2Ng) on [Unsplash](https://unsplash.com)\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `This quick guide shows you how to fetch data from Cloud Firestore. Assuming you already have a collection with a list of documents.`), mdx(\"p\", null, `Note: This guide will use Web version 9 (modular) - which is the latest version.`), mdx(\"h1\", null, `What we are going to do in this tutorial:`), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, `Understand how Event Sourcing & Event Streams work.`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, `Understand how Snapshots work.`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, `Create a React custom hook which listens to events from Firestore Database.`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, `Render our data in our component.`)), mdx(\"p\", null, `If you don't have a project set up yet on Firebase, I have this `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/blog/initial-setup-for-cloud-firestore-database/\"\n  }, `quick guide`), ` to help you set it up.`), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, `💡 Once we've initialized our Firestore database, we will need it here.`)), mdx(\"h1\", null, `Event Sourcing & Streams`), mdx(\"p\", null, `In Event Sourcing, you'll typically replay all the events from the beginning of time from an Event Stream to get to the `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `current state`), ` of your aggregate. In most occasions, you'll have a `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `lifecycle`), ` to the stream that will eventually end but you could also have a stream that is never ending, something like products in a warehouse. The problem is what if we have thousands or millions of events that need to be replayed? This will create a very inefficient, time-consuming and slow process 😐 . This is where Snapshots come in.`), mdx(\"h1\", null, `Snapshots`), mdx(\"p\", null, `A snapshot is a representation of state for your aggregate at a particular point in time or event. To `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://firebase.google.com/docs/firestore/query-data/listen\"\n  }, `get realtime updates`), ` with our Cloud Firestore database, we will need an `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `onSnapshot()`), ` method which listens to a document. When you provide a callback in the initial call, it creates a document snapshot immediately with the current contents of the single document. Then, each time the contents change, another call updates the document snapshot. To listen to multiple documents in a collection, this method will listen to the results of a query which then creates a query snapshot.`), mdx(\"h1\", null, `React Custom Hook`), mdx(\"p\", null, `In order fetch and render the most updated data from our Firestore Database onto our UI, we will need to create a custom hook. This hook's job is to listen to events from our database, record the state of the aggregate and store the state. By using `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `onSnapshot()`), ` method, it attaches a listener for `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `QuerySnapshot`), ` events in our Firebase. Note that although streams are never ending, this listener can be cancelled by calling the function that is returned when `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `onShapshot()`), ` is called.`), mdx(\"h2\", null, `Explanation`), mdx(\"p\", null, `We will store the snapshot in an array using the `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `useState hook`), `. To be able to detect changes, we will use the `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `useEffect hook`), ` with our collection as dependency so that every document change in our collection gets hooked and stored in our state. The job of `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `collection()`), ` method here is to get the `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `CollectionReference`), ` instance that refers to the collection at the specified absolute path and returns the `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `CollectionReference`), ` instance.`), mdx(\"h2\", null, `Code`), mdx(\"p\", null, `Create a folder `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `\"hooks\"`), ` inside src and create a file `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `\"useFirestore.js\"`), `:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `mkdir root/src/hooks\ntouch root/src/hooks/useFirestore.js\n`)), mdx(\"p\", null, `Stick this code in it:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `import { useEffect, useState } from \"react\" // import the React hooks\nimport { onSnapshot, collection } from \"firebase/firestore\" // import the methods from firestore\nimport { firestoreDb } from \"../config/firebase\" // The reference to our Firestore database after we've initialized it.\n\nexport const useFirestore = col => {\n  const [docs, setDocs] = useState([])\n\n  useEffect(\n    () =>\n      onSnapshot(collection(firestoreDb, col), snapshot =>\n        setDocs(snapshot.docs.map(doc => ({ ...doc.data(), id: doc.id })))\n      ),\n    [col]\n  )\n\n  return { docs }\n}\n`)), mdx(\"h1\", null, `Render your data`), mdx(\"p\", null, `Create a file \"`, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `Products.js`), `\" inside `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `src/components`), `.`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `touch src/components/Products.js\n`)), mdx(\"p\", null, `Then, copy this code in it:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `import { useFirestore } from \"../hooks/useFirestore\" // Our hook we just created\n\nconst Products = () => {\n  const { docs } = useFirestore(\"your-collection-name\") // Our hook takes in the collectionName as parameter\"\n\n  return (\n    <div>\n      // ... add your own styling here\n      <ul>\n        {docs.map((product, index) => {\n          return (\n            <li key={index} className=\"flex my-2\">\n              <p>{index + 1}</p>\n              <h1>{product.Name}</h1> // Grab the keys from your document fields\n              <p>{product.Description}</p>\n              <p>\\${product.Price}</p>\n            </li>\n          )\n        })}\n      </ul>\n    </div>\n  )\n}\nexport default Products\n`)), mdx(\"p\", null, `Lets go ahead and run the app:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `npm run dev\n`)), mdx(\"p\", null, `Voila! We can now fetch our data from Cloud Firestore database. 👏`), mdx(\"p\", null, `While there is another option to fetch data from Firebase (like `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.npmjs.com/package/react-firebase-hooks\"\n  }, `react-firebase-hooks`), `), I chose to create my own customized hook that is understandable to me and works for me.`), mdx(\"p\", null, `If you are interested to learn more on how to sort & update the data from Firestore or how to store & delete images from Firebase Storage, check out my other blog posts. Good luck!`));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":2}},{"node":{"id":"607bdcda-0d6c-5f06-9a34-7c59aca6989d","fields":{"slug":"/blog/initial-setup-for-cloud-firestore-database/"},"frontmatter":{"date":"November 01, 2021","title":"Initial setup for Cloud Firestore database","description":"This quick guide shows you how to set up Cloud Firestore for your React application."},"excerpt":"This quick guide shows you how to set up Cloud Firestore for your application. Note: This guide will use Web version 9 (modular) - which is…","body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"slug\": \"initial-setup-for-cloud-firestore-database\",\n  \"title\": \"Initial setup for Cloud Firestore database\",\n  \"date\": \"2021-11-01\",\n  \"author\": \"Danniel Hansel\",\n  \"description\": \"This quick guide shows you how to set up Cloud Firestore for your React application.\",\n  \"published\": true,\n  \"featured\": true,\n  \"categories\": [\"react\"],\n  \"tags\": [\"react\", \"ssr\", \"backend\", \"nextjs\", \"database\"],\n  \"bannerUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602371/dannielhansel.com/content/blog/initial-setup-for-cloud-firestore-database_p8rflb.jpg\",\n  \"bannerCredit\": \"Photo by [Jan Antonin Kolar](https://unsplash.com/photos/lRoX0shwjUQ) on [Unsplash](https://unsplash.com)\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `This quick guide shows you how to set up Cloud Firestore for your application.`), mdx(\"p\", null, `Note: This guide will use Web version 9 (modular) - which is the latest version.`), mdx(\"h1\", null, `Create a project in Firebase`), mdx(\"p\", null, `If you haven't already, `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://firebase.google.com/docs/web/setup\"\n  }, `create a Firebase project and register your app`), ` with that project in the `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://console.firebase.google.com/u/0/\"\n  }, `Firebase Console`), `.`), mdx(\"p\", null, `Once you have your project set up, you'll get a `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `Firebase configuration object`), ` that you'll need to connect your app to your firebase project resources. Head over to the project settings and look for the SDK setup and configuration.`), mdx(\"h1\", null, `Install SDK & initialize Firestore Database`), mdx(\"p\", null, `In your terminal, `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `install the SDK`), ` (you can use npm or yarn):`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `npm install firebase\n// or if you use yarn:\nyarn add firebase\n`)), mdx(\"p\", null, `Then, `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `initialize Firebase`), `:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// create a new folder inside src called \"config\"\nmkdir root/src/config\n// create a file called \"firebase.js\"\ntouch root/src/config/firebase.js\n`)), mdx(\"p\", null, `Then stick this in it:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// You'll need to import these methods from Firebase and Cloud Firestore.\nimport { initializeApp } from \"firebase/app\"\nimport { getFirestore } from \"firebase/firestore\"\n\n// Initialize your app's Firebase configuration.\nconst app = initializeApp({\n  projectId: process.env.PROJECT_ID,\n  apiKey: process.env.API_KEY,\n  authDomain: process.env.AUTH_DOMAIN,\n  projectId: process.env.PROJECT_ID,\n  storageBucket: process.env.STORAGE_BUCKET,\n  messagingSenderId: process.env.MESSAGING_SENDER_ID,\n  appId: process.env.APP_ID,\n})\n// Export your Firestore database so you can use the services throughout your app.\nexport const firestoreDb = getFirestore()\n`)), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, `For security reasons, make sure to place your configuration keys inside environment variables so git can ignore it.`)), mdx(\"h1\", null, `Environment Variables`), mdx(\"p\", null, `In the root folder, create a `, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, `.env.local`), ` file. Then paste this in it:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `PROJECT_ID = your - project - id\nAPP_ID = your - app_id\nAPI_KEY = your - api_key\nAUTH_DOMAIN = your - project - id.firebaseapp.com\nSTORAGE_BUCKET = your - project - id.appspot.com\nMESSAGING_SENDER_ID = your - messaging_sender_id\n`)), mdx(\"h3\", null, `For NextJS applications`), mdx(\"p\", null, `If you're developing in NextJS, `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `you will need to copy this code in your`), ` `, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, `next.config.js`), ` `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `file`), `.`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `module.exports = {\n  reactStrictMode: true,\n  env: {\n    PROJECT_ID=your-project-id\n    APP_ID=your-app_id\n    API_KEY=your-api_key\n    AUTH_DOMAIN=your-project-id.firebaseapp.com\n    STORAGE_BUCKET=your-project-id.appspot.com\n    MESSAGING_SENDER_ID=your-messaging_sender_id\n  },\n  images: {\n    domains: [\"firebasestorage.googleapis.com\"], // if you are using Firebase storage\n  },\n};\n`)), mdx(\"h1\", null, `Conclusion`), mdx(\"p\", null, `A Firebase App is basically like a container-like object that has the common configuration and it shares authentication across all the Firebase services. So after you initialize the object, you can start using the services.`), mdx(\"p\", null, `The first time you add data in Firestore, they are stored implicitly in Documents, which is stored in Collections. You can create a new collection and a document either in the Firebase console or by adding some code.`), mdx(\"p\", null, `That's it. We've connected our Cloud Firestore Database to our app. 🎉`), mdx(\"p\", null, `If you'd like to learn on how to `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"/blog/fetching-data-from-firestore/\"\n  }, `fetch data`), ` from Firestore, check out my blog post. Good luck!`));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":1}},{"node":{"id":"6716a85b-6801-525e-b2ea-5448c01bf60d","fields":{"slug":"/blog/rebuilding-my-portfolio-site-with-tailwind-css/"},"frontmatter":{"date":"May 13, 2021","title":"Rebuilding my portfolio site with Tailwind CSS","description":"My experience with Tailwind CSS."},"excerpt":"In this post, we’ll talk about how switching to utility-first CSS framework like Tailwind CSS might work for you. Also, we’ll explore…","body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"slug\": \"rebuilding-my-portfolio-site-with-tailwind-css\",\n  \"title\": \"Rebuilding my portfolio site with Tailwind CSS\",\n  \"date\": \"2021-05-13\",\n  \"author\": \"Danniel Hansel\",\n  \"description\": \"My experience with Tailwind CSS.\",\n  \"published\": true,\n  \"featured\": true,\n  \"categories\": [\"react\"],\n  \"tags\": [\"javascript\", \"react\", \"gatsby\", \"tailwind-css\", \"bootstrap\"],\n  \"bannerUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1640453752/dannielhansel.com/content/blog/rebuild-portfolio_s7cuq0.webp\",\n  \"bannerCredit\": \"Photo by [Aziz Acharki](https://unsplash.com/photos/6YpwRf0iUa4) on [Unsplash](https://unsplash.com)\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `In this post, we’ll talk about how switching to utility-first CSS framework like Tailwind CSS might work for you.`), mdx(\"p\", null, `Also, we’ll explore Tailwind CSS on a broad level.`), mdx(\"p\", null, `On top of that, we’ll also be building a simple GatsbyJs App from scratch using Tailwind CSS including Tailwind CSS installation, configuration, and designing options.`), mdx(\"h1\", null, `What was I using before?`), mdx(\"p\", null, `Previously, I decided to build my own portfolio site with GatsbyJs and Bootstrap as the CSS framework. The reason why I chose to go with this tech stack is because I have been building several React/GatsbyJs websites in the past and I am also quite familiar with utilizing the Bootstrap framework. Although I was able to get it up and running fairly quickly, there was still something that I wasn’t quite happy about the user interface. Until I discovered Tailwind CSS and what it can do to improve my site and essentially meet my satisfaction.`), mdx(\"h1\", null, `Why did I make the switch?`), mdx(\"p\", null, `My goal after discovering Tailwind CSS was to simply rebuild any complex user interfaces without having my site to look alike any other sites out there. `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `This is the `, mdx(\"em\", {\n    parentName: \"strong\"\n  }, `difference`), ` between Bootstrap and Tailwind CSS.`), ` If you have never used and worked with Bootstrap before, you can tell right off the bat when a site is using Bootstrap framework.`), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, `(hint: just simply look at the Bootstrap buttons and compare them to Tailwind CSS buttons!)`)), mdx(\"p\", null, `However, don’t get me wrong here, Bootstrap is still great and does the job for certain project needs and requirements. In fact, I do still use Bootstrap for my other sites because it comes with a lot of pre-styled components out of the box that are ready to use and look good. `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `If you are just wanting to whip up an absolutely basic interface for a quick PoC (proof of concept), then Bootstrap is your go-to`), `.`), mdx(\"p\", null, `Having that in mind, `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `firstly`), ` I want my new portfolio site to be able to easily handle `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, mdx(\"em\", {\n    parentName: \"strong\"\n  }, `consistency`)), ` in terms of padding, margins, colors, and sizes. With Tailwind CSS, I could just write utility class and then repeatedly use them in my codebase.`), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `Secondly`), `, I want something that can speed up the process of handling `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, mdx(\"em\", {\n    parentName: \"strong\"\n  }, `responsiveness`)), ` of the site from small screens to bigger screens. Tailwind provides five `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `breakpoints`), ` by default to serve different common device resolutions. This makes it a piece of cake to build complex responsive interfaces without ever leaving your HTML.`), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `Thirdly`), `, I want something that doesn’t make it harder on me as the developer to support `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, mdx(\"em\", {\n    parentName: \"strong\"\n  }, `dark mode.`)), ` Dark mode has become the first-class feature of many operating systems. To make this as easy as possible, Tailwind comes with a `, mdx(\"em\", {\n    parentName: \"p\"\n  }, `‘dark’`), ` variant that lets you style your site however you want when dark mode is enabled.`), mdx(\"p\", null, `And `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `lastly`), `, I want to finish this project feeling more `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, mdx(\"em\", {\n    parentName: \"strong\"\n  }, `productive`)), ` than ever when it comes to developing the user interfaces. Since Tailwind comes with a set of utility classes, once you get used to the custom terms and vocabulary, you will feel like you are flying! All in all, Tailwind’s system is a masterpiece of design which I as a developer love it and feel empowered by it.`), mdx(\"h1\", null, `What is Tailwind CSS?`), mdx(\"p\", null, `Okay, then let’s talk about `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, mdx(\"em\", {\n    parentName: \"strong\"\n  }, `“what”`), ` is Tailwind CSS?`), ` Tailwind CSS is a utility-first CSS framework that provides you with a set of low-level utility classes. This framework uses `, mdx(\"em\", {\n    parentName: \"p\"\n  }, `atomic CSS`), ` (or functional CSS) which is essentially a delivery mechanism that allows you and I, as developers, to apply the system to the UI. On top of that, it uses PostCSS to process the final output and it comes with PurgeCSS which removes unused CSS from your project file.`), mdx(\"p\", null, `In this post, we’ll be using the Gatsby Default Starter. If you’ve never used Gatsby before, I have included a quick tutorial on how to create a new Gatsby project, but you can read more about it `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.digitalocean.com/community/tutorials/gatsbyjs-gatsby-first-steps\"\n  }, `here`), ` from the docs. But the idea here is simple, you can use any of your favorite framework or library and install Tailwind CSS to handle the styling for you!`), mdx(\"h1\", null, `Part 1: Gatsby Quick Installation Guide`), mdx(\"h2\", null, `Step 1: System requirements`), mdx(\"p\", null, `Make sure you have Node.js, Git, and other tools required to get started with your first Gatsby project. To learn more about it, check out the `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.gatsbyjs.com/docs/tutorial/part-zero/\"\n  }, `Gatsby docs`), `.`), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://git-scm.com/\"\n  }, `Git`), ` (v2.13 or greater)`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://nodejs.org/en/\"\n  }, `NodeJS`), ` (v8.2.0 0r higher)`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://www.npmjs.com/\"\n  }, `NPM`), ` (v6 or greater) or `, mdx(\"a\", {\n    parentName: \"li\",\n    \"href\": \"https://yarnpkg.com/\"\n  }, `Yarn`))), mdx(\"p\", null, `All of these must be available in your `, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, `PATH`), `. To verify things are set up properly, you can run this:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-shell\"\n  }, `git --version\nnode --version\nnpm --version # or yarn --version\n`)), mdx(\"p\", null, `If you have trouble with any of these, learn more about the PATH environment\nvariable and how to fix it here for `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.howtogeek.com/118594/how-to-edit-your-system-path-for-easy-command-line-access/\"\n  }, `windows`), ` or\n`, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://stackoverflow.com/questions/24306398/how-to-add-mongo-commands-to-path-on-mac-osx/24322978#24322978\"\n  }, `mac/linux`), `.`), mdx(\"h2\", null, `Step 2: Download/Install the Gatsby CLI package:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-shell\"\n  }, `npm install -g gatsby-cli\n`)), mdx(\"p\", null, `Check out all the available commands:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-shell\"\n  }, `gatsby --help\n`)), mdx(\"h2\", null, `Step 3: Create a Gatsby site using the default starter template`), mdx(\"p\", null, `Stick this in your terminal and hit enter`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-shell\"\n  }, `gatsby new my-first-gatsby-project https://github.com/gatsbyjs/gatsby-starter-default\n`)), mdx(\"p\", null, `Change into the directory:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-shell\"\n  }, `cd my-first-gatsby-project\n`)), mdx(\"p\", null, `Start the development server:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-shell\"\n  }, `gatsby develop\n`)), mdx(\"p\", null, `View your site locally. Open up a new tab in your browser and navigate to: `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"http://localhost:8000/\"\n  }, `http://localhost:8000/`)), mdx(\"h1\", null, `Part 2: Setting up Tailwind CSS`), mdx(\"h2\", null, `Step 1: Create two configs for Tailwind CSS and PostCSS:`), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, `Note: You might not have do this, so check if they're preinstalled in your root directory.`)), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-shell\"\n  }, `touch tailwind.config.js\n`)), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-shell\"\n  }, `touch postcss.config.js\n`)), mdx(\"p\", null, `Add this default configuration inside tailwind.config.js:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// inside tailwind.config.js\nconst defaultTheme = require(\"tailwindcss/defaultTheme\")\nconst plugin = require(\"tailwindcss/plugin\")\nconst colors = require(\"tailwindcss/colors\")\n\nmodule.exports = {\n  mode: \"jit\",\n  // purge: {              // this is not needed for tailwind 3.0\n  //   content: [\"./src/**/*.js\"],\n  // },\n  content: [\"./src/**/*.js\"],\n  darkMode: \"class\", // or 'media' or 'class'\n  theme: {\n    screens: {\n      ...defaultTheme.screens,\n      xs: \"475px\",\n    },\n    textColor: theme => ({\n      ...theme(\"colors\"),\n      primary: \"#397E89\",\n      secondary: \"#883377\",\n    }),\n    extend: {\n      fontFamily: {},\n    },\n  },\n  variants: {\n    extend: {},\n  },\n  plugins: [],\n}\n`)), mdx(\"h2\", null, `Step 2: Install Tailwind CSS and add NPM dependencies:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-shell\"\n  }, `npm install --save gatsby-plugin-postcss tailwindcss\n`)), mdx(\"p\", null, `Stick this plugin in:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// inside gatsby-config.js\nmodule.exports = {\n  // ...rest\n  plugins: [\n    {\n      resolve: \\`gatsby-plugin-postcss\\`,\n      options: {\n        postCssPlugins: [require(\"tailwindcss\")],\n      },\n    },\n  ],\n}\n`)), mdx(\"h2\", null, `Step 3: Import Tailwind CSS in the src/components/layout.css `, mdx(\"em\", {\n    parentName: \"h2\"\n  }, `(at the very top)`), `:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// inside layout.css\n@tailwind base;\n@tailwind components;\n@tailwind utilities;\n`)), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `Congrats! You have now successfully added TailwindCSS to your Gatsby project!`)), mdx(\"p\", null, `Next, it’s time to add Tailwind classes to your HTML. `, mdx(\"em\", {\n    parentName: \"p\"\n  }, `In this post, we are only going to create a basic Hero component on landing page and play around with the styling options.`)), mdx(\"h1\", null, `Part 3: Creating a basic Landing page`), mdx(\"p\", null, `Before we start, `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `let's first kill the dev server`), `. Navigate to your terminal and ctrl + C.`), mdx(\"h2\", null, `Navigate to index.js file and replace the IndexPage component with this:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `const IndexPage = () => (\n  <Layout>\n    <Seo title=\"Home\" />\n    <div\n      className=\"flex items-center bg-gradient-to-br from-green-400 via-blue-500 to-purple-500\n      shadow-inner min-h-screen\"\n    >\n      <div className=\"bg-white w-full py-6 shadow-2xl\">\n        <div className=\"mx-auto container w-4/5 sm:w-3/5\">\n          <div className=\"self-center items-center mb-4\">\n            <h1 className=\"capitalize font-bold text-xl text-center text-secondary\">\n              Your Name\n            </h1>\n            <h3 className=\"uppercase font-semibold text-primary text-center\">\n              Full Stack Developer\n            </h3>\n            <div className=\"grid justify-items-center\">\n              <button\n                className=\"transition duration-500 ease-in-out transform hover:-translate-y-1\n              hover:scale-110 bg-gradient-to-r from-green-400 to-blue-500 hover:from-blue-500\n              hover:to-purple-500 text-white font-bold py-2 px-4 border-b-4 border-blue-700\n              hover:border-purple-500 rounded mt-6\"\n              >\n                Contact Me!\n              </button>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  </Layout>\n)\n`)), mdx(\"h3\", null, `Run the development server to rebuild the project.`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-shell\"\n  }, `gatsby develop\n`)), mdx(\"p\", null, `Navigate to your `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"http://localhost:8000/\"\n  }, `localhost server`), ` to see the result! 🙌`), mdx(\"h1\", null, `Styling in Tailwind CSS`), mdx(\"h2\", null, `Colors in Tailwind CSS`), mdx(\"p\", null, `Inside `, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, `tailwind.config.js`), ` file, we can override Tailwind’s default `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://tailwindcss.com/docs/customizing-colors\"\n  }, `color palette`), `, extend it or even disable it.`), mdx(\"p\", null, `In our example, we have added two colors as `, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, `‘primary’`), ` and `, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, `‘secondary’`), `.`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// inside tailwind.config.js\ntheme: {\n    textColor: theme => ({\n      ...theme(\"colors\"),\n      primary: \"#397E89\",\n      secondary: \"#883377\",\n    }),\n        ...\n  },\n`)), mdx(\"p\", null, `To apply it to your HTML, you can simply just add it using inline style as `, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, `‘text-primary’`), ` or `, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, `‘text-secondary’`), `.`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `<h1 className=\"capitalize font-bold text-xl text-center text-secondary\">\n    Your Name\n</h1>\n\n<h3 className=\"uppercase font-semibold text-primary text-center\">\n    Full Stack Developer\n</h3>\n\n`)), mdx(\"h2\", null, `Styling a Button`), mdx(\"p\", null, `Tailwind comes with a palette of colors that you can choose from. I'd recommend you to check out all the colors they have and play around with it. In our example, we are using a `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `gradient of colors`), `.`), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, `bg-gradient-to-r from-green-400 to-blue-500`)), mdx(\"h2\", null, `Hovering a component (Pseudo classes with inline styling)`), mdx(\"p\", null, `In our example, we simply use a gradient of colors when a button is being hovered.`), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, `hover:from-blue-500 hover:to-purple-500`)), mdx(\"h2\", null, `Other low-level utility classes that we’ve used in our example:`), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `font-bold`), `: add bold font;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `flex`), `: display: flex;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `items-center`), `: align-items: center;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `shadow-inner`), `: box shadow`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `min-h-screen`), `: setting minimum height of an element;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `w-full`), `: width: 100%;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `w-4/5`), `: width: 80%;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `self-center`), `: align-self: center;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `py-6`), `: padding-top: 1.5rem; padding-bottom: 1.5rem;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `mb-4`), `: margin-bottom: 1rem;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `capitalize`), `: text-transform: capitalize;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `uppercase`), `: text-transform: uppercase;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `text-xl`), `: font-size: 1.25rem; line-height: 1.75rem;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `text-center`), `: text-align: center;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `justify-items-center`), `: justify-items: center;`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `transition`), `: transition property`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `bg-green-400`), `: to use green as the button’s background color`), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, `hover:bg-blue-700`), `: to change the blue color when hovering over the button`)), mdx(\"h1\", null, `The Downsides of Tailwind CSS 📉`), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, `As Tailwind CSS becomes more revolutionized, there are definitely some challenges. However, I am going to talk about the challenges I faced on the underlying concept of utility-first framework.`)), mdx(\"h2\", null, `Repeatable CSS`), mdx(\"p\", null, `With utility-first, you are going to have repeated classes. This could get annoying as your project eventually grows larger. Compare to regular CSS, you could just create a class that does the same job and you can reuse that class in multiple components.`), mdx(\"p\", null, `Of course, you can find a way to not repeat the classes but that defeats the purpose of using a utility-first concept because the goal is to minimize the handling of CSS to your project.`), mdx(\"h2\", null, `Readability`), mdx(\"p\", null, `Take our button for example. If you were to have multiple buttons on your site, you would have a long list of classes for each button and as you can already guess, It will be hard to read. This could be the biggest downfall of utility-first concept. As your project grows, you are more than likely going add tons of CSS classes to your project.`), mdx(\"h2\", null, `Atomic CSS downsides`), mdx(\"p\", null, `Atomic CSS is not ideal for performance. You would have to ship more CSS to the browser than necessary because no tooling can extract the per-page critical CSS. As your utility-based CSS library grows, so does the amount of CSS you ship to your users, leaving you having to build more tools to remove styles that you were never going to use in the first place.`), mdx(\"h1\", null, `Conclusion`), mdx(\"h3\", null, `Was it worth switching to Tailwind CSS?`), mdx(\"p\", null, `Most definitely, Yes! ✅After successfully rebuilding my portfolio site using Tailwind, I am loving every piece of it. If you love a good design, you'd definitely love Tailwind, especially with just how it gives you the aesthetic and modern feel and look. `, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `Very important for building the `, mdx(\"a\", {\n    parentName: \"strong\",\n    \"href\": \"https://headlessui.dev/\"\n  }, `user interface`), ` to enhance user experience.`), ` 👀 They also have a great `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/tailwindlabs/tailwindcss/discussions\"\n  }, `community`), ` and a well detailed `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://tailwindcss.com/docs/installation\"\n  }, `documentation`), `.`), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, `UPDATE`), `: They had just recently upgraded to `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://tailwindcss.com/docs/upgrade-guide\"\n  }, `Tailwind 3.0`), `.`)), mdx(\"p\", null, `Always keep this in mind, every tool and technology out there has tradeoffs. So it's always good to `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://play.tailwindcss.com/\"\n  }, `play around`), ` and test them. I hope that I’ve given you an overview of how Tailwind has helped me improve my project. 😇`));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":6}}]}},"pageContext":{}},
    "staticQueryHashes": ["2744905544","3145194271","3960949143","3970664207"]}