├── .env.development ├── .gitignore ├── .gitpod.yml ├── .glitch-assets ├── .vscode └── settings.json ├── Acknowledgement.md ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── content ├── meetups │ ├── 1.md │ ├── 2.md │ ├── 3.md │ ├── 4.md │ ├── 5.md │ ├── 6.md │ └── 7.md ├── speakers │ ├── crabbie.md │ └── wei.md ├── stories │ ├── baby-react-knowledgeable-is-born.md │ ├── images │ │ ├── penang.jpg │ │ ├── rk-bug.png │ │ ├── rk-draw-out-loud.png │ │ ├── rk-learning.png │ │ ├── rk-react.png │ │ ├── rk-shoutouts.png │ │ ├── rk-speaker-slide.png │ │ ├── rk-what-is.png │ │ └── rk.png │ ├── introducing-rk-lightning-to-this-town.md │ ├── recap-2 │ │ ├── index.md │ │ └── rk-what-are-you-learning-this-week.png │ ├── recap-rk-2019.md │ ├── rk-is-1yo.md │ └── rk-will-close-meetup-dot-com-group-soon.md └── talks │ └── how-not-to-get-caught-and-be-eaten.md ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-node.js ├── package.json ├── prettier.config.js ├── script.js ├── src ├── components │ ├── Avatar │ │ ├── index.jsx │ │ └── s.module.scss │ ├── Card │ │ ├── index.jsx │ │ └── s.module.scss │ ├── ExternalLinkIcon │ │ ├── index.jsx │ │ └── s.module.scss │ ├── Footer │ │ ├── index.jsx │ │ └── s.module.scss │ ├── Layout │ │ ├── index.jsx │ │ └── s.module.scss │ ├── Participants │ │ └── index.jsx │ ├── RSVP │ │ ├── index.js │ │ └── s.module.scss │ └── Talk │ │ ├── index.jsx │ │ └── s.module.scss ├── functions │ ├── airtable.js │ ├── package.json │ ├── rollup.config.js │ └── yarn.lock ├── pages │ ├── 404 │ │ ├── index.jsx │ │ └── s.module.scss │ ├── index.jsx │ └── s.module.scss ├── templates │ ├── Meetup │ │ ├── index.jsx │ │ └── s.module.scss │ ├── Speaker │ │ └── index.jsx │ ├── Story │ │ ├── index.jsx │ │ └── s.module.scss │ └── Talk │ │ └── index.jsx └── utils │ ├── parseDate.js │ ├── remote.js │ └── typography.js ├── static └── logo.png ├── watch.json └── yarn.lock /.env.development: -------------------------------------------------------------------------------- 1 | GLITCH_URL=react-knowledgeable.glitch.me -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | **/node_modules/* 3 | *.log 4 | .cache/ 5 | public 6 | .env 7 | functions/* -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - init: yarn install 3 | command: yarn start 4 | ports: 5 | - port: 8000 6 | onOpen: open-preview 7 | github: 8 | prebuilds: 9 | # enable for the master/default branch (defaults to true) 10 | master: true 11 | # enable for all branches in this repo (defaults to false) 12 | branches: true 13 | # enable for pull requests coming from this repo (defaults to true) 14 | pullRequests: true 15 | # enable for pull requests coming from forks (defaults to false) 16 | pullRequestsFromForks: true 17 | # add a "Review in Gitpod" button as a comment to pull requests (defaults to true) 18 | addComment: true 19 | # add a "Review in Gitpod" button to pull requests (defaults to false) 20 | addBadge: false 21 | # add a label once the prebuild is ready to pull requests (defaults to false) 22 | addLabel: prebuilt-in-gitpod -------------------------------------------------------------------------------- /.glitch-assets: -------------------------------------------------------------------------------- 1 | {"name":"drag-in-files.svg","date":"2016-10-22T16:17:49.954Z","url":"https://cdn.hyperdev.com/drag-in-files.svg","type":"image/svg","size":7646,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/drag-in-files.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(102, 153, 205)","uuid":"adSBq97hhhpFNUna"} 2 | {"name":"click-me.svg","date":"2016-10-23T16:17:49.954Z","url":"https://cdn.hyperdev.com/click-me.svg","type":"image/svg","size":7116,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/click-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(243, 185, 186)","uuid":"adSBq97hhhpFNUnb"} 3 | {"name":"paste-me.svg","date":"2016-10-24T16:17:49.954Z","url":"https://cdn.hyperdev.com/paste-me.svg","type":"image/svg","size":7242,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/paste-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(42, 179, 185)","uuid":"adSBq97hhhpFNUnc"} 4 | {"uuid":"adSBq97hhhpFNUna","deleted":true} 5 | {"uuid":"adSBq97hhhpFNUnb","deleted":true} 6 | {"uuid":"adSBq97hhhpFNUnc","deleted":true} 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /Acknowledgement.md: -------------------------------------------------------------------------------- 1 | 2 | The idea and implementation of this site could not have been possible without the existing great projects out there and the great people who have come to help and inspire: 3 | 4 | - [Ken](https://github.com/KenLSM) who has been running RK together with me since Oct 2018, who leads all the fine work done at RK 5 | - [Huijing](https://chenhuijing.com) for being the first one to look at this site and all the ideas / suggestions on styling, then all the brilliant work in designing, bouncing off ideas, and messing around with this site. This site would have been much less colorful without you 6 | - [Nut](https://github.com/nutstick) for showing me all the possibilities with GraphQL queries and helping setting everything up!! 7 | - [Thomas](https://github.com/thchia) for collaborating on this site, cannot wait to see what we'll create together down the road :)) 8 | - [meowni.ca](meowni.ca) for the inspirations 💜🦄 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## Sept 21 2019 3 | 4 | **Added** 5 | 6 | - Support for sponsors 7 | 8 | **Changed** 9 | 10 | - Meetup pages to have links to issue and meetup links 11 | - Moved "Talk Line-up" section to main area in meetup pages 12 | 13 | ## July 25 2019 14 | 15 | **Added** 16 | 17 | - Google analytics 18 | - SEO for story pages 19 | - Image sharp for post content 20 | 21 | **Fixed** 22 | 23 | - oembed twitter plugin 24 | 25 | ## July 17 2019 26 | 27 | **Changed** 28 | 29 | - RK friends layouts 30 | 31 | ## July 16 2019 32 | 33 | **Added** 34 | 35 | - RK friends 36 | - Query talks from GitHub 37 | 38 | **Changed** 39 | 40 | - Refactor UI components 41 | - A number of UI fixes 42 | 43 | ## July 15 2019 44 | 45 | **Added** 46 | 47 | - 404 page 48 | 49 | ## Earlier July 2019 50 | 51 | The site was born -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Wei Gao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Knowledgeable 2 | 3 | React Knowledgeable is a fun and friendly podium to share what we learn about React. 4 | 5 | This repo is the community site for ``. 6 | 7 | ## 🖥 Developing locally 8 | 9 | > You will need an Airtable API key to develop locally 10 | 11 | 1. Run `yarn` (or `npm install`) 12 | 2. Set up [GitHub Personal Access Token](https://github.com/settings/tokens), refer to [Authenticating with GraphQL](https://developer.github.com/v4/guides/forming-calls/#authenticating-with-graphql) for requisite scope 13 | 3. Acquire Airtable API Key and Base ID and set it into your environment. Your Airtable base should have a table named `Attendees` and short string fields with "Event ID", "Github Username", "Created Date", "Name" and "Type". 14 | 4. Run `yarn start` or `npm start` (see below for variable configuration). 15 | 16 | ### API Keys 17 | 18 | You can either create a `.env` file, or specify these keys when running the `start` command: 19 | 20 | `GITHUB_TOKEN=XXX AIRTABLE_API_KEY=YYY ... yarn start` or `env GITHUB_TOKEN=XXX AIRTABLE_API_KEY=YYY ... npm start` 21 | 22 | ``` 23 | // .env file 24 | 25 | GITHUB_TOKEN=XXX 26 | AIRTABLE_API_KEY=YYY 27 | AIRTABLE_BASE_ID=ZZZ 28 | ``` 29 | 30 | ## 🎙 Talk slides 31 | 32 | 1. Go to one of the meetup pages, i.e. https://reactknowledgeable.org/meetups/1/ 33 | 2. Press p for presentation mode 34 | 3. Paging controls: 35 | - space or j: next page 36 | - k: previous page 37 | - digits 0 ~ 9: respective pages 38 | 39 | ### Random things to note 40 | 41 | If you use `npm` instead of `yarn`, you may run into the following error: 42 | 43 | ``` 44 | The above error occurred in the component: 45 | in StoreStateProvider 46 | in App 47 | 48 | React will try to recreate this component tree from scratch using the error boundary you provided, App. 49 | Warning: App: Error boundaries should implement getDerivedStateFromError(). In that method, return a state update to display an error message or fallback UI. 50 | ``` 51 | The actual cause of this error might be due to the differences between how both package managers handle things. Running `yarn` and letting the yarn resolve dependencies will fix the issue. 52 | -------------------------------------------------------------------------------- /content/meetups/1.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2019-08-06 3 | venue: Carousell 4 | venueLogo: https://mweb-cdn.karousell.com/images/carousell-logo.svg 5 | venueLink: https://sg.carousell.com/ 6 | talks: 7 | - 8 8 | - 4 9 | - 1 10 | - 6 11 | - 5 12 | issueLink: https://github.com/react-knowledgeable/talks/issues/3 13 | title: '' 14 | --- 15 | 16 | ## ⚛️ React updates ⚛️ 17 | 18 | ### [Algebraic Effects for the Rest of Us](https://overreacted.io/algebraic-effects-for-the-rest-of-us/) 19 | 20 | Intuitively introduces algebraic effects, which invites us to think more thoroughly about effect handling in a perform - resume process, feels like try catch but more powerful! Presumptuous ES2025 proposal 😈 21 | 22 | ![](https://overreacted.io/static/5fb19385d24afb94180b6ba9aeb2b8d4/79ad4/effects.jpg) 23 | 24 | ### Gatsby officially released [Gatsby Theme](https://www.gatsbyjs.org/docs/themes/what-are-gatsby-themes/) 25 | 26 | [Gatsby Theme JAM](https://themejam.gatsbyjs.org/) a contest that ended on July 31st, and there were [many](https://amsterdam.netlify.com/) [interesting](https://gatsby-theme-minimal.netlify.com/) [themes](https://github.com/vojtaholik/gatsby-theme-simplecast) that emerged 27 | 28 | ### [Hermes Engine](https://hermesengine.dev/) was born 29 | 30 | [Chain React](https://infinite.red/ChainReactConf) happened on July 12, [Hermes was released](https://hermesengine.dev/), its doc site is using Docusaurus 2, [got only 1 page and yet has a dark light toggle](https://twitter.com/sebmck/status/1149386753012191232?s=20). Only available on Android, and still a work in progress 31 | ### More 32 | 33 | - [How we built a component library that people actually enjoy using](https://medium.com/styled-components/how-to-build-a-great-component-library-a40d974a412d) 34 | - [`useSubscriptionHook`](https://github.com/facebook/react/pull/15022) the React team now maintains a `useSubscription` hook 35 | - [`useEvent` hook](https://github.com/facebook/react/pull/15927) 36 | -------------------------------------------------------------------------------- /content/meetups/2.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2019-09-05 3 | venue: HackerspaceSG 4 | venueLogo: https://pbs.twimg.com/profile_banners/71136691/1397196298/1500x500 5 | venueLink: https://hackerspace.sg/ 6 | talks: 7 | - 2 8 | - 11 9 | - 13 10 | - 14 11 | issueLink: https://github.com/react-knowledgeable/talks/issues/9 12 | title: '' 13 | --- 14 | 15 | ## ⚛️ React updates ⚛️ 16 | 17 | ### ⚛️ [React 16.9 is released](https://reactjs.org/blog/2019/08/08/react-v16.9.0.html) 18 | 19 | Featuring: 20 | 21 | - Deprecations! I like to live UNSAFE-ly (courtesy of codemods)! 22 | - `"act()"` your age (testing utility updates...) 23 | - We heard you like profiling, so have a ``! Will notify ON EVERY RENDER 🤪 24 | - Some news about why the "real" Suspense is not ready yet (fear not React Core Team we support you 4eva) 25 | 26 | ### 🛠 [New DevTools](https://reactjs.org/blog/2019/08/15/new-react-devtools.html) (demo) 27 | 28 | - [changelog](https://github.com/facebook/react/blob/master/packages/react-devtools/CHANGELOG.md#400-august-15-2019) 29 | - [interactive tutorial](https://react-devtools-tutorial.now.sh/) 30 | 31 | ### 🥯 Flow v0.106 [Coming Soon: Changes to Object Spreads](https://medium.com/flow-type/coming-soon-changes-to-object-spreads-73204aef84e1) 32 | 33 | - the current model is based on an assumption that inexact object types do not specify own-ness, this makes properties from spread become optional because object spread at run time copies only _own_ properties 34 | - the new model assumes inexact object types specify own-ness on specified properties, therefore following our intuition of object spread more closely 35 | - inexact objects _may_ contain more properties that may overwrite existing properties in spread target 36 | - the new model will err, tell us what happens, and ask if we can make the spreaded object exact 37 | -------------------------------------------------------------------------------- /content/meetups/3.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2019-10-10 3 | venue: SP Digital 4 | venueAddress: SP Digital, Keppel Towers 2, 240 Tanjong Pagar Road \#08-00 5 | venueLogo: https://www.idcdxawards.com/wp-content/uploads/2019/01/SG-SP-Digital-2.png 6 | issueLink: https://github.com/react-knowledgeable/react-knowledgeable-talks/issues/12 7 | talks: 8 | - 15 9 | - 18 10 | - 19 11 | - 23 12 | title: '' 13 | --- 14 | 15 | ## Audience sponsored by _Shopee_ 16 | 17 | ## ⚛️ React updates ⚛️ 18 | 19 | ### ⚛️ [React 16.10 is released!](https://github.com/facebook/react/blob/master/CHANGELOG.md#16101-september-28-2019) 20 | 21 | ### 🛠DevTools updates 22 | Featuring: 23 | - [Adding props to components](https://github.com/facebook/react/pull/16700) 24 | - [Highlighting legacy context usage](https://github.com/facebook/react/pull/16617) 25 | 26 | ### ⚛️ [Preact X is released](https://github.com/preactjs/preact/releases/tag/10.0.0) 27 | 28 | Preact is the 3kB alternative to React with the same modern API. The release in [Preact X](https://preactjs.com/guide/v10/whats-new) contains a lot of features from React 16, which isn't supported by earlier versions of Preact. Features like Fragments, componentDidCatch, new context, and hooks are now supported by Preact. 29 | 30 | ### 📱[React Native 0.61 is released, with Fast Refresh!](https://github.com/react-native-community/releases/blob/master/CHANGELOG.md) 31 | [Official announcement](https://facebook.github.io/react-native/blog/2019/09/18/version-0.61) by Dan Abramov 32 | 33 | ### [React router v5.1.x released, hooks provided!](https://github.com/ReactTraining/react-router/releases/tag/v5.1.0) 34 | See the blog for useParams, useLocation, useHistory, and useRouteMatch hooks [here](https://reacttraining.com/blog/react-router-v5-1/). 35 | 36 | ### 📕 Interesting reads 37 | - [Design decision: why do we need the stale closure problem in the first place?](https://github.com/facebook/react/issues/16956) 38 | - [Intro to SVG for React Devs](https://able.bio/dbmzzo/intro-to-svg-for-react-developers--56cmmcy) 39 | - [React Hook Recipes ](https://usehooks.com) 40 | 41 | -------------------------------------------------------------------------------- /content/meetups/4.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2019-11-07 3 | issueLink: https://github.com/react-knowledgeable/react-knowledgeable-talks/issues/20 4 | venue: GovTech Hive 5 | venueLogo: https://d33wubrfki0l68.cloudfront.net/7b7e8b84b8180770131a2838266cc18409b22293/545c3/images/logo_govtech_hort.gif 6 | eventLink: https://www.eventbrite.com/e/rk-lightning-4-tickets-76852884045 7 | title: '' 8 | talks: 9 | - 22 10 | - 25 11 | - 27 12 | - 28 13 | --- 14 | 15 | ## ⚛️ React updates ⚛️ 16 | 17 | ### ⚛️ [React Conf](https://www.youtube.com/playlist?list=PLPxbbTqCLbGHPxZpw4xj_Wwg8-fdNxJRh) 18 | 19 | Videos from the conference are up. 🙌 20 | 21 | ### ⚛️ [React Advanced](https://www.youtube.com/watch?v=q6TD3PvmQts) 22 | 23 | Catch the recorded live stream. 📹 24 | 25 | ### ⚛️ [Concurrent Mode docs](https://reactjs.org/docs/concurrent-mode-intro.html) (Experimental ⚡️) 26 | 27 | Concurrent Mode is a set of new features that help React apps stay responsive and gracefully adjust to the user’s device capabilities and network speed. 28 | 29 | ``` 30 | ReactDOM.createRoot(rootNode).render(); 31 | ``` 32 | 33 | ### ⚛️ [React 16.11.0](https://github.com/facebook/react/blob/master/CHANGELOG.md#16110-october-22-2019) 34 | 35 | - Fix mouseenter handlers from firing twice inside nested React containers. 36 | - Remove unstable_createRoot and unstable_createSyncRoot experimental APIs. (These are available in the Experimental channel as createRoot and createSyncRoot.) 37 | 38 | ### 😭 Formik [v2](https://github.com/jaredpalmer/formik/releases/tag/v2.0.1) 39 | 40 | Your favourite form library, now built with hooks! 41 | 42 | ### 💐 react-beautiful-dnd [v12.0.0](https://github.com/atlassian/react-beautiful-dnd/releases/tag/v12.0.0) 43 | 44 | - 👾 Virtual list support: unlocking 10,000 items @ 60fps 45 | - 🎮 Sensor API enabling any input + scripted experiences 46 | 47 | ### 📕 Interesting reads 48 | - [Learn React in 10 Tweets with Hooks](https://dev.to/chrisachard/learn-react-in-10-tweets-with-hooks-59bc) 49 | - [19 Takeaways From React Conf 2019](https://blog.anthonymorris.dev/19-takeaways-from-react-conf-2019) 50 | - [Portals with Context](https://reacttraining.com/blog/portals-with-context/) 51 | - [ReactiveConf 2019 - Mark Dalgleish: Rethinking Design Practices](https://www.youtube.com/watch?v=jnV1u67_yVg) 52 | 53 | ### 🛠 New tools 54 | - [Tina CMS](https://tinacms.org/) - Open-source site editing toolkit for React-based frameworks — Gatsby & Next.js 55 | - [Divjoy](https://divjoy.com/) - React codebase generator with common building blocks 56 | - [BuilderX](https://builderx.io/) - Browser based design tool that codes React 57 | Native & React for you 58 | - [Reakit](https://reakit.io/) - Build accessible rich web apps with React 59 | -------------------------------------------------------------------------------- /content/meetups/5.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2019-12-05 3 | calendarLink: https://calendar.google.com/event?action=TEMPLATE&tmeid=YjlpbGwzcWI3Z2llbXY4cmdlOWIyMHZtdjAgaDBhZDI1Y3JoOTRtb2hxOTJoMGZ2dG4zY2dAZw&tmsrc=h0ad25crh94mohq92h0fvtn3cg%40group.calendar.google.com 4 | issueLink: https://github.com/react-knowledgeable/events/issues/5 5 | venue: Stripe 6 | venueLogo: https://cdn.worldvectorlogo.com/logos/stripe-4.svg 7 | venueAddress: Stripe SG, 60 Anson Rd, 05-01 Mapletree Anson, Singapore 079914 8 | venueAddressLink: https://www.google.com/maps/place/Stripe+Singapore/@1.274935,103.8431229,17z/data=!3m1!4b1!4m5!3m4!1s0x31da1913a4dcc0ff:0x984d01363a72b9a7!8m2!3d1.274935!4d103.8453116 9 | sponsors: 10 | - sponsor: Gatsby 11 | sponsorLogo: https://www.gatsbyjs.org/Gatsby-Logo.svg 12 | sponsorLink: https://www.gatsbyjs.org/ 13 | title: '' 14 | talks: 15 | - 30 16 | - 29 17 | - 31 18 | - 32 19 | - 33 20 | - 34 21 | - 38 22 | --- 23 | 24 | ## ⚛️ React updates ⚛️ 25 | -------------------------------------------------------------------------------- /content/meetups/6.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2020-01-09 3 | issueLink: https://github.com/react-knowledgeable/events/issues/6 4 | venue: 90Seconds 5 | calendarLink: https://calendar.google.com/event?action=TEMPLATE&tmeid=MTYybWpxODNvbjAwM2R0M25xOG51dGtxaHIgaDBhZDI1Y3JoOTRtb2hxOTJoMGZ2dG4zY2dAZw&tmsrc=h0ad25crh94mohq92h0fvtn3cg%40group.calendar.google.com 6 | venueLogo: https://res.cloudinary.com/ninety-seconds/image/upload/c_thumb,fl_lossy,fl_progressive/v1/-logos-2019/logo-90-black 7 | venueAddress: 90 Seconds, 158 Cecil St #03-01 Singapore 069545 8 | venueAddressLink: https://goo.gl/maps/NQHAbU2RAPdc7hZL9 9 | sponsors: 10 | - sponsor: NodeFlair 11 | sponsorLogo: https://www.nodeflair.com/wp-content/uploads/2018/04/NodeFlair_Full.png 12 | sponsorLink: https://www.nodeflair.com/ 13 | - sponsor: 90Seconds 14 | sponsorLogo: https://res.cloudinary.com/ninety-seconds/image/upload/c_thumb,fl_lossy,fl_progressive/v1/-logos-2019/logo-90-black 15 | sponsorLink: https://90seconds.com/ 16 | title: '' 17 | talks: 18 | - 36 19 | - 40 20 | - 41 21 | --- 22 | 23 | ## Agenda 24 | 25 | - Talks 26 | - RK Game: Two People Are Lying 27 | - Night snack (free join) 28 | 29 | ## Two People Are Lying 30 | 31 | - 1 out of group of 3 will have special intelligence about _an obscure term_ 32 | - 1 host to lead the conversations, audience will join Q&A 33 | - we try to guess who has the intelligence 34 | - [Matt and Tom](https://www.youtube.com/watch?v=3UAOs9B9UH8) and friends playing the game 35 | -------------------------------------------------------------------------------- /content/meetups/7.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2020-02-06 3 | issueLink: https://github.com/react-knowledgeable/events/issues/7 4 | calendarLink: https://calendar.google.com/event?action=TEMPLATE&tmeid=Mm90YnE5MGExbThwcnM3bTkyaDk1bDh2bzkgaDBhZDI1Y3JoOTRtb2hxOTJoMGZ2dG4zY2dAZw&tmsrc=h0ad25crh94mohq92h0fvtn3cg%40group.calendar.google.com 5 | title: '' 6 | --- 7 | 8 | ## ## `` this month 9 | 10 | This month, after [the Singapore edition of Global Diversity CFP Day](https://www.globaldiversitycfpday.com/events/233), we'll do a **CFP Special Edition** for February! This will also be the first chance to get the newest **(y)ear of the mouse** limited edition speaker sticker :) 11 | 12 | ### 📝 CFP special edition special proposals 13 | 14 | CFP stands for "call for proposals" and is a typical procedure adopted by conferences and meetups to ask people submit for talks. 15 | 16 | The goal of this special edition is **to think about, practice, and inspire** your potential conference talk / proposals. _Note that you don't have to be sure that you will absolutely submit this proposal to any conference yet_, nor do you have to be completely comfortable talking about it. The focus of this event is more on exploring the possibilities and to have other participants toss out ideas for inspirations. 17 | 18 | So this month, instead of submitting lightning talks, we ask that you submit _an intro to your talk_ where you talk about: 19 | 20 | - what would you like to talk about 21 | - what got you hooked up by this subject 22 | - what have you done to explore this subject 23 | - any difficulties you've encountered 24 | - any dramas that happened 25 | - what is the most interesting matter about this topic 26 | 27 | If you already have thoughts about how you will structure your talk, please do not hesitate to share with us: 28 | 29 | - how do you want your talk to progress 30 | - what do you want your audience to take home with 31 | 32 | In addition, you may also choose to include: 33 | 34 | - what is the conference(s) you'd like to submit this talk for 35 | - anything special about this conference 36 | - any previous talks that are interesting or made you consider going to this conference 37 | - where does this conference take place and anything interesting about this place 38 | 39 | To propose your special edition CFP talk, [create an issue here](https://github.com/react-knowledgeable/talks/issues/new?assignees=&labels=event&template=event.md&title=%3CRK+%2F%3E+%23+-+date) and reference `react-knowledgeable/events#7` (this issue). We'll reference your talk under this issue once we confirm with your schedule. 40 | 41 | ### 🙋🏻‍♀️ CFP special edition special activities 42 | 43 | After each talk, we'll go two rounds of brainstorms: 44 | 45 | - anybody in this room who has any knowledge about your subject matter 46 | - anybody who has any personal stories to share about this topic 47 | 48 | The goal of these two rounds of brainstorms is to help add inspirations to your talk. 49 | 50 | ### 🕹 CFP special edition special game 51 | 52 | We'll play [PowerPoint Karaoke](https://en.wikipedia.org/wiki/PowerPoint_Karaoke) as the second half of the event. We'll do an RK variant which potentially has more focus on the React ecosystem. 53 | 54 | Note that you will see the decks as you start speaking. The goal of this game is to practice public speaking skills. And in particular, your **improvisational and coming up with nonsense skills**. 55 | 56 | Special thanks to @yishus, @thchia, @KenLSM, @wgao19 for donating decks. If you are interested in donating decks for this game, please contact us in private (DM us on [reknowledgeable](https://twitter.com/reknowledgeable)). 57 | 58 | ## Participating 59 | 60 | ### CFP proposals 61 | 62 | To propose your special edition CFP talk, [create an issue here](https://github.com/react-knowledgeable/talks/issues/new?assignees=&labels=event&template=event.md&title=%3CRK+%2F%3E+%23+-+date) and reference `react-knowledgeable/events#7` (this issue) 63 | 64 | ### RK Karaoke signups 65 | 66 | To indicate your participation at RK Karaoke, please _comment in this issue below_ with: 67 | 68 | - full name 69 | - GitHub handle (please [RSVP here](https://reactknowledgeable.org/meetups/7/)) 70 | - [x] this will be my first time doing a public speaking 71 | - [x] I am happy to have this talk recorded by @engineersftw (by default, we record talks to be accessible by more audience, if you don't want, please uncheck this) 72 | -------------------------------------------------------------------------------- /content/speakers/crabbie.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Crabbie Rust 3 | twitter: reknowledgeable 4 | website: https://react-knowledgeable.netlify.com 5 | intro: Crabbie is the lord of walking sideways in the sea. 6 | --- -------------------------------------------------------------------------------- /content/speakers/wei.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Wei 3 | twitter: wgao19 4 | website: https://wgao19.cc, 5 | intro: Wei considers herself a work in progress React web developer. 6 | --- -------------------------------------------------------------------------------- /content/stories/baby-react-knowledgeable-is-born.md: -------------------------------------------------------------------------------- 1 | --- 2 | speaker: wei 3 | title: Baby React Knowledgeable is Born 4 | date: 2019-07-07 5 | --- 6 | 7 | `` is built with a lot of fun and love. It has been [a React podium where no one speaks about React 🤦🏻‍♀️](https://github.com/react-knowledgeable/talks/issues/4) (but we'll fix that). And it's been more... 8 | 9 | 10 | 11 | `` started as a weekly sharing in my company's React team. With our thirty and growing developers, we have been running for [36 weeks](https://github.com/Shopee/react-knowledgeable/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aclosed+label%3Aweekly) (as of July 2019), delivered [50+ talks](https://github.com/Shopee/react-knowledgeable/issues?utf8=%E2%9C%93&q=is%3Aclosed+label%3Atalk+) by more than 20 speakers, 6 of us have spoken at a local meetup this year, and some of us will start speaking at conferences later this year. 12 | 13 | Most of our developers were previously not very involved in [our local tech scope](https://engineers.sg/). To be honest, none of us had any prior public speaking experience to begin with and so you may wonder, what brought us doing `` now and what do we plan on doing for the future? 14 | 15 | Well, we started doing a weekly sharing because things we learn and problems we solve are shiny interesting and we need to tell others about it. Some of us who were more comfortable speaking started giving talks and even series of talks that could connect to a mini course and we (I) call him professor now. Then a few more people would give speaking a try. And we realize that as we prepare for talks, the need to “teach” pushed us to dive deeper into the subjects and we ended up learning more about them. Some of us have become the go-to person in our team in some fields. I think it is fair to say that having a well-organized talk series inside our team is like a magic podium that uplifted the career trajectory for a lot of us, and it has completely changed mine. 16 | 17 | If you were with us at ReactJS meetup last month, and happened to have arrived earlier, you may have seen [@swyx](https://twitter.com/swyx/) giving a [talk](https://www.youtube.com/watch?v=-f-rZepNKW0) on [#learnInPublic](https://twitter.com/hashtag/LearnInPublic). While at `` what we have is a podium, but what we really want to do is to get better together at whatever we are doing, and to share with others. Because sharing is caring, and sharing is also a best way to learn. So we'd like to pass on the spirit of learning in public, and create this lovely vibe in this town, more experts in more topics, more speakers, and, you know, love of React. Shawn doesn't know it, but his talk spawned 5 new blogs to my knowledge alone. And so we cannot keep this to ourselves, ( ... 18 | 19 | So here's the plan, we'll start doing a lightning talk series with RK. We'll do 4 ~ 5 lightnings with no Q&A attached, but with a networking break in between. Lightning talks are fun and compact. Here is an awesome lightning talk that you absolutely have to check out: [⚡️ - Andres Suarez - Moving Fast with Nuclide and Flow - React Conf 2017](https://www.youtube.com/watch?v=WRyk5ZVklFs). At 30 seconds the guy has a slide that says "DEMO". 20 | 21 | We'll pace our events out with our lovely brother meetup [ReactJS Singapore](https://www.meetup.com/React-Singapore/), so hopefully we'll have one React meetup once every other week? We're looking at a first meetup event on Aug 6, the Tuesday in two weeks, before the national holiday. We still got 2 spots for lightning, so grab them before they're filled. 22 | 23 | Here's how you can reach us: 24 | 25 | - Twitter [@reknowledgeable](https://twitter.com/reknowledgeable) 26 | - GitHub repo for [talks](https://www.meetup.com/React-Singapore/), [community site](https://github.com/react-knowledgeable/rk-community-site/) -------------------------------------------------------------------------------- /content/stories/images/penang.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/content/stories/images/penang.jpg -------------------------------------------------------------------------------- /content/stories/images/rk-bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/content/stories/images/rk-bug.png -------------------------------------------------------------------------------- /content/stories/images/rk-draw-out-loud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/content/stories/images/rk-draw-out-loud.png -------------------------------------------------------------------------------- /content/stories/images/rk-learning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/content/stories/images/rk-learning.png -------------------------------------------------------------------------------- /content/stories/images/rk-react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/content/stories/images/rk-react.png -------------------------------------------------------------------------------- /content/stories/images/rk-shoutouts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/content/stories/images/rk-shoutouts.png -------------------------------------------------------------------------------- /content/stories/images/rk-speaker-slide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/content/stories/images/rk-speaker-slide.png -------------------------------------------------------------------------------- /content/stories/images/rk-what-is.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/content/stories/images/rk-what-is.png -------------------------------------------------------------------------------- /content/stories/images/rk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/content/stories/images/rk.png -------------------------------------------------------------------------------- /content/stories/introducing-rk-lightning-to-this-town.md: -------------------------------------------------------------------------------- 1 | --- 2 | speaker: wei 3 | title: Introducing RK⚡️ to this Town 4 | date: 2019-07-25 5 | cover: './images/rk-speaker-slide.png' 6 | --- 7 | 8 | Me and [two](https://twitter.com/yishusee/) [more](https://twitter.com/kenleesm) RK kids went to [ReactJS Singapore July 2019 Edition](https://www.meetup.com/React-Singapore/events/260564102) to introduce `` to this town today. 9 | 10 | 11 | 12 | So we're starting `` in Singapore. Since we're an infantry meetup and people don't know about us, we figure we'd run around meetups to tell people about it. Normally how it goes is that most meetups here in Singapore has an announcement section at the end of each event. So that'll be what we aim at. 13 | 14 | As a side track, I took a break a couple of weeks ago where I visited Penang with [Xinling](https://twitter.com/helloxinling), a designer from our team. This girl has been my moral support all along. She's always very delightful and that matched the suns and the chills in Penang. 15 | 16 | ![my penang trip](./images/penang.jpg) 17 | 18 | On the last day of our trip, I was telling her that I'd be introducing RK to this town and she agreed to hear my talk and to give feedback. But, as the theory goes – first time rehearsing a talk always goes disastrous – that ended up me wanting to bury my face in my flat white after babbling five minutes of nonsense. 19 | 20 | As a designer Xinling is constantly drawing. And as a not-very-visual person I got affected by her dedication. She was drawing a postcard out of a photo she took in a street of Penang. I requested that I contribute to it so she allowed me to plaid one of the fillings. And it didn't go too bad (how bad can a plaiding go anyway). Before our flight she was drawing another card for her mom. Dedication is infectious, really. So I started drawing with my iPad as well. 21 | 22 | I could not get RK out of my mind after running the talk for a first time with her. So I started doodling RK. How can a non-visual person "doodle" RK? Well, I guess just write it out... 23 | 24 | ![React Knowledgeable](./images/rk.png) 25 | 26 | Then the next slide I drew was really very amateurish. Basically I just drew-out-loud what I thought of. 27 | 28 | ![draw out loud whats happening with RK](./images/rk-draw-out-loud.png) 29 | 30 | We boarded our flight back to Singapore. For once in my lifetime I dedicated my whole flight to one single task that got my full attention. And so the headline of RK ended up looking like this, it has its new logo designed by my friend [Huijing](https://twitter.com/hj_chen), and a line that says what we love about RK: 31 | 32 | ![what is rk](./images/rk-what-is.png) 33 | 34 | I was thinking about what I wanted to say about RK. I have so much to say and doodles just came out one after another. This bug, for instance. I was intended to say that "bugs fit well into a lightning talk, you get technical quickly, _and they are great for storytelling_". But you all know now that I forgot the last pitch loudly. Life `¯\_(ツ)_/¯`. 35 | 36 | ![bug](./images/rk-bug.png) 37 | 38 | Then this next slide about speaking and learning is subtly mocking Flow. If you were at [my talk last month about Flow](https://uuei.io/talks/flow-be-happy/), you know what I'm talking about. 39 | 40 | ![learning](./images/rk-learning.png) 41 | 42 | 43 | The React logo seemed not so hard -- until I tried. You need to get the angle right. That was like some hundred times of drawing skinny circles: 44 | 45 | ![react logo](./images/rk-react.png) 46 | 47 | Now here comes my favorite one: the RK speaker slide! That is _not_ the RK speaker sticker, by the way. The real RK speaker sticker – you'll only know when we launch :] But hopefully this one is cute enough as a mascot for RK? 48 | 49 | ![speaker sticker](./images/rk-speaker-slide.png) 50 | 51 | For the recent half a year getting involved with the local tech meetups, I feel gratefully accepted by the amazing communities and friends we have here. Shouting outs to [SingaporeCSS](https://singaporecss.github.io/) and [React Singapore](https://www.meetup.com/React-Singapore/) meetups, both of who have been of tremendous support to get `` going in town. 52 | 53 | `oembed: https://twitter.com/SingaporeCSS/status/1152120843142516736?s=20` 54 | 55 | ![shouting outs to singapore css and reactjs meetup](./images/rk-shoutouts.png) 56 | 57 | That roughly summarizes my slides. And now that I have this deck, it all became natural to me that I'd do this as a lightning talk. We're about to run a meetup solely on lightning talks so why not. If you were here at ReactJS meetup tonight, you've seen it all. It's far from perfect. I dry ran this a few more times yesterday and today. I squeezed one more in on our way there. Truth be told, even my co-organizer [Ken](https://twitter.com/kenleesm) agreed that they all went disastrous 😅 But I'm really very grateful that he didn't tell me until _after_ the actual talk, which went alright, I guess. 58 | 59 | A lot of people like the slides I doodled and some asked about the tools I used creating those slides. It's actually not a tool for slides, it's a drawing tool called [Paper](https://www.fiftythree.com/). But it worked out well for these slides and I had a lot of fun drawing them! If you like the slides, [here](https://noti.st/wgao19/0zB2FW/introducing-react-knowledgeable) is the notist page for this presentation where you can find all the slides :) 60 | -------------------------------------------------------------------------------- /content/stories/recap-2/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | speaker: wei 3 | title: Recap RK Lightning 2 4 | date: 2019-09-10 5 | cover: ./rk-what-are-you-learning-this-week.png 6 | --- 7 | 8 | Last Thursday, we had our second ever RK Lightning event at [HackerspaceSG](https://hackerspace.sg/) 🎉. Here's Wei's recap 👩🏻‍🌾 9 | 10 | 11 | 12 | 13 | ## Talks 14 | 15 | ### 💄 Build a Gatsby Theme and publish [#13](https://github.com/react-knowledgeable/react-knowledgeable-talks/issues/13) 16 | 17 | [Raj](https://mobile.twitter.com/email2vimalraj) kicked off the lightning talks with his second live demo with Gatsby, this time building a [Gatsby Theme](https://www.gatsbyjs.org/docs/themes/what-are-gatsby-themes/) of a site with a like button. What is your one liner for Gatsby Themes? Secretly, I called them partials. After last Thursday's talk, I think of them as a way to communicate with common features via a version number now. 18 | 19 | `twitter: https://twitter.com/reknowledgeable/status/1169578211249815552?s=20` 20 | 21 | - [slides](https://github.com/email2vimalraj/gatsby-theme-like-post/blob/master/build-gatsby-theme-talk.key) 22 | - [demo](https://github.com/email2vimalraj/gatsby-theme-like-post) 23 | - [video](https://engineers.sg/v/3638) 24 | 25 | ### 👞 Dancing with React Hooks [#2](https://github.com/react-knowledgeable/react-knowledgeable-talks/issues/2) 26 | 27 | Next, we had our most magical [Van](https://mobile.twitter.com/bokukage) to talk about what she learned about hooks by creating those little dancers with funny walk moves on the screen. Joyfully surprising everybody she demoed the moon walk 😂 The characters she created in her stage have exactly her style and that leads to her other talk at [SingaporeCSS](https://singaporecss.github.io/), [The Joy of Doing Things without the Need for Justification](https://smokinclove.github.io/the-joy-of-doing-things-without-the-need-for-justification/) - (oh look at her newest avatar, it has her MJ hat now!) For this talk, she then dived into what she learned about hooks, how to make setInterval and useEffect have peace, and her take on understanding hooks. 28 | 29 | `twitter: https://twitter.com/reknowledgeable/status/1169582223726501889` 30 | 31 | - [slides](https://docs.google.com/presentation/d/1mrGSHBNYoUlMYrOWZ6BMiJ4rCvfJqIq1XgTuPkePkkM/edit?usp=sharing) 32 | - [video](https://engineers.sg/video/dancing-with-react-hooks-react-knowledgeable--3637) 33 | 34 | We took a question break. I had a nice conversation with [Yangshun](https://twitter.com/yangshunz), who has me for [Docusaurus](https://docusaurus.io/) but it was actually the first time we met in person! The question break also featured popcorns popped by [Valentine](https://twitter.com/valentinechua) from Hackerspace our host, and stickers exchange! 35 | 36 | ### 🦖 How Modern Static Site Generators Work [#11](https://github.com/react-knowledgeable/react-knowledgeable-talks/issues/11) 37 | 38 | [Yangshun](https://twitter.com/yangshunz) talked about how modern static site generators are built. They share some intrinsic similarities with each other, and they differ from traditional ones. It seems that Yangshun has learned those by building [Docusaurus 2](https://docusaurus-2.netlify.com/) 😉 39 | 40 | - [slides](https://github.com/react-knowledgeable/react-knowledgeable-talks/files/3584661/React.Knowledgeable.-.How.Modern.Static.Site.Generators.Work.pdf) 41 | - video (to be updated) 42 | 43 | `twitter: https://twitter.com/reknowledgeable/status/1169587281411207169?s=20` 44 | 45 | ### 👥 Are React and CSS Friends? [#14](https://github.com/react-knowledgeable/react-knowledgeable-talks/issues/14) 46 | 47 | Then, I shared about styling sites with React, how React changes the way we write styles, and a mind model that makes sense for me to style my projects, including [our site](https://reactknowledgeable.org/). 48 | 49 | - [slides](https://uuei.io/talks/cream-pencil-crayon/) 50 | - [video](https://engineers.sg/v/3640) 51 | 52 | ### 🤕 Battle Stories: Portals [#16](https://github.com/react-knowledgeable/react-knowledgeable-talks/issues/16) 53 | 54 | Then finally, Thomas took up the last spot (15 mins before 9!) and shared a problem he encountered – communicating styles between page and iframe embedded modal. 55 | 56 | - [video](https://engineers.sg/v/3639) 57 | 58 | All videos are courtesy of the worldclassly [engineers.sg](https://engineers.sg/), [we will never stop getting amazed](https://twitter.com/swyx/status/1169640745604714496?s=20). 59 | 60 | ### 🤞 Till next time 61 | 62 | Our night snack was indian food at ABC, fun promised, our tables were tilted this time! 63 | 64 | RK is a fun and friendly podium to share what we learn about React. The best way to participate is to [speak at RK](https://github.com/react-knowledgeable/react-knowledgeable-talks/issues), share with us what is sparkling interesting to you. Hope to _hear from_ you next month! 65 | 66 | `twitter: https://twitter.com/wgao19/status/1169636723573190656?s=20` 67 | 68 | ## React updates of the month 69 | 70 | ### ⚛️ [React 16.9 is out](https://reactjs.org/blog/2019/08/08/react-v16.9.0.html) 71 | 72 | - more UNSAFE_ lifecycle methods 73 | - deprecated unheardof stuff 74 | - acync act() for testing 75 | - Performance Measurements with 76 | - need to wait longer for a combined release of concurrent mode + suspense for data 77 | fetching `¯\_(ツ)_/¯` i am not even surprised 78 | 79 | ### 🛠 [New DevTools](https://reactjs.org/blog/2019/08/15/new-react-devtools.html) 80 | 81 | - [changelog](https://github.com/facebook/react/blob/master/packages/react-devtools/CHANGELOG.md#400-august-15-2019) 82 | - [interactive tutorial](https://react-devtools-tutorial.now.sh/) 83 | 84 | My friend Nut doesn't like it because it no longer has the very reactive re-render component highlight. Although the "why my component rerenders" under profiler tab looks really shiok. 85 | 86 | ### 🥯 Flow v0.106 [Coming Soon: Changes to Object Spreads](https://medium.com/flow-type/coming-soon-changes-to-object-spreads-73204aef84e1) 87 | 88 | - the current model is based on an assumption that inexact object types do not specify own-ness, this makes properties from spread become optional because object spread at run time copies only _own_ properties 89 | - the new model assumes inexact object types specify own-ness on specified properties, therefore following our intuition of object spread more closely 90 | - inexact objects _may_ contain more properties that may overwrite existing properties in spread target 91 | - the new model will err, tell us what happens, and ask if we can make the spreaded object exact 92 | 93 | I got involved with a twitter thread the other day. There was some voice saying Flow is dead. Flow is _not_ dead my lovely people :) Flow is happily wedded with React. They live under the same household, and guess who gets to officially [support React v16.9 Profiler](https://github.com/facebook/flow/blob/master/tests/react_16_9/profiler.js) first? 94 | -------------------------------------------------------------------------------- /content/stories/recap-2/rk-what-are-you-learning-this-week.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/content/stories/recap-2/rk-what-are-you-learning-this-week.png -------------------------------------------------------------------------------- /content/stories/recap-rk-2019.md: -------------------------------------------------------------------------------- 1 | --- 2 | speaker: wei 3 | title: Year 2019 with RK 4 | date: 2020-01-09 5 | --- 6 | 7 | This week marks the 60th week of [*RK Originals*](https://github.com/Shopee/shopee-react-knowledgeable) and the 6th month of [*RK Lightning Singapore*](https://reactknowledgeable.org/) the meetup. Excuse us for the confusions it causes. I want to ask a potentially provoking question: 8 | 9 | > What do you want to get out of going to a meetup? 10 | 11 | You may want to learn about the technology. Free food is nice. And why not go meet some new friends? 12 | 13 | --- 14 | 15 | My first college math professor had a "weird" homework consultation policy. For normal problems, you can discuss with any classmates, but for *extra credit* problems, the only person you can turn to help for is the professor himself. Of course this is based on an honesty system but the rule is the rule. 16 | 17 | Then when you go to him for help, he'll do only one thing. He'll just ask, "What's your progress?" Then you start your explaining. If you're on the right track, he'll let you continue. If he sees you deviate, however, he'll ask you to explain more. 18 | 19 | This is when you realize that something may have been wrong. Because chances are, you can't explain. He seems to possess both the patience and the cavalier to never let out any hints. But it's exactly his "not helpful" that makes sure *he never spoils your pleasure of finding things out*. 20 | 21 | That professor defined my college experience. When I claim the main body of my learning journey, I gain unparalleled joy of finding things out. My favorite learning materials are inspirational rather than instructional, its educational value has its limit if all it does is to tell me how to do things. 22 | 23 | 24 | --- 25 | 26 | Frankly, I never really had the motivation to go to meetups until I began running RK. I don't like lectures and I'm particularly flawed in peopling. I went to [Super Silly Hackathon](https://supersillyhackathon.sg/) last year in hope to learn what a tech event is like, followed by [Global Diversity CFP Day](https://www.globaldiversitycfpday.com/), where I met the most amazing friend ever, [Huijing](https://www.chenhuijing.com/). Later this year we went to an incredible number of meetups, conferences, ramens and dumplings together. And the two meetups that we run are now best friend meetups, yes meetups also got frens yo. 27 | 28 | Huijing knows on a Singapore and a 4-year scale that it is hard to find speakers. I know it on a weekly clock and it's damn stressful sia. In retro, *RK Originals* now has 90 talks over 60 weeks in its back. If I thought about this set of numbers when I proposed it (1~2 talks per week by proposals), I would have probably dropped the idea immediately. So sometimes it is good to be not very smart to foresee the impossible, i.e., we don't have many people, we Asians, we no experience in speaking, life damn hard eh. 29 | 30 | Despite being a math major, numbers are also not my thing. So I am the most grateful that Shopee's tech leaders have given it the most freedom it could ever have. There's no KPI whatsoever associated with this podium at all, there still isn't. And the leaders respect and support the public meetup as well. But the further I go the more I am in awe of the 1-hour of faith this team of 40 (and counting up) amazing engineers put in this podium. 31 | 32 | So is it worth it? Why RK? Why every week / month? Why must constantly poke you all to speak? 33 | 34 | --- 35 | 36 | In my third year of college, while I was spamming the "whats your progress" thingy on the most ubiquitous animal in my major -- smart guys, I was also working at a learning center where, instead of having us help students who were taking the classes we took before, it actually let us help students who were _taking the same classes with us_. This is where sharing my learning process turned out to help me. By explaining my the problems over and over again, _I_ get a much refined understanding myself. 37 | 38 | There's a [#learnInPublic](https://twitter.com/hashtag/learninpublic) hashtag where one of our friends, [swyx](https://twitter.com/swyx), is a major advocate behind its recent upbeats. RK will repeatedly share its taste in this guiding principle because, as Professor Feynman has also said, *teaching is the best way to learn*. 39 | 40 | --- 41 | 42 | The podium *shines* when it is picked up by a first-time speaker, or someone who rarely speaks up in the team, or someone sees something so interesting that she absolutely has to share it. Be it initializing a new life experience, providing a stage for the rarely-heard-from, this podium has those "extra" meanings which now is an essential existence that I believe every team must possess. 43 | 44 | By running this podium I virtually encounter all talks more than once. It's the most humbling experience I've ever had because without this podium I would have never known that we have [Van](https://twitter.com/bokukage) who [masters drawing with CSS](https://smokinclove.github.io/writeups/a-tale-of-css-drawings/), [Lihau](https://twitter.com/lihautan) who is an expert in a spectrum of subjects that seems unreal as someone who works near me, and many more who prefer not to be in the public. The best content is right near me. 45 | 46 | I mean, conference talks are certainly great — they're impeccable performances, extremely well polished, speakers look more noble in front of hundreds of people. But so as great are internal sharing talks — the problems are complex but we share the same context to absorb them quickly, the talks are less polished but full of true gems in content, speakers sit right next to me at work every day. Never in my life have I had such a humbling year and the strikes are on a weekly basis and I need to travel only four floors. 47 | 48 | And, if you know our internal RK and know me as a person behind it, you know that at least half of my brain is full of craps. Is RK suspiciously a release of my accumulated nonsenses throughout the week? I don't know. But it'd be my crowning achievement if I successfully make us laugh, lol. Writing bugs is hard, have some fun yo. 49 | 50 | It's a gift if you can *always* enjoy coding and constantly sharpening your skills. Not many people have it. That is why I see the fun part the most important because fun sparks joy, it brings me back, it spirals for refinement. Nothing beats having a fun career. 51 | 52 | 53 | 54 | --- 55 | 56 | I'll end this with what *I* get out of. I get *the most* out of it. I've attracted some attention in this local community. I've found at least part of my value to my team — I've built something that makes my team a lovelier one. I've given a conference talk. I've met so many friends. I've formed an incredibly effective, long-term collaboration with Ken, then adding in a few more RK kids. I've learned knowledge and lessons. I've tried things out. 57 | 58 | So, sun eclipsing, Switch store queueing, kite, bui kee and pigeon flying, you have me behind RK, and we want you behind the podium :) 59 | -------------------------------------------------------------------------------- /content/stories/rk-is-1yo.md: -------------------------------------------------------------------------------- 1 | --- 2 | speaker: wei 3 | title: RK Originals is 1 Year Old 🥳 4 | date: 2019-10-05 5 | --- 6 | 7 | The "Originals" chapter of React Knowledgeable is 1 year old! 8 | 9 | 10 | 11 | This week, I got introduced to our new team members as "the girl behind RK". And I got people talk to me explicitly to comment on how awesome they think RK is. It's like a week of packed complements that I'm not sure I'm ready to take. It just so happened that this Saturday, Oct 5, is the 1-year anniversary for the original (Shopee) chapter of RK. So I'll shamelessly take all complements as birthday presents to this baby. 12 | 13 | Meanwhile, I need to make sure everyone who bugs me about RK will also bug [Ken](https://twitter.com/kenleesm). Because Ken is the true fine geek behind all the shiny parts of RK. There's no RK without Ken. 14 | 15 | Also RK has recently taken on a ninja fun look which seems incredibly great match with [Thomas](https://twitter.com/th_chia). You should totally come to our next meetup if you've never met him (which is wroooooong and needsfix). 16 | 17 | And I also hope that [Jennie](https://twitter.com/jyee721) will rephrase the intro as _a_ girl behind RK and not _the_ girl behind RK because apparently she's contributing more than she realizes. And we have [Yishu](https://github.com/yishus), plus one ninja fun and puts us on a superb gender balance. 18 | 19 | The Singapore chapter of RK relies on many pairs of hands roughly led by [Huijing](https://twitter.com/hj_chen/), who prefers not to be on the roster but has been supporting us all the way. Bey timer will be her constant precense, so it is with our logo, our website, stickers, and all fine look that RK has. She's probably gonna make sure we look greaaaaaaaaaat inside out. And, please keep supplying the term we steal too :] 20 | 21 | And we have received so much support from the local community, [ReactJS](https://www.meetup.com/React-Singapore/), [SingaporeCSS](https://singaporecss.github.io/), [SingaporeJS](https://github.com/SingaporeJS/talk.js), [Engineers.SG](https://engineers.sg/), as well as the companies who hosted us, starting from [Carousell](https://sg.carousell.com/), [Hackerspace](https://hackerspace.sg/), [SP Digital](https://blog.spdigital.io/), and [GovTech](https://www.tech.gov.sg/) Hive down the pipeline and potentially [Stripe](https://stripe.com/) in Dec. And gratitudes also go to all the fine ladies and gentlemen who have put in blind faith in us and supported our presence. 22 | 23 | Nothing can express our appreciation to all the speakers who have presented great content at RK. All we promise is that you'll always have us behind this podium, hopefully your fun and friendly companion to your journey as a React developer. 24 | -------------------------------------------------------------------------------- /content/stories/rk-will-close-meetup-dot-com-group-soon.md: -------------------------------------------------------------------------------- 1 | --- 2 | speaker: wei 3 | title: RK Will Close Meetup.com Group Soon 4 | date: 2019-12-07 5 | --- 6 | 7 | Hello RK friends, 8 | 9 | We are closing this meetup group within a month. In the future, please use our website (https://reactknowledgeable.org/) as home base for any updates and RSVP for events. And the best way to reach out to us is via twitter @reknowledgeable. 10 | 11 | Our RSVP requires that you have a GitHub account, which, as we speak today, is the most common platform that us developers share. We record only the necessary information to run our events. All our code is open sourced (https://github.com/react-knowledgeable/rk-community-site/) and you may review that we're not doing funny things with your information. In the mean time, you are more than welcome to contribute :) 12 | 13 | While we are grateful that many members learned about us via meetup.com, we are moving away because we are wary of meetup.com's payment policy. RK is a community run by volunteer work, it is our responsibility to keep our cost in check. Our main goal is to consistently run this fun & friendly podium to share what we learn as a React developer, we believe we can bring people together without being reliant on specific platform. So, we hope you will still be with us outside of meetup.com, because we are still expecting great talks from all of you. 14 | 15 | _Wei_ from RK -------------------------------------------------------------------------------- /content/talks/how-not-to-get-caught-and-be-eaten.md: -------------------------------------------------------------------------------- 1 | --- 2 | speaker: crabbie 3 | title: How Not to Get Caught and Be Eaten 4 | intro: The human beings like to eat crab too much. We need to change that fact. Otherwise they are gonna keep catching us and steam us and eat us and they even feel good about it. If you are concerned about then endangerment of our species, please come support us. This world is better with your faith. Cheers. 5 | --- 6 | -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom'; 2 | 3 | // https://twitter.com/EphemeralCircle/status/1190670453221842944?s=20 4 | // our own @thchia actually also pointed this out as well 5 | // https://github.com/react-knowledgeable/rk-community-site/issues/70#issuecomment-549008052 6 | // took me much more hassle to figure this, apologize for my silliness 7 | export const replaceHydrateFunction = () => { 8 | return (element, container, callback) => { 9 | ReactDOM.createRoot(container, { 10 | hydrate: true, 11 | hydrationOptions: { onHydrated: callback }, 12 | }).render(element); 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | 3 | module.exports = { 4 | pathPrefix: '/', 5 | siteMetadata: { 6 | title: 'React Knowledgeable', 7 | titleTemplate: 8 | '%s · Fun and friendly podium to share what we learn about React.', 9 | description: 10 | 'React Knowledgeable is a fun and friendly podium to share what we learn about React.', 11 | url: 'https://reactknowledgeable.org', // No trailing slash allowed! 12 | image: '/logo.png', // Path to your image you placed in the 'static' folder 13 | twitter: 'reknowledgeable', 14 | footerLinks: [ 15 | { 16 | name: 'SingaporeCSS', 17 | link: 'https://singaporecss.github.io', 18 | }, 19 | { 20 | name: 'SingaporeJS', 21 | link: 'https://www.singaporejs.org/talk.js/', 22 | }, 23 | { 24 | name: 'ReactJS Singapore', 25 | link: 'https://www.meetup.com/React-Singapore/', 26 | }, 27 | { 28 | name: 'Engineers SG', 29 | link: 'https://engineers.sg/', 30 | }, 31 | { 32 | name: 'JAMstackSG', 33 | link: 'https://jamstacksingapore.com/', 34 | }, 35 | ], 36 | }, 37 | plugins: [ 38 | { 39 | resolve: `gatsby-plugin-google-analytics`, 40 | options: { 41 | trackingId: 'UA-136098806-2', 42 | }, 43 | }, 44 | `gatsby-plugin-react-helmet`, 45 | { 46 | resolve: `gatsby-plugin-favicon`, 47 | options: { 48 | logo: './static/logo.png', 49 | 50 | // WebApp Manifest Configuration 51 | appName: null, // Inferred with your package.json 52 | appDescription: null, 53 | developerName: null, 54 | developerURL: null, 55 | dir: 'auto', 56 | lang: 'en-US', 57 | background: '#fff', 58 | theme_color: '#fff', 59 | display: 'standalone', 60 | orientation: 'any', 61 | start_url: '/?homescreen=1', 62 | version: '1.0', 63 | 64 | icons: { 65 | android: true, 66 | appleIcon: true, 67 | appleStartup: true, 68 | coast: false, 69 | favicons: true, 70 | firefox: true, 71 | yandex: false, 72 | windows: false, 73 | }, 74 | }, 75 | }, 76 | { 77 | resolve: `gatsby-plugin-sass`, 78 | options: { 79 | implementation: require('sass'), 80 | }, 81 | }, 82 | { 83 | resolve: `gatsby-source-filesystem`, 84 | options: { 85 | name: 'content', 86 | path: `${__dirname}/content/`, 87 | }, 88 | }, 89 | { 90 | resolve: `gatsby-transformer-remark`, 91 | options: { 92 | excerpt_separator: ``, 93 | plugins: [ 94 | { 95 | resolve: `@raae/gatsby-remark-oembed`, 96 | options: { 97 | usePrefix: [`oembed`, `twitter`], 98 | providers: { 99 | include: ['Twitter'], 100 | }, 101 | }, 102 | }, 103 | { 104 | resolve: `gatsby-remark-images`, 105 | options: { 106 | maxWidth: 590, 107 | }, 108 | }, 109 | ], 110 | }, 111 | }, 112 | { 113 | resolve: `gatsby-plugin-typography`, 114 | options: { 115 | pathToConfigModule: `src/utils/typography`, 116 | }, 117 | }, 118 | 'gatsby-plugin-sharp', 119 | 'gatsby-transformer-sharp', 120 | { 121 | resolve: `gatsby-source-graphql`, 122 | options: { 123 | typeName: 'GitHub', 124 | fieldName: 'github', 125 | url: 'https://api.github.com/graphql', 126 | headers: { 127 | Authorization: `bearer ${process.env.GITHUB_TOKEN}`, 128 | }, 129 | fetchOptions: {}, 130 | }, 131 | }, 132 | { 133 | resolve: `gatsby-source-airtable`, 134 | options: { 135 | apiKey: process.env.AIRTABLE_API_KEY, 136 | tables: [ 137 | { 138 | baseId: process.env.AIRTABLE_BASE_ID, 139 | tableName: 'Attendees', 140 | }, 141 | ], 142 | }, 143 | }, 144 | ], 145 | }; 146 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { createFilePath } = require('gatsby-source-filesystem'); 3 | const axios = require('axios') 4 | 5 | // exports.sourceNodes = async ({ actions, reporter, createContentDigest }) => { 6 | // const { createNode } = actions 7 | // const host = process.env.NODE_ENV === 'production' ? `https://reactknowledgeable.org` : `` 8 | // const data = await axios.get(`${host}/.netlify/functions/airtable`) 9 | // if (data.status >= 200 && data.status < 300) { 10 | // data.data.forEach(datum => createNode({ 11 | // ...datum, 12 | // id: `${datum.Name}-${datum["Created Date"]}`, 13 | // parent: null, 14 | // children: [], 15 | // internal: { 16 | // type: "RKAttendee", 17 | // contentDigest: createContentDigest(datum) 18 | // } 19 | // })) 20 | // reporter.success("Retrieved attendee data") 21 | // } else { 22 | // reporter.error("Error encountered retrieving attendees") 23 | // } 24 | // return 25 | // } 26 | 27 | exports.onCreateNode = ({ node, actions, getNode }) => { 28 | const { createNodeField } = actions; 29 | if (node.internal.type === `MarkdownRemark`) { 30 | const value = createFilePath({ node, getNode }); 31 | createNodeField({ 32 | name: `slug`, 33 | node, 34 | value, 35 | }); 36 | } 37 | }; 38 | 39 | exports.createPages = ({ graphql, actions }) => { 40 | const { createPage, createRedirect } = actions; 41 | 42 | createRedirect({ 43 | fromPath: '/story/stories/introducing-rk-lightning-to-this-town/', 44 | toPath: '/stories/introducing-rk-lightning-to-this-town/', 45 | isPermanent: true, 46 | redirectInBrowser: true, 47 | }); 48 | createRedirect({ 49 | fromPath: '/story/stories/baby-react-knowledgeable-is-born/', 50 | toPath: '/stories/baby-react-knowledgeable-is-born/', 51 | isPermanent: true, 52 | redirectInBrowser: true, 53 | }); 54 | 55 | const talkTemplate = path.resolve(`./src/templates/Talk/index.jsx`); 56 | const storyTemplate = path.resolve(`./src/templates/Story/index.jsx`); 57 | const meetupTemplate = path.resolve(`./src/templates/Meetup/index.jsx`); 58 | // const speakerTemplate = path.resolve(`./src/templates/Speaker/index.jsx`); 59 | 60 | return Promise.all([ 61 | graphql( 62 | ` 63 | { 64 | stories: allMarkdownRemark( 65 | filter: { fileAbsolutePath: { regex: "/stories/" } } 66 | ) { 67 | nodes { 68 | fields { 69 | slug 70 | } 71 | } 72 | } 73 | meetups: allMarkdownRemark( 74 | filter: { fileAbsolutePath: { regex: "/meetups/" } } 75 | ) { 76 | nodes { 77 | fields { 78 | slug 79 | } 80 | } 81 | } 82 | } 83 | ` 84 | ).then(result => { 85 | if (result.errors) { 86 | throw result.errors; 87 | } 88 | 89 | // Create blog posts pages. 90 | const { 91 | stories: { nodes: stories }, 92 | meetups: { nodes: meetups }, 93 | } = result.data; 94 | 95 | stories.forEach(story => { 96 | createPage({ 97 | path: `${story.fields.slug}`, 98 | component: storyTemplate, 99 | context: { 100 | slug: story.fields.slug, 101 | }, 102 | }); 103 | }); 104 | meetups.forEach(meetup => { 105 | const id = meetup.fields.slug.replace(/[^\d]+/g, "") // to remove everything except the numbers 106 | createPage({ 107 | path: `${meetup.fields.slug}`, 108 | component: meetupTemplate, 109 | context: { 110 | id, 111 | slug: meetup.fields.slug, 112 | }, 113 | }); 114 | }); 115 | }), 116 | graphql( 117 | ` 118 | { 119 | talks: github { 120 | repository(owner: "react-knowledgeable", name: "talks") { 121 | issues(last: 100, labels: ["talk"]) { 122 | nodes { 123 | number 124 | } 125 | } 126 | } 127 | } 128 | } 129 | ` 130 | ).then(result => { 131 | if (result.errors) { 132 | throw result.errors; 133 | } 134 | 135 | // Create blog posts pages. 136 | const { 137 | talks: { 138 | repository: { 139 | issues: { nodes: talks }, 140 | }, 141 | }, 142 | } = result.data; 143 | 144 | talks.forEach(talk => { 145 | createPage({ 146 | path: `/talks/${talk.number}`, 147 | component: talkTemplate, 148 | context: { 149 | number: talk.number, 150 | }, 151 | }); 152 | }); 153 | }), 154 | ]); 155 | }; 156 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rk-community-site", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "repository": "git@github.com:wgao19/rk-community-site.git", 6 | "author": "Wei Gao ", 7 | "license": "MIT", 8 | "dependencies": { 9 | "@raae/gatsby-remark-oembed": "^0.1.1", 10 | "@reach/router": "^1.2.1", 11 | "axios": "^0.19.0", 12 | "classnames": "^2.2.6", 13 | "gatsby": "^2.17.4", 14 | "gatsby-plugin-favicon": "^3.1.6", 15 | "gatsby-plugin-google-analytics": "^2.1.23", 16 | "gatsby-plugin-offline": "^3.0.16", 17 | "gatsby-plugin-react-helmet": "^3.1.13", 18 | "gatsby-plugin-sass": "^2.1.20", 19 | "gatsby-plugin-sharp": "^2.3.4", 20 | "gatsby-plugin-typography": "^2.3.14", 21 | "gatsby-remark-images": "^3.1.28", 22 | "gatsby-source-airtable": "^2.0.10", 23 | "gatsby-source-filesystem": "^2.1.33", 24 | "gatsby-source-graphql": "^2.1.20", 25 | "gatsby-transformer-remark": "^2.6.30", 26 | "gatsby-transformer-sharp": "^2.3.6", 27 | "react": "^0.0.0-experimental-f6b8d31a7", 28 | "react-dom": "^0.0.0-experimental-f6b8d31a7", 29 | "react-helmet": "^5.2.1", 30 | "react-key-handler": "^1.2.0-beta.3", 31 | "react-typography": "^0.16.19", 32 | "rehype-react": "^4.0.1", 33 | "typography": "^0.16.19" 34 | }, 35 | "devDependencies": { 36 | "dotenv": "^8.2.0", 37 | "prettier": "^1.18.2", 38 | "sass": "^1.23.1" 39 | }, 40 | "scripts": { 41 | "develop": "gatsby develop -H 0.0.0.0", 42 | "start": "npm run develop", 43 | "build": "yarn run functions && gatsby build", 44 | "functions": "cd src/functions && yarn run build" 45 | }, 46 | "resolutions": { 47 | "gatsby-plugin-favicon/favicons-webpack-plugin/favicons/sharp": "^0.23.1" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true, 3 | trailingComma: 'es5', 4 | bracketSpacing: true, 5 | jsxBracketSameLine: false, 6 | printWidth: 80, 7 | parser: 'babel-flow', 8 | } 9 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | /* If you're feeling fancy you can add interactivity 2 | to your site with Javascript */ 3 | 4 | // prints "hi" in the browser's dev tools console 5 | console.log('built with <3'); 6 | -------------------------------------------------------------------------------- /src/components/Avatar/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import s from './s.module.scss'; 3 | 4 | export default ({ avatarUrl, login, url }) => ( 5 | 6 | {`${login}-avatar`} 7 | 8 | ); 9 | -------------------------------------------------------------------------------- /src/components/Avatar/s.module.scss: -------------------------------------------------------------------------------- 1 | .avatar { 2 | border-radius: 50%; 3 | width: 50px; 4 | margin-bottom: 0; 5 | } 6 | .avatarLink { 7 | border-bottom: 0; 8 | &:hover { 9 | border-bottom: 0; 10 | } 11 | } -------------------------------------------------------------------------------- /src/components/Card/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cx from 'classnames'; 3 | import s from './s.module.scss'; 4 | 5 | export default ({ className, children }) => ( 6 |
{children}
7 | ); 8 | -------------------------------------------------------------------------------- /src/components/Card/s.module.scss: -------------------------------------------------------------------------------- 1 | .card { 2 | border: 2px solid black; 3 | border-radius: var(--round-corner); 4 | padding: .5em 1.5em; 5 | margin: 0 auto 1em; 6 | box-shadow: #222 4px 4px 0 0; 7 | } -------------------------------------------------------------------------------- /src/components/ExternalLinkIcon/index.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import s from './s.module.scss'; 3 | 4 | const ExternalLinkIcon = () => ( 5 | 10 | 11 | 12 | ); 13 | 14 | export default ExternalLinkIcon; 15 | -------------------------------------------------------------------------------- /src/components/ExternalLinkIcon/s.module.scss: -------------------------------------------------------------------------------- 1 | .externalLinkIcon { 2 | vertical-align: top; 3 | width: 1.5em; 4 | height: 1.5em; 5 | margin-left: 0.5em; 6 | } -------------------------------------------------------------------------------- /src/components/Footer/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { graphql, StaticQuery } from 'gatsby'; 3 | import s from './s.module.scss'; 4 | 5 | const Friend = ({ name, link }) => ( 6 | 7 | 13 | 17 | 21 | 22 | {name} 23 | 24 | ); 25 | 26 | const Footer = () => ( 27 | { 45 | return ( 46 |
47 |

48 | Built with love.{' '} 49 | 50 | 51 | 57 | 58 | 59 |

60 |
61 | Friends of RK: 62 | {!!footerLinks && 63 | footerLinks.map(link => ( 64 | 65 | ))} 66 |
67 |
68 | ); 69 | }} 70 | /> 71 | ); 72 | 73 | export default Footer; 74 | -------------------------------------------------------------------------------- /src/components/Footer/s.module.scss: -------------------------------------------------------------------------------- 1 | :local { 2 | .footer { 3 | min-width: 16em; 4 | padding: 1em; 5 | -ms-grid-column: 1; 6 | -ms-grid-column-span: 2; 7 | -ms-grid-row: 4; 8 | grid-column: 1 / span 2; 9 | display: -ms-grid; 10 | display: grid; 11 | -ms-grid-columns: max-content 1fr; 12 | grid-template-columns: max-content 1fr; 13 | margin-top: 3.8326rem; 14 | @media (min-width: 518px) { 15 | align-items: center; 16 | margin-top: initial; 17 | } 18 | } 19 | 20 | .footer p { 21 | margin: 0; 22 | display: flex; 23 | align-items: center; 24 | @media (max-width: 517px) { 25 | writing-mode: vertical-lr; 26 | } 27 | } 28 | 29 | .footer div { 30 | -ms-grid-column: 2; 31 | -ms-grid-column-align: end; 32 | justify-self: end; 33 | display: flex; 34 | flex-direction: column; 35 | justify-content: space-between; 36 | @media (min-width: 648px) and (max-width: 1099px) { 37 | display: grid; 38 | grid-template-columns: max-content max-content; 39 | grid-column-gap: 0.5em; 40 | span { 41 | grid-column: 1 / -1; 42 | } 43 | } 44 | @media (min-width: 1100px) { 45 | display: block; 46 | } 47 | } 48 | 49 | .icon { 50 | height: 1.2em; 51 | width: 1.5em; 52 | border: none; 53 | margin-left: 0.5em; 54 | } 55 | 56 | .icon:hover { 57 | border: none; 58 | } 59 | 60 | .icon path { 61 | transition: fill 0.3s ease; 62 | } 63 | 64 | .icon:hover path { 65 | fill: white; 66 | } 67 | 68 | .friendLabel { 69 | display: block; 70 | font-weight: bold; 71 | } 72 | 73 | .friendLink { 74 | display: block; 75 | cursor: pointer; 76 | border-bottom: none; 77 | white-space: nowrap; 78 | @media (min-width: 900px) { 79 | display: inline-block; 80 | margin-right: 1em; 81 | } 82 | } 83 | 84 | .friendLink:last-child { 85 | margin-right: 0; 86 | } 87 | 88 | .friendLink:hover { 89 | border-bottom: none; 90 | } 91 | 92 | .friendLink:hover .friendIcon { 93 | transform: rotate(360deg); 94 | } 95 | 96 | @media (prefers-reduced-motion: reduce) { 97 | .friendLink:hover .friendIcon { 98 | transform: scale(1.2); 99 | } 100 | } 101 | 102 | .friendIcon { 103 | width: 1em; 104 | height: 1em; 105 | margin-right: 0.25em; 106 | transition: transform 0.5s ease-in-out; 107 | } 108 | } -------------------------------------------------------------------------------- /src/components/Layout/index.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import cx from 'classnames'; 3 | import Helmet from 'react-helmet'; 4 | import { Link } from 'gatsby'; 5 | import Footer from '../Footer'; 6 | import s from './s.module.scss'; 7 | 8 | export default props => { 9 | const { 10 | children, 11 | title, 12 | description, 13 | image, 14 | url, 15 | titleTemplate, 16 | twitter, 17 | coverImage, 18 | className, 19 | onKeyPress, 20 | twitterCardType, 21 | } = props; 22 | const fullImageUrl = coverImage ? `${url}${coverImage}` : `${url}${image}`; 23 | const usedTitle = titleTemplate ? titleTemplate.replace('%s', title) : title; 24 | return ( 25 |
26 | 27 | 28 | {usedTitle} 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 |

40 | 46 | 50 | 54 | 55 | React Knowledgeable 56 |

57 |

58 | React Knowledgeable, nicknamed <RK />, is a fun and 59 | friendly podium to share what we learn about React. 60 |

61 | 65 | 70 | 71 | 72 | 73 | 74 | Speak at RK 75 | 76 |
77 | {children} 78 |
79 |
80 | ); 81 | }; 82 | -------------------------------------------------------------------------------- /src/components/Layout/s.module.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --round-corner: 2px; 3 | } 4 | 5 | // naïve default layout 6 | // header and footer are full-width 7 | // main takes --main-width and aside takes --aside width 8 | // meant to be overwritten 9 | .defaultLayout { 10 | --aside-width: 440px; 11 | --main-width: 900px; 12 | background: white; 13 | min-height: 100vh; 14 | aside div { 15 | width: 100%; 16 | } 17 | @media (min-width: 1145px) { 18 | display: -ms-grid; 19 | display: grid; 20 | // -ms-grid-columns: minmax(900px, 1fr) minmax(440px, 1fr); 21 | grid-template-columns: minmax(--main-width, 1fr) minmax(--aside-width, 1fr); 22 | header, footer { 23 | -ms-grid-column: 1; 24 | -ms-grid-column-span: 2; 25 | grid-column: 1 / -1; 26 | } 27 | main { 28 | -ms-grid-row: 2; 29 | grid-column: 1; 30 | grid-row: 2; 31 | } 32 | aside:first-of-type { 33 | -ms-grid-row: 2; 34 | } 35 | aside:nth-of-type(2) { 36 | -ms-grid-row: 3; 37 | } 38 | aside { 39 | -ms-grid-column: 2; 40 | grid-column: 2; 41 | } 42 | } 43 | } 44 | 45 | .logo { 46 | vertical-align: middle; 47 | width: 4rem; 48 | margin-right: .5rem; 49 | } 50 | 51 | :global { 52 | .twitter-tweet-rendered { 53 | margin: 1.666rem auto; 54 | } 55 | } 56 | 57 | .speakAtRK { 58 | background: rgba(255, 255, 255, 0.75); 59 | display: flex; 60 | align-items: center; 61 | padding: 0.25em; 62 | position: fixed; 63 | top: .5em; 64 | right: .5em; 65 | border: 1px solid black; 66 | border-radius: var(--round-corner); 67 | padding: 0.25em 0.5em; 68 | box-shadow: #222 2px 2px 0 0; 69 | } 70 | .speakAtRKLogo { 71 | width: 1em; 72 | height: 1em; 73 | margin-right: 0.25em; 74 | } 75 | 76 | input { 77 | border: solid 1px black; 78 | box-shadow: #222 2px 2px 0 0; 79 | padding: 0.25em; 80 | max-width: 100%; 81 | } -------------------------------------------------------------------------------- /src/components/Participants/index.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Avatar from '../../components/Avatar'; 3 | 4 | const getAvatarProps = username => ({ 5 | avatarUrl: `https://github.com/${username}.png?size=80`, 6 | url: `https://github.com/${username}`, 7 | login: username, 8 | }); 9 | 10 | const Participants = ({ rawParticipants }) => { 11 | const participants = new Set(); 12 | rawParticipants.map(({ node: { data: { Github_Username: username } } }) => { 13 | // dedupe 14 | return participants.add(username ? username.toLowerCase() : 'react-knowledgeable'); 15 | }); 16 | const numberOfSecretParticipants = rawParticipants.filter( 17 | ({ 18 | node: { 19 | data: { Github_Username: username }, 20 | }, 21 | }) => !username || username === 'react-knowledgeable' 22 | ).length; 23 | 24 | return participants.size > 0 ? ( 25 | <> 26 |

