{"data":{"post":{"title":"Notes On Implementation of Gatsblog","subtitle":"","isPublished":true,"createdTime":"2019-03-04T00:00:00.000Z","lastModifiedTime":null,"license":null,"tags":["Blog","Programming","Gatsblog"],"category":"Showcase","file":{"childMdx":{"excerpt":"This post has been revisited with LLM technology to improve its English\nfluency. In this post, I'll…","code":{"body":"function _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\nconst layoutProps = {};\nreturn class MDXContent extends React.Component {\n  constructor(props) {\n    super(props);\n    this.layout = null;\n  }\n\n  render() {\n    const _this$props = this.props,\n          {\n      components\n    } = _this$props,\n          props = _objectWithoutProperties(_this$props, [\"components\"]);\n\n    return React.createElement(MDXTag, {\n      name: \"wrapper\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"blockquote\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `This post has been revisited with LLM technology to improve its English\nfluency.`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `In this post, I'll discuss the implementation of Gatsblog, a blog system\nbuilt with Gatsby.js. If you missed my previous posts about the overview and\ndesign of Gatsblog, please check them for context about the technology stack.\nAs this is my first JavaScript/Node.js/front-end project, the following\napproaches may not represent best practices.`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `Identifying Resources`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `How do we identify one post from another?`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Since posts may share the same name, we need a unique identifier for each.\nLike Jekyll, I initially chose a URL scheme of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `/post/YYYY/MM/post-name`), ` and\na filename format of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `YYYY-MM-DDThh-mm-ssZ-post-name.md`), ` (with optional time\nand timezone). However, I soon discovered this approach couldn't distinguish\nposts with identical names published on the same day.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `To solve this problem, I decided to `, React.createElement(MDXTag, {\n      name: \"strong\",\n      components: components,\n      parentName: \"p\"\n    }, `hash`), ` the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `YYYY-MM-DDThh-mm-ssZ`), `\nportion and append the hash value to the URL. The resulting URL scheme\nbecame:`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {}\n    }, `/post/YYYY/MM/post-name-1a0c\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `This allows unique identification of each post.`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `Protecting Sensitive Information from Bots`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Websites often contain sensitive information meant only for human users.\nPlain HTML content like `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `mailto:whatever@email.ltd`), ` exposes information to\nbots. To protect against this, I designed a simple process and implemented\na React component that:`), React.createElement(MDXTag, {\n      name: \"ol\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ol\"\n    }, `Encrypts sensitive information during source compilation`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ol\"\n    }, `Decrypts the information only when a real user clicks the component`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `The implementation is straightforward, with one caveat: Safari prevents\nprogrammatic behaviors like page redirection on click unless you call\n`, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `event.preventDefault()`), ` immediately after a click event.`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `Adapting to CSS Layout Box`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `While implementing my design, I discovered that CSS layout boxes aren't\nideal for professional designers.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Some might say, \"But CSS offers flex-box and grid layout models.\"`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `I don't mean just the box model; none of CSS's layout models align with\nhow designers think. CSS layout boxes calculate text content size using\n`, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `line-height`), `, a concept unfamiliar to designers. Designers work with\ntypographic properties like ascent, descent, x-height, and line spacing,\nnot `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `line-height`), `.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/bd17f59e516723edbad0c5b33484ba0a/e331b/typography-explained.png\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"a\",\n      props: {\n        \"title\": \"Typography Explained\",\n        \"alt\": \"Typography Explained\",\n        \"src\": \"/static/bd17f59e516723edbad0c5b33484ba0a/e331b/typography-explained.png\",\n        \"srcSet\": [\"/static/bd17f59e516723edbad0c5b33484ba0a/e331b/typography-explained.png 1x\", \"/static/ee75ab2442149440d31aabec0a82099f/62def/typography-explained%402x.png 2x\", \"/static/3936677a6553dd8539ae58fdd9a2a78c/3bed8/typography-explained%403x.png 3x\"],\n        \"loading\": \"lazy\"\n      }\n    })), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            Typography Explained\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `In CSS, `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `line-height`), ` sets the space used for lines in text. This property\nhas no direct connection to font attributes. The only way to connect\n`, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `line-height`), ` to font is by setting it with a unitless number—creating a\nratio between `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `line-height`), ` and `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `font-size`), `.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/2a06c084ce5b63a14e0858e671f3d1e4/23088/line-height-explained.png\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"a\",\n      props: {\n        \"title\": \"Line Height Explained\",\n        \"alt\": \"Line Height Explained\",\n        \"src\": \"/static/2a06c084ce5b63a14e0858e671f3d1e4/23088/line-height-explained.png\",\n        \"srcSet\": [\"/static/2a06c084ce5b63a14e0858e671f3d1e4/23088/line-height-explained.png 1x\", \"/static/96c5808884539ab2594a6d050189c076/6cd0f/line-height-explained%402x.png 2x\", \"/static/bcf1e84b4b132b11a757a6330acd1e92/471e9/line-height-explained%403x.png 3x\"],\n        \"loading\": \"lazy\"\n      }\n    })), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            Line Height Explained\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `As shown in my previous post, designers often lay out elements using font\nattributes. This creates a disconnect between the default size of CSS layout\nboxes and designer expectations.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `To bridge CSS layout boxes and the designer's world, we must think in terms\nof `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `line-height`), ` when setting margins rather than font attributes. I developed\na solution called Normalized Layout Box to adjust layout box size to match\ndesigner intentions.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"figure\",\n      components: components,\n      parentName: \"p\"\n    }, `\n    `, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"figure\",\n      props: {\n        \"href\": \"/static/9026985997eeeb8855b3d43528ee276d/4d5a0/normalized-layout-box.png\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"a\",\n      props: {\n        \"title\": \"Normalized Layout Box\",\n        \"alt\": \"Normalized Layout Box\",\n        \"src\": \"/static/9026985997eeeb8855b3d43528ee276d/4d5a0/normalized-layout-box.png\",\n        \"srcSet\": [\"/static/9026985997eeeb8855b3d43528ee276d/4d5a0/normalized-layout-box.png 1x\", \"/static/77b109a25915f39247329be0939c2416/5fc4b/normalized-layout-box%402x.png 2x\", \"/static/76883cd9b8c8ad24d3d9cc3f3429b035/dc546/normalized-layout-box%403x.png 3x\"],\n        \"loading\": \"lazy\"\n      }\n    })), `\n    `, React.createElement(MDXTag, {\n      name: \"figcaption\",\n      components: components,\n      parentName: \"figure\"\n    }, `\n        `, React.createElement(MDXTag, {\n      name: \"span\",\n      components: components,\n      parentName: \"figcaption\"\n    }, `\n            Normalized Layout Box\n        `), `\n    `))), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `Normalized Layout Box`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `To reduce layout box size, we can use negative margins:`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-css\"\n      }\n    }, `.normalized-layout-box {\n  font-size: 1.3em;\n  line-height: 1.3;\n  margin-top: -0.3rem;\n  margin-bottom: -0.3rem;\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `However, since block elements collapse margins (when elements are adjacent\nor nested), we end up with `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `0`), ` top margin if the layout box is the first\nchild and `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `0`), ` bottom margin if it's the last child. To make negative margins\nwork in these cases, we must wrap the block elements in a flex box.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-css\"\n      }\n    }, `.normalized-layout-box-flex-wrapper {\n  align-items: stretch;\n  display: flex;\n  flex-direction: column;\n}\n`)), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-html\"\n      }\n    }, `<div class=\"normalized-layout-box-flex-wrapper\">\n  <div class=\"normalized-layout-box\">\n    Contents\n  </div>\n</div>\n`)), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `Testing`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `This project lacks comprehensive testing. Testing JavaScript is tedious because,\nas a dynamic language, it relies heavily on tests for correctness. Without\nexplicit data type schemes, ensuring program correctness requires extensive\ntesting efforts.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `You might suggest \"snapshot\" testing—a great feature in Jest. But many issues\nstem from type mismatches or mistakes that type checking would catch. Also,\nhow can we verify that manually created snapshots are correct?`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `I need a type system for JavaScript. If I continue developing this blog project,\nI would migrate from JavaScript to TypeScript to address these concerns.`));\n  }\n\n}\nMDXContent.isMDXComponent = true;","scope":""},"headings":[{"value":"Identifying Resources","depth":2},{"value":"Protecting Sensitive Information from Bots","depth":2},{"value":"Adapting to CSS Layout Box","depth":2},{"value":"Normalized Layout Box","depth":3},{"value":"Testing","depth":2}]}}},"earlierPostExcerpt":{"slug":"/post/2019/03/notes-on-design-of-gatsblog-1431","title":"Notes on Design of Gatsblog","subtitle":"","createdTime":"2019-03-03T00:00:00.000Z","tags":["Blog","Design","Gatsblog"],"category":"Showcase","file":{"childMdx":{"excerpt":"This post has been revisited with LLM technology to improve its English\nfluency. I had limited time to create a modern design for the first version of Gatsblog.\nThe design is somewhat \"old school,\" but I carefully tuned the grid system to\nachieve a high-quality layout. Grid System Grid systems are…"}}},"laterPostExcerpt":{"slug":"/post/2019/03/use-crontab-to-automate-updates-of-cli-softwares-cac3","title":"Use crontab to Automate Updates of CLI Softwares","subtitle":"","createdTime":"2019-03-24T00:00:00.000Z","tags":["UNIX","crontab","Automation"],"category":"Productivity","file":{"childMdx":{"excerpt":"crontab , an abbreviation of chronic table (periodical time table), is\na task scheduler which schedules tasks in period of time on UNIX systems.\nEach user in UNIX systems have its own \"crontab\". Editing the crontab File By executing  crontab -e , you can open the crontab of the user you logged\nin…"}}}},"pageContext":{"postId":"b0391bd1-0091-590a-80f2-6b6cb0632e4d","earlierPostId":"10d7b0ff-a57b-5ed6-8009-210fb03be8e7","laterPostId":"134e5703-f8d8-5c94-b7f7-fbe98b44876e"}}