diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..b512c09d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/data/snippet_data.json b/data/snippet_data.json new file mode 100644 index 000000000..446e47d96 --- /dev/null +++ b/data/snippet_data.json @@ -0,0 +1,301 @@ +[ + { + "name": "AutoLink.md", + "title": "AutoLink", + "text": "Renders a string as plaintext, with URLs converted to appropriate `` elements.\n\nUse `String.prototype.split()` and `String.prototype.match()` with a regular expression to find URLs in a string.\nReturn a `` with matched URLs rendered as `` elements, dealing with missing protocol prefixes if necessary, and the rest of the string rendered as plaintext.\n\n", + "codeBlocks": [ + "```jsx\nfunction AutoLink({ text }) {\n const delimiter = /((?:https?:\\/\\/)?(?:(?:[a-z0-9]?(?:[a-z0-9\\-]{1,61}[a-z0-9])?\\.[^\\.|\\s])+[a-z\\.]*[a-z]+|(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3})(?::\\d{1,5})*[a-z0-9.,_\\/~#&=;%+?\\-\\\\(\\\\)]*)/gi;\n\n return (\n \n {text.split(delimiter).map(word => {\n let match = word.match(delimiter);\n if (match) {\n let url = match[0];\n return (\n {url}\n );\n }\n return word;\n })}\n \n );\n}\n```", + "```jsx\nReactDOM.render(\n ,\n document.getElementById('root')\n);\n```" + ], + "expertise": 2, + "tags": [ + "string", + "fragment", + "functional" + ], + "notes": [] + }, + { + "name": "Carousel.md", + "title": "Carousel", + "text": "Renders a carousel component.\n\nInitially set `state.active` to `0` (index of the first item).\nUse an object, `style`, to hold the styles for the individual components.\nDefine a method, `setActiveItem`, which uses `this.setState` to change the state's `active` property to the index of the next item.\nDefine another method, `changeItem`, which is called by `setActiveItem` after updating the state each time and also when the component\nfirst renders (on `ComponentDidMount`).\nIn the `render()` method, destructure `state`, `style` and `props`, compute if visibility style should be set to `visible` or not for each carousel item while mapping over and applying the combined style to the carousel item component accordingly.\nRender the carousel items using [React.cloneElement](https://reactjs.org/docs/react-api.html#cloneelement) and pass down rest\n`props` along with the computed styles.\n\n", + "codeBlocks": [ + "```jsx\nclass Carousel extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n active: 0\n };\n this.scrollInterval = null;\n this.style = {\n carousel: {\n position: \"relative\"\n },\n carouselItem: {\n position: \"absolute\",\n visibility: \"hidden\"\n },\n visible: {\n visibility: \"visible\"\n }\n };\n }\n componentDidMount() {\n this.changeItem();\n }\n setActiveItem = () => {\n const { carouselItems } = this.props;\n this.setState(\n prevState => ({\n active: (prevState.active + 1) % carouselItems.length\n }),\n this.changeItem\n );\n };\n changeItem = () => {\n this.scrollInterval = setTimeout(this.setActiveItem, 2000);\n };\n render() {\n const { carouselItems, ...rest } = this.props;\n const { active } = this.state;\n const { visible, carousel, carouselItem } = this.style;\n return (\n
\n {carouselItems.map((item, index) => {\n const activeStyle = active === index ? visible : {};\n return React.cloneElement(item, {\n ...rest,\n style: {\n ...carouselItem,\n ...activeStyle\n }\n });\n })}\n
\n );\n }\n}\n```", + "```jsx\nReactDOM.render(\n carousel item 1,\n
carousel item 2
,\n
carousel item 3
\n ]}\n />,\n document.getElementById(\"root\")\n);\n ```" + ], + "expertise": 2, + "tags": [ + "visual", + "children", + "state", + "class" + ], + "notes": [] + }, + { + "name": "Collapse.md", + "title": "Collapse", + "text": "Renders a component with collapsible content.\n\nUse the value of the `collapsed` prop to determine the initial state of the content (collapsed/expanded).\nSet the `state` of the component to the value of the `collapsed` prop (cast to a boolean value) and bind the `toggleCollapse` method to the component's context.\nUse an object, `style`, to hold the styles for individual components and their states.\nCreate a method, `toggleCollapse`, which uses `Component.prototype.setState` to change the component's `state` from collapsed to expanded and vice versa.\nIn the `render()` method, use a `
` to wrap both the `\n
\n {this.props.children}\n
\n
\n );\n }\n}\n```", + "```jsx\nReactDOM.render(\n \n

This is a collapse

\n

Hello world!

\n
,\n document.getElementById('root')\n);\n```" + ], + "expertise": 2, + "tags": [ + "visual", + "children", + "state", + "class" + ], + "notes": [] + }, + { + "name": "DataList.md", + "title": "DataList", + "text": "Renders a list of elements from an array of primitives.\n\nUse the value of the `isOrdered` prop to conditionally render a `
    ` or `
      ` list.\nUse `Array.prototype.map` to render every item in `data` as a `
    • ` element, give it a `key` produced from the concatenation of the its index and value.\nOmit the `isOrdered` prop to render a `
        ` list by default.\n\n", + "codeBlocks": [ + "```jsx\nfunction DataList({ isOrdered, data }) {\n const list = data.map((val, i) => (\n
      • {val}
      • \n ));\n return isOrdered ?
          {list}
        :
          {list}
        ;\n}\n```", + "```jsx\nconst names = ['John', 'Paul', 'Mary'];\nReactDOM.render(, document.getElementById('root'));\nReactDOM.render(, document.getElementById('root'));\n```" + ], + "expertise": 0, + "tags": [ + "array", + "functional" + ], + "notes": [] + }, + { + "name": "DataTable.md", + "title": "DataTable", + "text": "Renders a table with rows dynamically created from an array of primitives.\n\nRender a `` element with two columns (`ID` and `Value`).\nUse `Array.prototype.map` to render every item in `data` as a `` element, consisting of its index and value, give it a `key` produced from the concatenation of the two.\n\n", + "codeBlocks": [ + "```jsx\nfunction DataTable({ data }) {\n return (\n
        \n \n \n \n \n \n \n \n {data.map((val, i) =>\n \n \n \n \n )}\n \n
        IDValue
        {i}{val}
        \n );\n}\n```", + "```jsx\nconst people = ['John', 'Jesse'];\nReactDOM.render(\n ,\n document.getElementById('root')\n);\n```" + ], + "expertise": 0, + "tags": [ + "array", + "functional" + ], + "notes": [] + }, + { + "name": "Input.md", + "title": "Input", + "text": "Renders an `` element that uses a callback function to pass its value to the parent component.\n\nUse object destructuring to set defaults for certain attributes of the `` element.\nRender an `` element with the appropriate attributes and use the `callback` function in the `onChange` event to pass the value of the input to the parent.\n\n", + "codeBlocks": [ + "```jsx\nfunction Input ({ callback, type = 'text', disabled = false, readOnly = false, placeholder = '' }) {\n return (\n callback(value)}\n />\n );\n}\n```", + "```jsx\nReactDOM.render(\n console.log(val)}/>,\n document.getElementById('root')\n);\n```" + ], + "expertise": 0, + "tags": [ + "input", + "functional" + ], + "notes": [] + }, + { + "name": "LimitedTextarea.md", + "title": "LimitedTextarea", + "text": "Renders a textarea component with a character limit.\n\nUse the value of the `value` prop to determine the initial `state.content` and `state.characterCount` and the value of the `limit` props to determine the value of `state.limit`.\nCreate a method, `handleChange`, which trims the `event.target.value` data if necessary and uses `Component.prototype.setState` to update `state.content` and `state.characterCount`, and bind it to the component's context.\nIn the`render()` method, use a`
        ` to wrap both the`\n

        {this.state.characterCount}/{this.props.limit}

        \n
        \n );\n }\n}\n```", + "```jsx\nReactDOM.render(\n ,\n document.getElementById('root')\n);\n```" + ], + "expertise": 0, + "tags": [ + "input", + "state", + "class" + ], + "notes": [] + }, + { + "name": "Mailto.md", + "title": "Mailto", + "text": "Renders a link formatted to send an email.\n\nDestructure the component's props, use `email`, `subject` and `body` to create a `` element with an appropriate `href` attribute.\nRender the link with `props.children` as its content.\n\n", + "codeBlocks": [ + "```jsx\nfunction Mailto({ email, subject, body, ...props }) {\n return (\n \n {props.children}\n \n );\n}\n```", + "```jsx\nReactDOM.render(\n \n Mail me!\n ,\n document.getElementById(\"root\")\n);\n```" + ], + "expertise": 0, + "tags": [ + "functional" + ], + "notes": [] + }, + { + "name": "MappedTable.md", + "title": "MappedTable", + "text": "Renders a table with rows dynamically created from an array of objects and a list of property names.\n\nUse `Object.keys()`, `Array.prototype.filter()`, `Array.prototype.includes()` and `Array.prototype.reduce()` to produce a `filteredData` array, containing all objects with the keys specified in `propertyNames`.\nRender a `` element with a set of columns equal to the amount of values in `propertyNames`.\nUse `Array.prototype.map` to render each value in the `propertyNames` array as a `` element, containing a `
        ` element.\nUse `Array.prototype.map` to render each object in the `filteredData` array as a `
        ` for each key in the object.\n\n", + "codeBlocks": [ + "```jsx\nfunction MappedTable({ data, propertyNames }) {\n let filteredData = data.map(v =>\n Object.keys(v)\n .filter(k => propertyNames.includes(k))\n .reduce((acc, key) => ((acc[key] = v[key]), acc), {})\n );\n return (\n \n \n {propertyNames.map(val => )}\n \n \n {filteredData.map((val, i) => (\n \n {propertyNames.map(p => )}\n \n ))}\n \n
        {val}
        {val[p]}
        \n );\n}\n```", + "```jsx\nconst people = [\n { name: 'John', surname: 'Smith', age: 42 },\n { name: 'Adam', surname: 'Smith', gender: 'male' }\n];\nconst propertyNames = ['name', 'surname', 'age'];\nReactDOM.render(\n ,\n document.getElementById('root')\n);\n```" + ], + "expertise": 1, + "tags": [ + "array", + "object", + "functional" + ], + "notes": [ + "This component does not work with nested objects and will break if there are nested objects inside any of the properties specified in `propertyNames`.", + "", + "" + ] + }, + { + "name": "ModalDialog.md", + "title": "ModalDialog", + "text": "Renders a dialog component in a modal, controllable through events. \nTo use the component, import `ModalDialog` only once and then display it using `ModalDialog.show()`, passing the JSX templates and data as parameters.\n\nDefine `modalHandler`, a method that will handle showing the modal dialog, set `state` to the default values initially and bind the `close` and `modalClick` methods to the component's context.\nDefine `close` and `modalClick` to toggle the visibility of the modal dialog, based on `state.closeOnClick`.\nUse the CustomEvent API to listen for `modal` events, that can be dispatched from the `static` `show()` method, handle listeners appropriately from `componentDidMount` and `componentWillUnmount`.\n\nThe `show()` method accepts an argument, that should contain three parameters:\n* `title`, a string for the dialog's title\n* `closeOnClick`, `true` if the modal should close on click or `false` if it should only close when clicking the *X* button\n* `content`, which is the JSX content to be rendered inside the dialog\n\nFinally, in the `render()` method, use a `
        ` to wrap everything and render the modal dialog with the content passed to `show()`.\n\n", + "codeBlocks": [ + "```css\n .modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.6);\n z-index: 9998;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n .dialog {\n background-color: white;\n border-radius: 5px;\n overflow: hidden;\n }\n .dialog-title {\n box-sizing: border-box;\n width: 100%;\n height: 48px;\n padding: 0 16px;\n border-bottom: 0.5px solid #c3c3c3;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .dialog-close {\n font-size: 32px;\n color: #c3c3c3;\n cursor: pointer;\n transform: rotate(45deg);\n user-select: none;\n }\n .dialog-close:hover {\n color: red;\n }\n .dialog-content {\n min-width: 300px;\n }\n```", + "```jsx\nclass ModalDialog extends React.Component {\n constructor() {\n super();\n this.modalHandler = (e) => {\n this.setState({\n data: e.detail.data,\n visible: true\n });\n };\n this.state = {\n data: {\n title: '',\n closeOnClick: false,\n content: ''\n },\n visible: false\n };\n this.close = this.close.bind(this);\n this.modalClick = this.modalClick.bind(this);\n }\n render() {\n return !this.state.visible ? null :
        \n
        \n
        { this.state.data.title }+
        \n
        \n {\n this.state.data.content\n }\n
        \n
        \n
        \n }\n componentDidMount() {\n document.addEventListener('modal', this.modalHandler);\n }\n componentWillUnmount() {\n document.removeEventListener('modal', this.modalHandler);\n }\n close() {\n this.setState({\n visible: false,\n data: {\n title: '',\n closeOnClick: false,\n content: ''\n }\n });\n }\n static show(data) {\n document.dispatchEvent(new CustomEvent('modal', {\n detail: {\n data\n }\n }));\n }\n modalClick() {\n if (this.state.data.closeOnClick) this.close();\n }\n}\n```", + "```jsx\n// add to render function\n\n\n// every time you wanna call the dialog\n// content is a jsx element\nModalDialog.show({\n title: 'Hello, world!',\n closeOnClick: true,\n content: \n}); \n```" + ], + "expertise": 1, + "tags": [ + "visual", + "static", + "children", + "state", + "class" + ], + "notes": [ + "This component includes a lot of CSS, which might conflict with other CSS in your project. It is recomended for the modal to be a direct child of the body tag.", + "A more up-to-date method with lower compatibility is to use [Portals](https://reactjs.org/docs/portals.html) in React 16+.", + "", + "" + ] + }, + { + "name": "PasswordRevealer.md", + "title": "PasswordRevealer", + "text": "Renders a password input field with a reveal button.\n\nInitially set `state.shown` to `false` to ensure that the password is not shown by default.\nCreate a method, `toggleShown`, which uses `Component.prototype.setState` to change the input's state from shown to hidden and vice versa, bind it to the component's context.\nIn the`render()` method, use a`
        ` to wrap both the`` and the `\n
        \n );\n }\n}\n```", + "```jsx\nReactDOM.render(, document.getElementById('root'));\n```" + ], + "expertise": 0, + "tags": [ + "input", + "state", + "class" + ], + "notes": [] + }, + { + "name": "Select.md", + "title": "Select", + "text": "Renders a `` element.\nRender a `` element.\n\n", + "codeBlocks": [ + "```jsx\nfunction Select ({ values, callback, disabled = false, readonly = false, selected }) {\n return (\n callback(value)}\n >\n {values.map(([value, text]) => )}\n \n );\n}\n```", + "```jsx\nlet choices = [\n ['grapefruit', 'Grapefruit'],\n ['lime', 'Lime'],\n ['coconut', 'Coconut'],\n ['mango', 'Mango']\n];\nReactDOM.render(\n