27 | 28 | 👥 29 | {' '} 30 | Attendees{' '} 31 | 32 | 👥 33 | 34 |

35 |

36 | {participants.size > 1 ? ( 37 | {participants.size} amazing RK kids are going 38 | ) : ( 39 | an amazing RK kid is going 40 | )} 41 | {participants.size && numberOfSecretParticipants > 0 && ( 42 | 43 | , {numberOfSecretParticipants} more are going but prefer not to let 44 | us know. 45 | 46 | )} 47 |

48 | {/* @TODO: Put this back when we have added the ability for people to hide their profile */ 49 | Array.from(participants).map(username => { 50 | return ; 51 | })} 52 | 53 | ) : null; 54 | }; 55 | 56 | export default Participants; 57 | -------------------------------------------------------------------------------- /src/components/RSVP/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import axios from 'axios'; 3 | import s from './s.module.scss'; 4 | 5 | const initialState = { 6 | name: '', 7 | username: '', 8 | submissionError: '', 9 | submitting: false, 10 | submissionSuccess: false, 11 | }; 12 | function reducer(state = initialState, action = { type: '' }) { 13 | switch (action.type) { 14 | case 'input': 15 | return { 16 | ...state, 17 | [action.payload.name]: action.payload.value, 18 | submission_error: '', 19 | submissionSuccess: false, 20 | }; 21 | case 'submit': 22 | return { 23 | ...state, 24 | submissionError: '', 25 | submissionSuccess: false, 26 | submitting: true, 27 | }; 28 | case 'submission_error': 29 | return { 30 | ...state, 31 | submissionError: action.payload.error, 32 | submissionSuccess: false, 33 | submitting: false, 34 | }; 35 | case 'submission_success': 36 | return { 37 | ...state, 38 | name: '', 39 | username: '', 40 | submissionSuccess: true, 41 | submissionError: '', 42 | submitting: false, 43 | }; 44 | default: 45 | return state; 46 | } 47 | } 48 | 49 | export default ({ eventId, calendarLink }) => { 50 | const [formVisible, setFormVisible] = React.useState(false); 51 | const [nameError, setNameError] = React.useState(''); 52 | const [state, dispatch] = React.useReducer(reducer, initialState); 53 | const handleSubmit = e => { 54 | e.preventDefault(); 55 | if (!state.name) { 56 | return setNameError('Required'); 57 | } else { 58 | dispatch({ type: 'submit' }); 59 | insertAttendee({ name: state.name, username: state.username, eventId }) 60 | .then(() => { 61 | dispatch({ type: 'submission_success' }); 62 | setFormVisible(false); 63 | }) 64 | .catch(() => { 65 | dispatch({ 66 | type: 'submission_error', 67 | payload: { 68 | error: "Oops, we couldn't register you, please try again.", 69 | }, 70 | }); 71 | }); 72 | } 73 | }; 74 | return ( 75 | 76 | {!state.submissionSuccess && ( 77 | 80 | )} 81 |
82 | 93 | 107 | {state.submissionError && ( 108 |

{state.submissionError}

109 | )} 110 | {/* Ask if they want their name to be shown? */} 111 | 114 |
115 | {state.submissionSuccess && ( 116 |

117 | See you there :) Would you like to{' '} 118 | 119 | add this to your calendar 120 | 121 | ? 122 |

123 | )} 124 |
125 | ); 126 | }; 127 | 128 | function insertAttendee({ eventId, username, name }) { 129 | return axios.post(`/.netlify/functions/airtable`, { 130 | name, 131 | username, 132 | eventId, 133 | }); 134 | } 135 | -------------------------------------------------------------------------------- /src/components/RSVP/s.module.scss: -------------------------------------------------------------------------------- 1 | .hidden { 2 | visibility: hidden; 3 | height: 0; 4 | } 5 | .form { 6 | margin-top: 1em; 7 | } 8 | 9 | .btn { 10 | background: rgba(255, 255, 255, 0.75); 11 | display: flex; 12 | align-items: center; 13 | padding: 0.25em; 14 | border: 1px solid black; 15 | border-radius: var(--round-corner); 16 | padding: 0.25em 0.5em; 17 | box-shadow: #222 2px 2px 0 0; 18 | cursor: pointer; 19 | &:disabled { 20 | opacity: 0.4; 21 | } 22 | } 23 | 24 | .formField { 25 | display: block; 26 | margin: 0.5em 0em; 27 | } 28 | 29 | .formField:last-of-type { 30 | margin-bottom: 2em; 31 | } 32 | 33 | .fieldLabel { 34 | display: block; 35 | margin: 0em; 36 | } 37 | 38 | .fieldCaption { 39 | color: #777; 40 | font-size: .75em; 41 | margin-bottom: .5em; 42 | } 43 | 44 | .fieldError { 45 | @extend .fieldLabel; 46 | color: red; 47 | margin-top: 0.25em; 48 | } 49 | 50 | .submissionError { 51 | font-size: 0.875rem; 52 | } 53 | -------------------------------------------------------------------------------- /src/components/Talk/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Avatar from '../Avatar'; 3 | import Card from '../Card'; 4 | import s from './s.module.scss'; 5 | 6 | export default props => { 7 | const { title, url, author } = props; 8 | return ( 9 | 10 |

11 | {title} 12 |

13 | 14 | {/** we need to parse talk body (markdown) */} 15 | {/*

*/} 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/Talk/s.module.scss: -------------------------------------------------------------------------------- 1 | .talk { 2 | display: grid; 3 | grid-template-columns: 1fr max-content; 4 | align-items: flex-start; 5 | padding: 2rem 1.5rem; 6 | } 7 | 8 | .author { 9 | grid-column: 2; 10 | } 11 | .title { 12 | line-height: 1.8; 13 | margin: 0; 14 | margin-right: 0.25em; 15 | } -------------------------------------------------------------------------------- /src/functions/airtable.js: -------------------------------------------------------------------------------- 1 | import Airtable from 'airtable' 2 | 3 | const ERROR_MSGS = { 4 | UNSUPPORTED_METHOD: 'Unsupported method', 5 | UNKNOWN_ERROR: 'Server Error', 6 | } 7 | 8 | export const handler = async (event, _, callback) => { 9 | try { 10 | const atClient = _configureAirtable() 11 | switch (event.httpMethod) { 12 | case 'POST': 13 | await insertAttendee(atClient, event, callback) 14 | break 15 | case 'GET': 16 | await retrieveAttendees(atClient, event, callback) 17 | break 18 | default: 19 | callback(Error({ message: ERROR_MSGS.UNSUPPORTED_METHOD }), { 20 | status: 405, 21 | body: ERROR_MSGS.UNSUPPORTED_METHOD, 22 | }) 23 | } 24 | } catch (e) { 25 | callback(Error(e), { 26 | status: 500, 27 | body: ERROR_MSGS.UNKNOWN_ERROR, 28 | }) 29 | } 30 | } 31 | 32 | async function retrieveAttendees(Client, event, callback) { 33 | let attendees = [] 34 | let selectOpts = {} 35 | const { eventId } = event.queryStringParameters 36 | if (eventId) { 37 | selectOpts = { filterByFormula: `SEARCH("${eventId}",{Event ID})` } 38 | } 39 | await Client('Attendees') 40 | .select(selectOpts) 41 | .eachPage((records, fetchNextPage) => { 42 | records.forEach(function(record) { 43 | attendees.push(record.fields) 44 | }) 45 | fetchNextPage() 46 | }) 47 | callback(null, { 48 | status: 200, 49 | body: JSON.stringify(attendees), 50 | }) 51 | } 52 | 53 | async function insertAttendee(Client, event, callback) { 54 | if (event.httpMethod !== 'POST') { 55 | return callback(Error({ message: ERROR_MSGS.UNSUPPORTED_METHOD }), { 56 | status: 405, 57 | body: ERROR_MSGS.UNSUPPORTED_METHOD, 58 | }) 59 | } 60 | const { eventId, name, username } = JSON.parse(event.body) 61 | await Client('Attendees').create([ 62 | { 63 | fields: { 64 | Name: name, 65 | 'Github Username': username, 66 | 'Event ID': eventId, 67 | Type: 'Attendee', 68 | 'Created Date': new Date().toISOString(), 69 | }, 70 | }, 71 | ]) 72 | callback(null, { 73 | status: 200, 74 | body: JSON.stringify({ name, eventId }), 75 | }) 76 | } 77 | 78 | function _configureAirtable() { 79 | Airtable.configure({ apiKey: '__AIRTABLE_API_KEY__' }) 80 | return Airtable.base('__AIRTABLE_BASE_ID__') 81 | } 82 | -------------------------------------------------------------------------------- /src/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rk-functions", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "yarn && rollup --config && cp -r node_modules ../../functions" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "@rollup/plugin-replace": "^2.2.0", 13 | "airtable": "^0.7.2", 14 | "rollup": "^1.26.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/functions/rollup.config.js: -------------------------------------------------------------------------------- 1 | /* This is for building the Netlify functions (lambdas) only! */ 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const promisify = require('util').promisify; 6 | const readdir = promisify(fs.readdir); 7 | const replace = require('@rollup/plugin-replace'); 8 | 9 | export default () => { 10 | return new Promise(res => { 11 | _getFunctionPaths().then(paths => { 12 | res( 13 | paths.map(func => ({ 14 | input: func.input, 15 | output: { 16 | file: path.resolve(__dirname, '../../functions', func.filePath), 17 | format: 'cjs', 18 | }, 19 | plugins: [ 20 | replace({ 21 | __AIRTABLE_API_KEY__: process.env.AIRTABLE_API_KEY, 22 | __AIRTABLE_BASE_ID__: process.env.AIRTABLE_BASE_ID, 23 | }), 24 | ], 25 | external: ['airtable'] 26 | })) 27 | ); 28 | }); 29 | }); 30 | }; 31 | 32 | async function _getFunctionPaths() { 33 | const functionSrc = path.resolve(__dirname); 34 | const functionPaths = await readdir(functionSrc); 35 | return functionPaths 36 | .filter(filePath => { 37 | return ![ 38 | 'node_modules', 39 | 'package.json', 40 | 'yarn.lock', 41 | 'rollup.config.js' 42 | ].includes( 43 | filePath 44 | ); 45 | }) 46 | .map(filePath => ({ 47 | input: path.resolve(functionSrc, filePath), 48 | filePath, 49 | })); 50 | } 51 | -------------------------------------------------------------------------------- /src/functions/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@rollup/plugin-replace@^2.2.0": 6 | version "2.2.0" 7 | resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.2.0.tgz#e3b11881fb1ab1be7570e1ccd175b8249e448c52" 8 | integrity sha512-DnALjyAdfAyQ4i6tJdi4v6rJwx5tzV9/+M7G8qA3cHpPOYQOgM4U8bU4lSM24h9hFIbycxRTHtE+TkENLqRlEA== 9 | dependencies: 10 | magic-string "^0.25.2" 11 | rollup-pluginutils "^2.6.0" 12 | typescript "^3.4.3" 13 | 14 | "@types/estree@*": 15 | version "0.0.39" 16 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" 17 | integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== 18 | 19 | "@types/node@*": 20 | version "12.12.5" 21 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.5.tgz#66103d2eddc543d44a04394abb7be52506d7f290" 22 | integrity sha512-KEjODidV4XYUlJBF3XdjSH5FWoMCtO0utnhtdLf1AgeuZLOrRbvmU/gaRCVg7ZaQDjVf3l84egiY0mRNe5xE4A== 23 | 24 | acorn@^7.1.0: 25 | version "7.1.0" 26 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" 27 | integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== 28 | 29 | airtable@^0.7.2: 30 | version "0.7.2" 31 | resolved "https://registry.yarnpkg.com/airtable/-/airtable-0.7.2.tgz#106e87b7139f6a2c9f1bd856583e83626e2f3c04" 32 | integrity sha512-BwHIJyXmtUJ78EpnNzs+aYmPK9r0xNeFyKkmSn9I6WvG6QYcXlbDe6rhoEwqEdrjPVL6ZCoNwimJN4l6y5TUJg== 33 | dependencies: 34 | lodash "4.17.15" 35 | request "2.88.0" 36 | xhr "2.3.3" 37 | 38 | ajv@^6.5.5: 39 | version "6.10.2" 40 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" 41 | integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== 42 | dependencies: 43 | fast-deep-equal "^2.0.1" 44 | fast-json-stable-stringify "^2.0.0" 45 | json-schema-traverse "^0.4.1" 46 | uri-js "^4.2.2" 47 | 48 | asn1@~0.2.3: 49 | version "0.2.4" 50 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" 51 | integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== 52 | dependencies: 53 | safer-buffer "~2.1.0" 54 | 55 | assert-plus@1.0.0, assert-plus@^1.0.0: 56 | version "1.0.0" 57 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 58 | integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= 59 | 60 | asynckit@^0.4.0: 61 | version "0.4.0" 62 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 63 | integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= 64 | 65 | aws-sign2@~0.7.0: 66 | version "0.7.0" 67 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" 68 | integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= 69 | 70 | aws4@^1.8.0: 71 | version "1.8.0" 72 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" 73 | integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== 74 | 75 | bcrypt-pbkdf@^1.0.0: 76 | version "1.0.2" 77 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" 78 | integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= 79 | dependencies: 80 | tweetnacl "^0.14.3" 81 | 82 | caseless@~0.12.0: 83 | version "0.12.0" 84 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 85 | integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= 86 | 87 | combined-stream@^1.0.6, combined-stream@~1.0.6: 88 | version "1.0.8" 89 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 90 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 91 | dependencies: 92 | delayed-stream "~1.0.0" 93 | 94 | core-util-is@1.0.2: 95 | version "1.0.2" 96 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 97 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= 98 | 99 | dashdash@^1.12.0: 100 | version "1.14.1" 101 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 102 | integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= 103 | dependencies: 104 | assert-plus "^1.0.0" 105 | 106 | define-properties@^1.1.3: 107 | version "1.1.3" 108 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 109 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== 110 | dependencies: 111 | object-keys "^1.0.12" 112 | 113 | delayed-stream@~1.0.0: 114 | version "1.0.0" 115 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 116 | integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= 117 | 118 | dom-walk@^0.1.0: 119 | version "0.1.1" 120 | resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" 121 | integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= 122 | 123 | ecc-jsbn@~0.1.1: 124 | version "0.1.2" 125 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" 126 | integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= 127 | dependencies: 128 | jsbn "~0.1.0" 129 | safer-buffer "^2.1.0" 130 | 131 | es-abstract@^1.13.0: 132 | version "1.16.0" 133 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.0.tgz#d3a26dc9c3283ac9750dca569586e976d9dcc06d" 134 | integrity sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg== 135 | dependencies: 136 | es-to-primitive "^1.2.0" 137 | function-bind "^1.1.1" 138 | has "^1.0.3" 139 | has-symbols "^1.0.0" 140 | is-callable "^1.1.4" 141 | is-regex "^1.0.4" 142 | object-inspect "^1.6.0" 143 | object-keys "^1.1.1" 144 | string.prototype.trimleft "^2.1.0" 145 | string.prototype.trimright "^2.1.0" 146 | 147 | es-to-primitive@^1.2.0: 148 | version "1.2.0" 149 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" 150 | integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== 151 | dependencies: 152 | is-callable "^1.1.4" 153 | is-date-object "^1.0.1" 154 | is-symbol "^1.0.2" 155 | 156 | estree-walker@^0.6.1: 157 | version "0.6.1" 158 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" 159 | integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== 160 | 161 | extend@~3.0.2: 162 | version "3.0.2" 163 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" 164 | integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== 165 | 166 | extsprintf@1.3.0: 167 | version "1.3.0" 168 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" 169 | integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= 170 | 171 | extsprintf@^1.2.0: 172 | version "1.4.0" 173 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" 174 | integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= 175 | 176 | fast-deep-equal@^2.0.1: 177 | version "2.0.1" 178 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" 179 | integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= 180 | 181 | fast-json-stable-stringify@^2.0.0: 182 | version "2.0.0" 183 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 184 | integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= 185 | 186 | for-each@^0.3.3: 187 | version "0.3.3" 188 | resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" 189 | integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== 190 | dependencies: 191 | is-callable "^1.1.3" 192 | 193 | forever-agent@~0.6.1: 194 | version "0.6.1" 195 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 196 | integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= 197 | 198 | form-data@~2.3.2: 199 | version "2.3.3" 200 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" 201 | integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== 202 | dependencies: 203 | asynckit "^0.4.0" 204 | combined-stream "^1.0.6" 205 | mime-types "^2.1.12" 206 | 207 | function-bind@^1.1.1: 208 | version "1.1.1" 209 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 210 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 211 | 212 | getpass@^0.1.1: 213 | version "0.1.7" 214 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 215 | integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= 216 | dependencies: 217 | assert-plus "^1.0.0" 218 | 219 | global@~4.3.0: 220 | version "4.3.2" 221 | resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" 222 | integrity sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8= 223 | dependencies: 224 | min-document "^2.19.0" 225 | process "~0.5.1" 226 | 227 | har-schema@^2.0.0: 228 | version "2.0.0" 229 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" 230 | integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= 231 | 232 | har-validator@~5.1.0: 233 | version "5.1.3" 234 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" 235 | integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== 236 | dependencies: 237 | ajv "^6.5.5" 238 | har-schema "^2.0.0" 239 | 240 | has-symbols@^1.0.0: 241 | version "1.0.0" 242 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" 243 | integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= 244 | 245 | has@^1.0.1, has@^1.0.3: 246 | version "1.0.3" 247 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 248 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 249 | dependencies: 250 | function-bind "^1.1.1" 251 | 252 | http-signature@~1.2.0: 253 | version "1.2.0" 254 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" 255 | integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= 256 | dependencies: 257 | assert-plus "^1.0.0" 258 | jsprim "^1.2.2" 259 | sshpk "^1.7.0" 260 | 261 | is-callable@^1.1.3, is-callable@^1.1.4: 262 | version "1.1.4" 263 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" 264 | integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== 265 | 266 | is-date-object@^1.0.1: 267 | version "1.0.1" 268 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" 269 | integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= 270 | 271 | is-function@^1.0.1: 272 | version "1.0.1" 273 | resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" 274 | integrity sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU= 275 | 276 | is-regex@^1.0.4: 277 | version "1.0.4" 278 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" 279 | integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= 280 | dependencies: 281 | has "^1.0.1" 282 | 283 | is-symbol@^1.0.2: 284 | version "1.0.2" 285 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" 286 | integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== 287 | dependencies: 288 | has-symbols "^1.0.0" 289 | 290 | is-typedarray@~1.0.0: 291 | version "1.0.0" 292 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 293 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= 294 | 295 | isstream@~0.1.2: 296 | version "0.1.2" 297 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 298 | integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= 299 | 300 | jsbn@~0.1.0: 301 | version "0.1.1" 302 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 303 | integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= 304 | 305 | json-schema-traverse@^0.4.1: 306 | version "0.4.1" 307 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 308 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 309 | 310 | json-schema@0.2.3: 311 | version "0.2.3" 312 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 313 | integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= 314 | 315 | json-stringify-safe@~5.0.1: 316 | version "5.0.1" 317 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 318 | integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= 319 | 320 | jsprim@^1.2.2: 321 | version "1.4.1" 322 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" 323 | integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= 324 | dependencies: 325 | assert-plus "1.0.0" 326 | extsprintf "1.3.0" 327 | json-schema "0.2.3" 328 | verror "1.10.0" 329 | 330 | lodash@4.17.15: 331 | version "4.17.15" 332 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 333 | integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== 334 | 335 | magic-string@^0.25.2: 336 | version "0.25.4" 337 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.4.tgz#325b8a0a79fc423db109b77fd5a19183b7ba5143" 338 | integrity sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw== 339 | dependencies: 340 | sourcemap-codec "^1.4.4" 341 | 342 | mime-db@1.40.0: 343 | version "1.40.0" 344 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" 345 | integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== 346 | 347 | mime-types@^2.1.12, mime-types@~2.1.19: 348 | version "2.1.24" 349 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" 350 | integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== 351 | dependencies: 352 | mime-db "1.40.0" 353 | 354 | min-document@^2.19.0: 355 | version "2.19.0" 356 | resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" 357 | integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= 358 | dependencies: 359 | dom-walk "^0.1.0" 360 | 361 | oauth-sign@~0.9.0: 362 | version "0.9.0" 363 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" 364 | integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== 365 | 366 | object-inspect@^1.6.0: 367 | version "1.6.0" 368 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" 369 | integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== 370 | 371 | object-keys@^1.0.12, object-keys@^1.1.1: 372 | version "1.1.1" 373 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 374 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 375 | 376 | parse-headers@^2.0.0: 377 | version "2.0.2" 378 | resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.2.tgz#9545e8a4c1ae5eaea7d24992bca890281ed26e34" 379 | integrity sha512-/LypJhzFmyBIDYP9aDVgeyEb5sQfbfY5mnDq4hVhlQ69js87wXfmEI5V3xI6vvXasqebp0oCytYFLxsBVfCzSg== 380 | dependencies: 381 | for-each "^0.3.3" 382 | string.prototype.trim "^1.1.2" 383 | 384 | performance-now@^2.1.0: 385 | version "2.1.0" 386 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" 387 | integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= 388 | 389 | process@~0.5.1: 390 | version "0.5.2" 391 | resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" 392 | integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8= 393 | 394 | psl@^1.1.24: 395 | version "1.4.0" 396 | resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" 397 | integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== 398 | 399 | punycode@^1.4.1: 400 | version "1.4.1" 401 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 402 | integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= 403 | 404 | punycode@^2.1.0: 405 | version "2.1.1" 406 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 407 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 408 | 409 | qs@~6.5.2: 410 | version "6.5.2" 411 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 412 | integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== 413 | 414 | request@2.88.0: 415 | version "2.88.0" 416 | resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" 417 | integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== 418 | dependencies: 419 | aws-sign2 "~0.7.0" 420 | aws4 "^1.8.0" 421 | caseless "~0.12.0" 422 | combined-stream "~1.0.6" 423 | extend "~3.0.2" 424 | forever-agent "~0.6.1" 425 | form-data "~2.3.2" 426 | har-validator "~5.1.0" 427 | http-signature "~1.2.0" 428 | is-typedarray "~1.0.0" 429 | isstream "~0.1.2" 430 | json-stringify-safe "~5.0.1" 431 | mime-types "~2.1.19" 432 | oauth-sign "~0.9.0" 433 | performance-now "^2.1.0" 434 | qs "~6.5.2" 435 | safe-buffer "^5.1.2" 436 | tough-cookie "~2.4.3" 437 | tunnel-agent "^0.6.0" 438 | uuid "^3.3.2" 439 | 440 | rollup-pluginutils@^2.6.0: 441 | version "2.8.2" 442 | resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" 443 | integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== 444 | dependencies: 445 | estree-walker "^0.6.1" 446 | 447 | rollup@^1.26.3: 448 | version "1.26.3" 449 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.26.3.tgz#3e71b8120a4ccc745a856e926cab0efbe0eead90" 450 | integrity sha512-8MhY/M8gnv3Q/pQQSWYWzbeJ5J1C5anCNY5BK1kV8Yzw9RFS0FF4lbLt+uyPO3wLKWXSXrhAL5pWL85TZAh+Sw== 451 | dependencies: 452 | "@types/estree" "*" 453 | "@types/node" "*" 454 | acorn "^7.1.0" 455 | 456 | safe-buffer@^5.0.1, safe-buffer@^5.1.2: 457 | version "5.2.0" 458 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" 459 | integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== 460 | 461 | safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: 462 | version "2.1.2" 463 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 464 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 465 | 466 | sourcemap-codec@^1.4.4: 467 | version "1.4.6" 468 | resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9" 469 | integrity sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg== 470 | 471 | sshpk@^1.7.0: 472 | version "1.16.1" 473 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" 474 | integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== 475 | dependencies: 476 | asn1 "~0.2.3" 477 | assert-plus "^1.0.0" 478 | bcrypt-pbkdf "^1.0.0" 479 | dashdash "^1.12.0" 480 | ecc-jsbn "~0.1.1" 481 | getpass "^0.1.1" 482 | jsbn "~0.1.0" 483 | safer-buffer "^2.0.2" 484 | tweetnacl "~0.14.0" 485 | 486 | string.prototype.trim@^1.1.2: 487 | version "1.2.0" 488 | resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.0.tgz#75a729b10cfc1be439543dae442129459ce61e3d" 489 | integrity sha512-9EIjYD/WdlvLpn987+ctkLf0FfvBefOCuiEr2henD8X+7jfwPnyvTdmW8OJhj5p+M0/96mBdynLWkxUr+rHlpg== 490 | dependencies: 491 | define-properties "^1.1.3" 492 | es-abstract "^1.13.0" 493 | function-bind "^1.1.1" 494 | 495 | string.prototype.trimleft@^2.1.0: 496 | version "2.1.0" 497 | resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" 498 | integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== 499 | dependencies: 500 | define-properties "^1.1.3" 501 | function-bind "^1.1.1" 502 | 503 | string.prototype.trimright@^2.1.0: 504 | version "2.1.0" 505 | resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" 506 | integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== 507 | dependencies: 508 | define-properties "^1.1.3" 509 | function-bind "^1.1.1" 510 | 511 | tough-cookie@~2.4.3: 512 | version "2.4.3" 513 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" 514 | integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== 515 | dependencies: 516 | psl "^1.1.24" 517 | punycode "^1.4.1" 518 | 519 | tunnel-agent@^0.6.0: 520 | version "0.6.0" 521 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 522 | integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= 523 | dependencies: 524 | safe-buffer "^5.0.1" 525 | 526 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 527 | version "0.14.5" 528 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 529 | integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= 530 | 531 | typescript@^3.4.3: 532 | version "3.6.4" 533 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d" 534 | integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg== 535 | 536 | uri-js@^4.2.2: 537 | version "4.2.2" 538 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" 539 | integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== 540 | dependencies: 541 | punycode "^2.1.0" 542 | 543 | uuid@^3.3.2: 544 | version "3.3.3" 545 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" 546 | integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== 547 | 548 | verror@1.10.0: 549 | version "1.10.0" 550 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" 551 | integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= 552 | dependencies: 553 | assert-plus "^1.0.0" 554 | core-util-is "1.0.2" 555 | extsprintf "^1.2.0" 556 | 557 | xhr@2.3.3: 558 | version "2.3.3" 559 | resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.3.3.tgz#ad6b810e0917ce72b5ec704f5d41f1503b8e7524" 560 | integrity sha1-rWuBDgkXznK17HBPXUHxUDuOdSQ= 561 | dependencies: 562 | global "~4.3.0" 563 | is-function "^1.0.1" 564 | parse-headers "^2.0.0" 565 | xtend "^4.0.0" 566 | 567 | xtend@^4.0.0: 568 | version "4.0.2" 569 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" 570 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== 571 | -------------------------------------------------------------------------------- /src/pages/404/index.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Link } from 'gatsby'; 3 | import s from './s.module.scss'; 4 | 5 | const browser = typeof window !== 'undefined' && window; 6 | 7 | export default () => 8 | browser && ( 9 |

10 |

Integer overflow!

11 | 16 | 20 | 24 | 30 | 31 | Press here to restart 32 |
33 | ); 34 | -------------------------------------------------------------------------------- /src/pages/404/s.module.scss: -------------------------------------------------------------------------------- 1 | .uhOh { 2 | height: 100vh; 3 | margin: 0 auto; 4 | max-width: 52rem; 5 | min-width: 16rem; 6 | display: flex; 7 | flex-direction: column; 8 | align-items: center; 9 | justify-content: center; 10 | text-align: center; 11 | } 12 | 13 | .uhOh h1 { 14 | margin: 0 0 0.5em; 15 | } 16 | 17 | .uhOh svg { 18 | max-height: 70vh; 19 | min-height: 10em; 20 | margin-bottom: 1em; 21 | } 22 | 23 | .uhOh a { 24 | font-weight: bold; 25 | font-size: 150%; 26 | } 27 | -------------------------------------------------------------------------------- /src/pages/index.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Link, graphql } from 'gatsby'; 3 | import Layout from '../components/Layout'; 4 | import Talk from '../components/Talk'; 5 | import Card from '../components/Card'; 6 | import RSVP from '../components/RSVP'; 7 | import ExternalLinkIcon from '../components/ExternalLinkIcon'; 8 | import parseDate from '../utils/parseDate'; 9 | import s from './s.module.scss'; 10 | 11 | const parseBodyText = body => { 12 | return body.match('') 13 | ? body.split('')[1].split('')[0] 14 | : ''; 15 | }; 16 | 17 | export default ({ 18 | data: { 19 | site: { 20 | siteMetadata: { title, description, url, image, twitter, titleTemplate }, 21 | }, 22 | meetups: { nodes: meetups }, 23 | stories: { nodes: stories }, 24 | github: { 25 | repository: { 26 | content: { nodes: labels }, 27 | talks: { nodes: talks }, 28 | }, 29 | }, 30 | }, 31 | }) => { 32 | const nextMeetup = getNextMeetup(meetups); 33 | const { 34 | fields: { slug: nextMeetupSlug } = {}, 35 | frontmatter: { title: meetupTitle, venue, date }, 36 | } = nextMeetup || { frontmatter: {} }; 37 | return ( 38 | 49 | 88 |
89 |

Topics

90 |
91 | {!!labels && 92 | labels 93 | .filter( 94 | label => 95 | // GH doesn't have query filters on labels 96 | !['talk', 'event', 'react updates'].includes(label.name) && 97 | label.issues.nodes.length 98 | ) 99 | .map(({ name, issues: { nodes: issues } }) => ( 100 | 101 |

{name}

102 | {!!issues && 103 | issues 104 | // sorts by created descending, later talk comes up 105 | .sort((a, b) => (a.createdAt > b.createdAt ? -1 : 1)) 106 | .map( 107 | ({ title, body, url, closed, createdAt, number }) => ( 108 | 109 |

110 | {title} 111 | {!closed ? ( 112 | upcoming 113 | ) : null} 114 | 120 | 121 | 122 |

123 |

124 | {parseBodyText(body)} 125 |

126 |
127 | ) 128 | )} 129 |
130 | ))} 131 |
132 |
133 | 149 |
150 | ); 151 | }; 152 | 153 | export const pageQuery = graphql` 154 | query HomePageQuery { 155 | site { 156 | siteMetadata { 157 | title 158 | image 159 | description 160 | url 161 | twitter 162 | titleTemplate 163 | } 164 | } 165 | meetups: allMarkdownRemark( 166 | filter: { fileAbsolutePath: { regex: "/meetups/" } } 167 | sort: { fields: frontmatter___date, order: ASC } 168 | ) { 169 | nodes { 170 | frontmatter { 171 | venue 172 | date 173 | talks 174 | title 175 | calendarLink 176 | } 177 | fields { 178 | slug 179 | } 180 | excerpt 181 | } 182 | } 183 | github { 184 | repository(owner: "react-knowledgeable", name: "talks") { 185 | content: labels(first: 30) { 186 | nodes { 187 | name 188 | description 189 | issues(last: 100) { 190 | totalCount 191 | nodes { 192 | title 193 | body 194 | url 195 | number 196 | closed 197 | createdAt 198 | } 199 | } 200 | } 201 | } 202 | talks: issues( 203 | last: 100 204 | labels: ["talk"] 205 | orderBy: { field: CREATED_AT, direction: ASC } 206 | ) { 207 | nodes { 208 | title 209 | body 210 | number 211 | bodyText 212 | author { 213 | avatarUrl 214 | login 215 | url 216 | } 217 | url 218 | } 219 | } 220 | } 221 | } 222 | stories: allMarkdownRemark( 223 | filter: { fileAbsolutePath: { regex: "/stories/" } } 224 | sort: { fields: frontmatter___date, order: DESC } 225 | ) { 226 | nodes { 227 | frontmatter { 228 | title 229 | } 230 | fields { 231 | slug 232 | } 233 | excerpt 234 | } 235 | } 236 | } 237 | `; 238 | 239 | // meetups must be sorted by date 240 | function getNextMeetup(meetups) { 241 | const now = new Date(); 242 | return meetups.find(({ frontmatter: { date } }) => { 243 | const eventDate = new Date(date); 244 | return eventDate.setDate(eventDate.getDate() + 1) >= now; 245 | }); 246 | } 247 | -------------------------------------------------------------------------------- /src/pages/s.module.scss: -------------------------------------------------------------------------------- 1 | .homePageLayout { 2 | @media (min-width: 1145px) { 3 | -ms-grid-columns: 1fr minmax(20em, 30%); 4 | grid-template-columns: auto minmax(20em, 30%); 5 | -ms-grid-rows: min-content min-content 1fr auto; 6 | grid-template-rows: min-content min-content 1fr auto; 7 | main { 8 | -ms-grid-row-span: 2; 9 | grid-row: 2 / span 2; 10 | } 11 | } 12 | } 13 | 14 | .upcomingMeetupInfo { 15 | @media (min-width: 748px) and (max-width: 1144px) { 16 | display: grid; 17 | grid-template-columns: 1fr auto; 18 | grid-column-gap: 0.5em; 19 | h2 { 20 | grid-column: 1 / -1; 21 | } 22 | h3 { 23 | word-break: break-word; 24 | } 25 | } 26 | } 27 | 28 | .topicListing { 29 | column-width: 20em; 30 | } 31 | .topicCard { 32 | padding-bottom: 2rem; 33 | break-inside: avoid; 34 | } 35 | .topicIntro { 36 | max-height: 5em; 37 | @supports (-webkit-line-clamp: 3) { 38 | display: -webkit-box; 39 | /* autoprefixer: off */ 40 | -webkit-box-orient: vertical; 41 | /* autoprefixer: on */ 42 | -webkit-line-clamp: 3; 43 | } 44 | overflow: hidden; 45 | } 46 | 47 | .talkAuthor { 48 | display: flex; 49 | align-items: center; 50 | p { 51 | display: inline-block; 52 | } 53 | img { 54 | width: 3rem; 55 | border-radius: 50%; 56 | margin-right: 1rem; 57 | } 58 | } 59 | 60 | .upcoming { 61 | font-weight: lighter; 62 | border-radius: var(--round-corner); 63 | background: #222; 64 | color: white; 65 | margin-left: .5em; 66 | padding: 2px 4px; 67 | font-size: .75em; 68 | } 69 | 70 | .externalLink { 71 | border-bottom: none; 72 | } 73 | -------------------------------------------------------------------------------- /src/templates/Meetup/index.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import cx from 'classnames'; 3 | import { graphql } from 'gatsby'; 4 | import r2r from 'rehype-react'; 5 | import KeyHandler, { KEYPRESS } from 'react-key-handler'; 6 | import parseDate from '../../utils/parseDate'; 7 | import Layout from '../../components/Layout'; 8 | import RSVP from '../../components/RSVP'; 9 | import Participants from '../../components/Participants'; 10 | import ExternalLinkIcon from '../../components/ExternalLinkIcon'; 11 | import { modes, slideTo } from '../../utils/remote'; 12 | import s from './s.module.scss'; 13 | 14 | const buildSections = elements => { 15 | const sectionTags = ['h2', 'h3']; 16 | const sections = []; 17 | return elements 18 | .filter(node => node.type === 'element') 19 | .reduce((acc, cur) => { 20 | if (!acc.length || sectionTags.includes(cur.tagName)) { 21 | acc.push({ 22 | tagName: 'section', 23 | type: 'element', 24 | properties: {}, 25 | children: [cur], 26 | }); 27 | } else { 28 | acc[acc.length - 1].children.push(cur); 29 | } 30 | return acc; 31 | }, sections); 32 | }; 33 | 34 | const astToHtml = new r2r({ 35 | createElement: React.createElement, 36 | Fragment: React.Fragment, 37 | }).Compiler; 38 | 39 | export default ({ 40 | location, 41 | pageContext: { id }, 42 | data: { 43 | allAirtable: { edges: rawParticipants }, 44 | site: { 45 | siteMetadata: { 46 | description, 47 | url, 48 | image, 49 | twitter, 50 | titleTemplate, 51 | footerLinks, 52 | }, 53 | }, 54 | markdownRemark: { 55 | frontmatter: { 56 | title, 57 | date, 58 | venue, 59 | venueLogo, 60 | venueLink, 61 | venueAddress, 62 | venueAddressLink, 63 | sponsors, 64 | talks: talkIssueIds, 65 | issueLink, 66 | calendarLink, 67 | }, 68 | htmlAst, 69 | }, 70 | talks: { 71 | repository: { 72 | issues: { nodes: talks }, 73 | }, 74 | }, 75 | }, 76 | }) => { 77 | const [mode, setMode] = React.useState(modes.article); 78 | React.useEffect(() => { 79 | if ([modes.presentation].includes(mode)) { 80 | const pages = document.querySelectorAll('section'); 81 | pages && 82 | pages.length && 83 | pages[location.hash.slice(1) || 0].scrollIntoView({ 84 | behavior: 'smooth', 85 | }); 86 | } 87 | }, [mode, location]); 88 | const toggleMode = newMode => 89 | newMode === mode ? setMode(modes.article) : setMode(newMode); 90 | const sections = buildSections(htmlAst.children); 91 | const content = astToHtml({ 92 | type: 'root', 93 | children: sections, 94 | }); 95 | return ( 96 | 107 | toggleMode(modes.presentation)} 111 | /> 112 | toggleMode(modes.article)} 116 | /> 117 | {[modes.presentation, modes.speaker].includes(mode) && ( 118 | <> 119 | {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => ( 120 | slideTo(i, location)} 125 | /> 126 | ))} 127 | slideTo('prev', location)} 131 | /> 132 | slideTo('next', location)} 136 | /> 137 | slideTo('next', location)} 141 | /> 142 | 143 | )} 144 | 252 |
253 |
254 |

{title}

255 |

256 | {parseDate(date)}, 7:30pm 257 |

258 |
259 |
260 | 261 |
262 |
263 | 264 |
265 | {content && content} 266 |
267 |

268 | 269 | 🎙 270 | {' '} 271 | Talk Line-up{' '} 272 | 273 | 🎙 274 | 275 |

276 |
    277 | {talkIssueIds && 278 | talkIssueIds.length && 279 | talkIssueIds.map(talkIssueId => { 280 | const talkData = talks.find( 281 | ({ number }) => number === talkIssueId 282 | ); 283 | const { title, url } = talkData; 284 | return ( 285 |
  • 286 | 287 | {title} 288 | 289 |
  • 290 | ); 291 | })} 292 |
293 |
294 |
295 |
296 | ); 297 | }; 298 | 299 | export const pageQuery = graphql` 300 | query MeetupQuery($slug: String!, $id: String!) { 301 | # allRkAttendee(filter: { Event_ID: { eq: $id } }) { 302 | # totalCount 303 | # } 304 | allAirtable(filter: { data: { Event_ID: { eq: $id } } }) { 305 | totalCount 306 | edges { 307 | node { 308 | data { 309 | Github_Username 310 | } 311 | } 312 | } 313 | } 314 | site { 315 | siteMetadata { 316 | title 317 | image 318 | description 319 | url 320 | twitter 321 | titleTemplate 322 | footerLinks { 323 | name 324 | link 325 | } 326 | } 327 | } 328 | markdownRemark(fields: { slug: { eq: $slug } }) { 329 | frontmatter { 330 | title 331 | venue 332 | venueLogo 333 | venueAddress 334 | venueAddressLink 335 | venueLink 336 | sponsors { 337 | sponsor 338 | sponsorLogo 339 | sponsorLink 340 | } 341 | talks 342 | date 343 | issueLink 344 | calendarLink 345 | } 346 | html 347 | htmlAst 348 | fields { 349 | slug 350 | } 351 | } 352 | talks: github { 353 | repository(owner: "react-knowledgeable", name: "talks") { 354 | issues( 355 | first: 100 356 | labels: ["talk"] 357 | orderBy: { field: CREATED_AT, direction: ASC } 358 | ) { 359 | nodes { 360 | title 361 | body 362 | number 363 | bodyText 364 | author { 365 | avatarUrl 366 | login 367 | url 368 | } 369 | url 370 | } 371 | } 372 | } 373 | } 374 | } 375 | `; 376 | -------------------------------------------------------------------------------- /src/templates/Meetup/s.module.scss: -------------------------------------------------------------------------------- 1 | 2 | .presentation { 3 | display: block; 4 | margin: 0; 5 | padding: 0; 6 | max-height: 100vh; 7 | overflow-y: hidden; 8 | 9 | header, footer { 10 | display: none; 11 | } 12 | main, article, aside { 13 | display: contents; 14 | } 15 | 16 | div.doNotPresent { 17 | display: none; 18 | } 19 | 20 | section { 21 | padding: 1rem calc((100vw - 60%) / 2); 22 | margin-top: -1.51rem; // hack 23 | height: 100vh; 24 | display: flex; 25 | justify-content: center; 26 | flex-direction: column; 27 | font-size: 1.5rem; 28 | div { 29 | width: 100%; 30 | } 31 | } 32 | 33 | h1, h2, h3 { 34 | margin-top: 0; 35 | padding-top: 2rem; 36 | font-size: 2em; 37 | line-height: 1.5; 38 | } 39 | h4 { 40 | font-size: .9em; 41 | } 42 | } 43 | 44 | .article { 45 | grid-template-columns: minmax(var(--main-width), 3fr) minmax(var(--aside-width), 1fr); 46 | 47 | /** 48 | * TODO: move this to appropriate place 49 | * the current problem is that it assumes one side is shorter than the other 50 | * same problem with home page 51 | * so better reconsider this layout integratedly 52 | */ 53 | > footer { 54 | @media (min-width: 1600px) { 55 | grid-column: 1; 56 | grid-row: 3; 57 | align-self: end; 58 | } 59 | > div { 60 | @media (min-width: 1600px) { 61 | display: block; 62 | } 63 | } 64 | } 65 | > p { 66 | @media (min-width: 1600px) { 67 | writing-mode: unset; 68 | } 69 | } 70 | } 71 | 72 | .venueLink { 73 | border-bottom: 0; 74 | } 75 | .venueLink:hover, .venueLink:active { 76 | border-bottom: 0; 77 | } 78 | 79 | .attendees { 80 | margin-bottom: 2rem; 81 | } -------------------------------------------------------------------------------- /src/templates/Speaker/index.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export default () =>
talk
; 3 | -------------------------------------------------------------------------------- /src/templates/Story/index.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { graphql } from 'gatsby'; 3 | import parseDate from '../../utils/parseDate'; 4 | import Layout from '../../components/Layout'; 5 | import s from './s.module.scss'; 6 | 7 | export default ({ 8 | data: { 9 | site: { 10 | siteMetadata: { 11 | title: siteTitle, 12 | description, 13 | url, 14 | image, 15 | twitter, 16 | titleTemplate, 17 | }, 18 | }, 19 | markdownRemark: { 20 | frontmatter: { title, speaker, date, cover }, 21 | html, 22 | }, 23 | }, 24 | }) => ( 25 | 38 |
39 |

{title}

40 |

41 | {speaker} on {parseDate(date)} 42 |

43 |
44 |
45 |
46 |
47 |
48 | ); 49 | 50 | export const pageQuery = graphql` 51 | query StoryQuery($slug: String!) { 52 | site { 53 | siteMetadata { 54 | title 55 | description 56 | url 57 | twitter 58 | titleTemplate 59 | image 60 | } 61 | } 62 | markdownRemark(fields: { slug: { eq: $slug } }) { 63 | frontmatter { 64 | title 65 | speaker 66 | date 67 | cover { 68 | childImageSharp { 69 | sizes(maxWidth: 720) { 70 | ...GatsbyImageSharpSizes 71 | } 72 | } 73 | } 74 | } 75 | html 76 | fields { 77 | slug 78 | } 79 | } 80 | } 81 | `; 82 | -------------------------------------------------------------------------------- /src/templates/Story/s.module.scss: -------------------------------------------------------------------------------- 1 | .story { 2 | max-width: 50rem; 3 | margin: 0 auto; 4 | } 5 | .storyLayout { 6 | header { 7 | border-bottom: 1px solid; 8 | } 9 | } -------------------------------------------------------------------------------- /src/templates/Talk/index.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { graphql } from 'gatsby'; 3 | import parseDate from '../../utils/parseDate'; 4 | import Layout from '../../components/Layout'; 5 | 6 | export default ({ 7 | data: { 8 | talks: { 9 | repository: { 10 | issue: { 11 | author: { avatarUrl, login }, 12 | title, 13 | number, 14 | bodyHTML, 15 | createdAt, 16 | }, 17 | }, 18 | }, 19 | }, 20 | }) => ( 21 | 22 |
23 |

{title}

24 |

25 | {login} on {parseDate(createdAt)} 26 |

27 |
28 |
29 |
30 |
31 |
32 | ); 33 | 34 | export const pageQuery = graphql` 35 | query TalkQuery($number: Int!) { 36 | talks: github { 37 | repository(owner: "react-knowledgeable", name: "talks") { 38 | issue(number: $number) { 39 | author { 40 | avatarUrl 41 | login 42 | } 43 | title 44 | number 45 | bodyHTML 46 | createdAt 47 | } 48 | } 49 | } 50 | } 51 | `; 52 | -------------------------------------------------------------------------------- /src/utils/parseDate.js: -------------------------------------------------------------------------------- 1 | export default date => { 2 | const d = new Date(date); 3 | return d === 'Invalid Date' 4 | ? date 5 | : d.toLocaleDateString([], { 6 | day: 'numeric', 7 | month: 'long', 8 | year: 'numeric', 9 | }); 10 | }; 11 | -------------------------------------------------------------------------------- /src/utils/remote.js: -------------------------------------------------------------------------------- 1 | import { navigate } from '@reach/router'; 2 | 3 | export const modes = { 4 | article: 'article', 5 | presentation: 'presentation', 6 | }; 7 | 8 | export const slideTo = (to, location) => { 9 | switch (to) { 10 | case 0: 11 | case 1: 12 | case 2: 13 | case 3: 14 | case 4: 15 | case 5: 16 | case 6: 17 | case 7: 18 | case 8: 19 | case 9: { 20 | navigate( 21 | `${location.pathname}#${Math.min( 22 | to, 23 | document.querySelectorAll('section').length - 1 24 | )}` 25 | ); 26 | break; 27 | } 28 | case 'prev': { 29 | const currentHash = location.hash 30 | ? parseInt(location.hash.slice(1), 10) 31 | : 0; 32 | navigate( 33 | `${location.pathname}#${currentHash >= 1 ? currentHash - 1 : 0}` 34 | ); 35 | break; 36 | } 37 | case 'next': { 38 | const currentHash = location.hash 39 | ? parseInt(location.hash.slice(1), 10) 40 | : 0; 41 | const pages = document.querySelectorAll('section'); 42 | navigate( 43 | `${location.pathname}#${ 44 | currentHash >= pages.length - 1 ? pages.length - 1 : currentHash + 1 45 | }` 46 | ); 47 | break; 48 | } 49 | default: { 50 | return; 51 | } 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /src/utils/typography.js: -------------------------------------------------------------------------------- 1 | import Typography from 'typography'; 2 | 3 | const typography = new Typography({ 4 | baseFontSize: '18px', 5 | baseLineHeight: 1.666, 6 | 7 | googleFonts: [ 8 | { 9 | name: 'IBM Plex Mono', 10 | styles: ['700', '700i', '400', '400i'], 11 | }, 12 | ], 13 | headerFontFamily: ['IBM Plex Mono', 'monospace'], 14 | bodyFontFamily: ['IBM Plex Mono', 'monospace'], 15 | overrideStyles: ({ rhythm, adjustFontSizeTo }, { blockMarginBottom }) => { 16 | return { 17 | h1: { 18 | fontStyle: 'italic', 19 | marginTop: rhythm(1.2), 20 | marginBottom: rhythm(1.2), 21 | lineHeight: rhythm(1.8), 22 | }, 23 | h2: { 24 | marginTop: rhythm(1.1), 25 | marginBottom: rhythm(1.1), 26 | lineHeight: rhythm(1.5), 27 | }, 28 | h3: { 29 | marginTop: rhythm(1.03), 30 | marginBottom: rhythm(1.03), 31 | lineHeight: rhythm(1.3), 32 | }, 33 | h4: { 34 | marginTop: rhythm(1), 35 | marginBottom: rhythm(1), 36 | lineHeight: rhythm(1), 37 | }, 38 | h5: { 39 | marginTop: rhythm(0.9), 40 | marginBottom: rhythm(0.9), 41 | }, 42 | h6: { 43 | marginTop: rhythm(0.75), 44 | marginBottom: rhythm(0.75), 45 | }, 46 | code: { 47 | fontSize: '1.1em', 48 | fontFamily: "'IBM Plex Mono', monospace", 49 | whiteSpace: 'nowrap', 50 | }, 51 | 52 | 'header, main, aside': { 53 | padding: '1em', 54 | }, 55 | 'h1 a, h2 a, h3 a': { 56 | borderBottom: '2px solid #222', 57 | }, 58 | 'h1 a:hover, h1 a:active, h2 a:hover, h2 a:active, h3 a:hover, h3 a:active': { 59 | borderBottom: '4px solid #222', 60 | }, 61 | a: { 62 | color: 'black', 63 | textDecoration: 'none', 64 | borderBottom: '1.5px solid #222', 65 | paddingBottom: '2px', 66 | transition: 'all .1s ease', 67 | }, 68 | ul: { 69 | paddingInlineStart: '20px', 70 | }, 71 | 'ul li': { 72 | marginBottom: '8px', 73 | }, 74 | hr: { 75 | height: 0, 76 | marginBottom: '5rem', 77 | }, 78 | 'hr::after': { 79 | content: "'***'", 80 | textAlign: 'center', 81 | display: 'block', 82 | fontSize: '1.5rem', 83 | opacity: 0.5, 84 | letterSpacing: '10px', 85 | }, 86 | }; 87 | }, 88 | }); 89 | 90 | export default typography; 91 | -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-knowledgeable/rk-community-site/10fe3c306fe33f5c5453c0eaad1b1ea8dcc98d39/static/logo.png -------------------------------------------------------------------------------- /watch.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": { 3 | "include": [ 4 | "^package\\.json$", 5 | "^\\.env$", 6 | "^\\.env.development", 7 | "^gatsby-node.js$" 8 | ] 9 | }, 10 | "restart": { 11 | "exclude": [ 12 | "^src/", 13 | "^public/", 14 | "^.cache/", 15 | "^README.md$" 16 | ], 17 | "include": [ 18 | "\\.json$", 19 | "^gatsby-config.js$", 20 | "^glitch-config.js$" 21 | ] 22 | }, 23 | "throttle": 100 24 | } --------------------------------------------------------------------------------