<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Bobate Isaac on Medium]]></title>
        <description><![CDATA[Stories by Bobate Isaac on Medium]]></description>
        <link>https://medium.com/@bobateisaac?source=rss-29cfa9c1c0bd------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*AW5HDUaTioGZnOW5</url>
            <title>Stories by Bobate Isaac on Medium</title>
            <link>https://medium.com/@bobateisaac?source=rss-29cfa9c1c0bd------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 23 May 2026 11:57:24 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@bobateisaac/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Writing cleaner CSS code with BEM]]></title>
            <link>https://medium.com/stackanatomy/writing-cleaner-css-code-with-bem-71bab2bb957a?source=rss-29cfa9c1c0bd------2</link>
            <guid isPermaLink="false">https://medium.com/p/71bab2bb957a</guid>
            <category><![CDATA[css3]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[web-design]]></category>
            <category><![CDATA[front-end-development]]></category>
            <dc:creator><![CDATA[Bobate Isaac]]></dc:creator>
            <pubDate>Tue, 27 Jun 2023 16:53:05 GMT</pubDate>
            <atom:updated>2023-06-29T23:37:54.680Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pDtQSkgf0ACYTCHq3ge56g.png" /></figure><blockquote>Clean and organized code is crucial in modern web development projects, and developers are constantly seeking ways to improve code maintainability and organization. Thankfully, various techniques exist to achieve this goal, including the popular Block Element Modifier (BEM) methodology — and this article will explain how BEM works and why you should start applying it.</blockquote><p>In this article, we’ll delve into the world of BEM, exploring its many advantages, usage, and implementation strategies for both HTML and CSS. By using BEM, developers can implement a structured, modular approach to naming conventions in HTML and CSS, resulting in code that is easier to read, more maintainable, and less prone to errors. This article will equip you with an understanding of the importance of BEM in modern web development and the ability to write cleaner, more maintainable code for your next project or product. Let’s get started!</p><h3>What is BEM?</h3><p><a href="https://en.bem.info/methodology/quick-start/">BEM</a> is a naming convention for HTML and CSS classes that helps developers create maintainable and organized code. It provides a structured format for naming the HTML and CSS classes, leading to the breakdown of our webpage into smaller components (block, elements, and modifiers components). It was created in the mid-2000s by developers working on the complex user interface of the Yandex search engine. The developers were struggling with maintaining their rapidly growing CSS codebase. They needed a structured approach to naming conventions in HTML and CSS to make their codebase more maintainable, scalable, and reusable. After experimenting with several methods, they settled on BEM, which aims to create a hierarchy of components on the webpage. In 2010, they published their approach in a blog post, which gained popularity in the web development community. Today, BEM is widely adopted as a naming convention for HTML and CSS by companies such as Google, Airbnb, and GitHub, and has spawned many tools and resources to assist developers in implementing the methodology more efficiently.</p><p>There are many benefits to using the BEM methodology. Here are a few reasons for you to consider using BEM:</p><ul><li><strong>Reusability</strong>: BEM methodology allows us to generate code that enables the reuse of components in multiple instances, resulting in a well-structured and organized hierarchy of components on the webpage. As a result, it becomes possible to use blocks in various locations on the page.</li><li><strong>Maintainability</strong>: BEM’s well-defined structure facilitates targeted changes or updates to particular sections of a webpage. By employing BEM, we can ensure smooth code maintenance, faster updates, and minimize coding errors, resulting in an error-free codebase.</li><li><strong>Better accessibility</strong>: The naming convention offered by BEM enhances accessibility as it helps technologies, such as screen readers, to detect, interpret, and understand the content on a webpage with greater ease.</li><li><strong>Better collaboration</strong>: BEM’s naming convention simplifies teamwork among developers. By adopting a unified naming convention for classes, developers can comprehend and edit each other’s code more effortlessly, ultimately fostering better collaboration and teamwork.</li></ul><p>Before you continue reading, take this practical explanation as the primary goal of BEM. For instance, if your friend or another developer were to look at your CSS code, they should easily understand the code. It means that your code should be readable, clear, and concise. In other words, your code should have a consistent style that your friend or another developer can easily understand.</p><h3>When should we use BEM?</h3><p>We mostly used BEM when dealing with projects having a huge codebase comprising multiple pages. Here are some practical samples of where we can implement BEM:</p><ul><li><strong>Large-Scale Projects</strong>: We can introduce BEM when we have a project with a large codebase, which comprises multiple developers building different parts of the project. Using BEM, we can easily maintain the project and reduce the risk of error and code conflict.</li><li><strong>Accessibility-focused projects</strong>: The BEM methodology will make our website more accessible to users when projects prioritize Search Engine Optimization (SEO). With BEM, our website would be more accessible to users when they use technology that detects the contents of a webpage.</li></ul><h3>The breakdown of the keyword “BEM”</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/561/0*8JVWwoBBTkwkXA6G.png" /></figure><p>BEM is a keyword that represents three entities:</p><h3>Block</h3><p>This is a fundamental entity in the structure of BEM, which is very useful in organizing and structuring CSS and HTML code for websites and web applications. A block is an independent User Interface (UI) entity that represents a reusable component of a web page. Some examples of the block entity on the webpage are the navigation bar, sidebar, header, etc.</p><p>Example of the block naming method:</p><pre>.btn {<br>  color: red;<br>  font-size: 15px;<br>}</pre><p>In the code snippet above, we can easily deduce that the developer is trying to style a button (a block in this case). It means that when choosing a name for a block element to style, we should choose names that are easy to read and understand. Also, the block name should start with a small letter like the block name btn above.</p><p>When applying the block method while setting the class name, we should remember the name should be descriptive and show the function or purpose of the block. That is the sole aim of the block naming convention. You are not required to consider other features (like appearance — color) of the block element when creating a class name. The modifier entity deals with appearance, so never try to do this:</p><pre>.blue-btn {<br>  color: blue;<br>  font-size: 18px;<br>}</pre><p>Instead, try to follow best practices by just using a word or set of descriptive words in alignment with the function of the element.</p><p>Another school of thought when working with the block is when we want to use more than a word for our block name. The creators of BEM had this in mind while developing it, and thus, they came up with a solution — separating words with hyphens.</p><p>For example, a product list block would be named “product-list”:</p><pre>.product-list {<br>  list-style: none;<br>  font-size: 14px;<br>}</pre><p>When using the block entity, you should always try to integrate the following guidelines:</p><ul><li>Choose semantic block names: Choose names that explicitly define the function of the element, not its appearance.</li><li>Use class names consistently: BEM enforces having class names for every element in your code. Therefore, all element entities within a block should have a class name, including the block entity. With this‌, nothing is affected by changing the class style. Instead of using element selectors, assign a class name for each element in your codebase.</li><li>Separate block styles from their elements: BEM encourages us to separate block styling from other components, like the element. We often use Block styles in other parts of the code, which is why code conflicts may occur when combining the style of a block with another component.</li></ul><p>Following the guidelines above will ensure that integrating the block entity when defining classes for our markdown or when styling (CSS) is a seamless process.</p><h3>Element</h3><p>The letter’ E’ in the BEM symbolizes the Element entity. Element, unlike the block entity, is dependent. They are the children of the block entity, as they can not stand alone. We can find them inside a block — they live inside the block.</p><p><strong>Note</strong>: an element can only have a parent (just a block it’s tied to), and we can’t use it outside that block. Let’s take an example of a block — header. Inside the header block, we have things like logos, links, and buttons embedded in it. These things found in the header block are the “elements.” Now, how do we create an element name? An element name starts with the parent name (block name), followed by double underscores, and ends with the element name.</p><p>The CSS code:</p><pre>/*recall header is our block name, therefore header comes first*/<br>.header__logo {<br> <br>}</pre><p>Our HTML code:</p><pre>&lt;div class=&quot;header&quot;&gt;<br>  &lt;img class=&quot;header__logo&quot; alt=&quot;logo&quot;/&gt;<br>&lt;/div&gt;</pre><p>In the code sample above, we have a parent element (div) with a block name of header. Inside it, we have an image element with an element name header__logo.</p><h3>Nesting Elements within the same block</h3><p>Nesting elements is embedding an element inside another element within the same block. Using the example of a header block with a navigation element inside it ‌containing a menu-item element (ul tag - an unordered list), we can then say the menu item is nested in the navigation element.</p><p>Nesting Elements are very useful in representing complex or hierarchical relationships between parts of a Block. However, it is ‌advisable to keep the Element hierarchy flat and avoid nesting elements deeply. Deeply nested elements can make the HTML and CSS code more complex and harder to read and maintain. It can also lead to specificity issues when styling the nested elements, making it harder to override styles or change the layout later.</p><p>Therefore, use nesting sparingly only when it is necessary to represent the structure of the block. It is often better to use multiple blocks or elements at the same hierarchy level to represent different parts of the page rather than nesting elements intensely.</p><p>Here is a code sample to explain the theory of nesting of elements:</p><pre>&lt;div class=&quot;header&quot;&gt;<br>  &lt;img class=&quot;header__logo&quot; alt=&quot;logo&quot;/&gt;<br>  &lt;nav class=&quot;header__link&quot;&gt;<br>&lt;!--     menu-list --&gt;<br>    &lt;ul class=&quot;header__menu-list&quot;&gt;&lt;/ul&gt;<br>  &lt;/nav&gt;<br>&lt;/div&gt;</pre><p>We can deduce from the code that we still implement the standard naming convention for defining element names, even when elements are being nested. We could have written the code above this way:</p><pre>&lt;div class=&quot;header&quot;&gt;<br>  &lt;img class=&quot;header__logo&quot; alt=&quot;logo&quot;/&gt;<br>  &lt;nav class=&quot;header__link&quot;&gt;<br>&lt;!--     menu-list --&gt;<br>    &lt;ul class=&quot;header__link__menu-list&quot;&gt;&lt;/ul&gt;<br>  &lt;/nav&gt;<br>&lt;/div&gt;</pre><p>When defining an element name for a nested element, you shouldn’t prefix it with the parent element name (header__link in this case), which results in this — header__link__menu-list. Just prefix it with the block name (header), followed by double underscores, and then the element name, which results in this - header__menu-list (for this example).</p><p>Here are some key things to consider when using the Element entity:</p><ul><li>We use elements to represent sub-components of a block.</li><li>Assign a descriptive name to your element and always follow the standard naming convention, even when working with nested elements.</li><li>Avoid using an element outside the block it belongs to.</li><li>Reduce the level of nesting elements.</li></ul><p>Considering these tips will let you adapt to industry-standard usage of the Element entity in the BEM methodology.</p><h3>Modifier</h3><p>This determines/defines the appearance, state, or behaviour of a Block or an Element independently (without creating a new Block or Element from scratch).</p><p>We separate the modifier name from the block or element name by using two hyphens (--). The ideal way of naming modifiers is to prefix them with a double hyphen (--), though some people use double underscores (__) or a single hyphen (-). I would advise you to take it as an ideal practice to use the double hyphen (--) as a prefix for the modifier name and not the other methods in other not to mix the modifier with another entity, like an element since it uses the double underscore (__) prefix.</p><p>Here is the syntax:</p><pre>/*when targeting a Block*/<br>.block-name-modifier-name {<br>/*   styles go in here */<br>}<br><br>/*when targeting an Element*/<br>.block-name__element-name-modifier-name {<br>/*   styles go in here */<br>}</pre><p>We add Modifiers to Blocks or Elements by adding their name as a suffix to the Block or Element’s class, separated by two underscores.</p><p>Note, Modifiers are optional, but you can choose to use them because of their efficiency in creating visual styles and adding variation to Elements and Blocks. Some examples of modifier names are disabled, primary, and so on.</p><p>For example, within a div container are two buttons with identical styles except for their state (active or disabled). To accomplish this, we utilize a Block named card that contains an Element called buttons. From there, we apply Modifier to the buttons we want to assign a state.</p><p>The HTML code</p><pre>&lt;div class=&quot;card&quot;&gt;<br>  &lt;div class=&quot;card__buttons&quot;&gt;<br>    &lt;button class=&quot;card__buttons–active&quot;&gt;&lt;/button&gt;<br>    &lt;button class=&quot;card__buttons–disabled&quot;&gt;&lt;/button&gt;<br>  &lt;/div&gt;<br>&lt;/div&gt;</pre><p>In the code above, we have two modifiers named card__buttons-active and card__buttons-disabled, respectively.</p><p>When creating a name for any entity in the BEM methodology, try to use names that people who are not developers can easily understand.</p><pre>&lt;div class=&quot;card&quot;&gt;<br>  &lt;div class=&quot;card__buttons&quot;&gt;<br>    &lt;button class=&quot;card__buttons–active&quot;&gt;&lt;/button&gt;<br>    &lt;button class=&quot;card__buttons–disabled&quot;&gt;&lt;/button&gt;<br>  &lt;/div&gt;<br>&lt;/div&gt;</pre><p>Even if a non-developer looks at this code, they can easily predict that we are styling buttons on the card and that we assigned one to be active (a state that shows it has already been clicked) and the other to be disabled (a state that makes the button unclickable).</p><p>Modifiers are optional, but if you choose to use them, you need to note these things:</p><ul><li>Use them judiciously and only when essential to prevent needless complications in our code.</li><li>When creating a modifier name, try to be clear and specific about its purpose, like disabling buttons, changing the font size, etc.</li><li>Avoid using a Modifier to override a style. Instead, consider adjusting the style to your desired outcome.</li></ul><h3>Session Replay for Developers</h3><p>Uncover frustrations, understand bugs and fix slowdowns like never before with <a href="https://github.com/openreplay/openreplay">OpenReplay</a> — an open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.<a href="https://github.com/openreplay/openreplay"> Check our GitHub repo </a>and join the thousands of developers in our community.</p><p><em>Happy debugging! </em><a href="https://openreplay.com/">https://openreplay.com/</a></p><h3>The Practical Aspect</h3><p>In this section, we’re going to take a look at a real-world example that demonstrates the BEM methodology.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/392/0*2mxxT_83lhGxPVPQ.jpg" /></figure><p>The case study for this segment is a Card structure built with HTML and CSS — the image above.</p><p>From the image, we can deduce the following entities:</p><ul><li><strong>Block</strong>: The card itself is the Block; it can also be referred to as the Parent of all other elements since other elements are embedded in it.</li><li><strong>Element</strong>: Here, we can say that we have just two direct elements, a header component, and a button component. But in the actual sense, we have five elements — a header element with three elements (image element, title element, and description element) nested within it and a button element that has two actual button elements nested within it.</li><li><strong>Modifier</strong>: Just as I said earlier, modifiers are used in place of setting appearance, and tweaking styles — as its name suggests, it helps us modify styles. In the card above, a modifier was created to disable one of the buttons, i.e., making the button inactive and unclickable.</li></ul><p>Here is the code to create the card above; take a deep look at it — the HTML and CSS code. Try to see how I implemented BEM when defining class names in the semantic HTML and how I structured the classes in CSS following each other from top-to-bottom (this is very important, try to always let your style be in a top-down approach).</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fembed%2Fpreview%2FqBMKoOW%3Fdefault-tabs%3Dhtml%252Cresult%26height%3D600%26host%3Dhttps%253A%252F%252Fcodepen.io%26slug-hash%3DqBMKoOW&amp;display_name=CodePen&amp;url=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fpen%2FqBMKoOW&amp;image=https%3A%2F%2Fshots.codepen.io%2Fusername%2Fpen%2FqBMKoOW-512.jpg%3Fversion%3D1680430563&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/4b361740986f9cbb0ca98fb894932e76/href">https://medium.com/media/4b361740986f9cbb0ca98fb894932e76/href</a></iframe><h3>Resources</h3><p>For more understanding of the subject discussed, you can use these websites:</p><ul><li><a href="https://en.bem.info/">Official BEM Website</a></li><li><a href="https://css-tricks.com/bem-101/">BEM 101</a></li></ul><h3>Conclusion</h3><p>This article explored how the Block Element Modifier (BEM) methodology can aid in writing cleaner, more maintainable CSS code. We analyzed BEM’s history, principles, implementation, and best practices. Although some arguments against BEM exist, many people accept that it offers a clear and consistent approach to organizing CSS code.</p><p>I hope you will consider using BEM in your subsequent projects because of its benefits. The benefits of BEM, such as easier collaboration, faster development time, and reduced errors, make it a valuable tool in modern web development.</p><p><strong>Call to action</strong>: I challenge developers to try implementing BEM in their next project and see the positive impact it can have. Remember to start with a solid foundation by naming and structuring your blocks, elements, and modifiers. With the BEM methodology, you can take your CSS coding skills to the next level and create more efficient and maintainable user interfaces.</p><p>I trust that you found this piece informative and enjoyable. If you have any questions, please don’t hesitate to ask them in the comment box below. Additionally, I would appreciate it if you could share, like, and comment. Thank you for reading.</p><p><em>Originally published at </em><a href="https://blog.openreplay.com/writing-cleaner-css-code-with-bem/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=71bab2bb957a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/writing-cleaner-css-code-with-bem-71bab2bb957a">Writing cleaner CSS code with BEM</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Color types in CSS]]></title>
            <link>https://medium.com/stackanatomy/color-types-in-css-151605b8a299?source=rss-29cfa9c1c0bd------2</link>
            <guid isPermaLink="false">https://medium.com/p/151605b8a299</guid>
            <dc:creator><![CDATA[Bobate Isaac]]></dc:creator>
            <pubDate>Thu, 16 Mar 2023 23:56:31 GMT</pubDate>
            <atom:updated>2023-04-02T21:27:51.183Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QfHoU4y-22ZM25t1GJGxiw.png" /></figure><p>Spot me an object which can’t be attributed to a color! None right? That shows the efficacy of colors in our day-to-day living.</p><p>Colors are important design components as they help produce visually appealing and accessible web pages. As a Web developer, you should understand the different color models in CSS as it helps in implementing effective designs. With the wide range of color types available, knowing where to start is overwhelming, but don’t worry! This article is here to help you navigate the world of colors in CSS.</p><p>In this guide, we will take an in-depth look at the different color types available in CSS. We’ll start by discussing the different color types available in CSS, such as named colors, RGB, and HSL values. We’ll cover additional topics such as RGBA, HSLA, and using the currentColor keyword in CSS.</p><p>By the end of this guide, you will have a solid understanding of using colors in CSS effectively. Let’s dive in and explore the world of color in CSS!</p><h3>Color Syntax in CSS</h3><p>The color specification in CSS is relatively simple but solely depends on the color type. The most common ways to define colors in CSS are using named colors, hexadecimal values, RGB, and HSL values. Each type of color notation has its syntax and rules for defining colors, but they all follow the same basic structure of being a property value representation.</p><p>We use the color property in CSS to set the color of text content within an element. The syntax for using the color property is</p><pre>element {<br>  color: value;<br>}</pre><p>Where element is the HTML element you want to apply the color, and value is the color value you want to set. The value can be any of the color types we discussed earlier, such as named colors, hexadecimal values, RGB, and HSL.For example, the following CSS syntax sets the text color of an element to red:</p><pre>element {<br>  color: red;<br>}</pre><p>or</p><pre>element {<br>  color: #ff0000;<br>}</pre><p>or</p><pre>element {<br>  color: rgb(255, 0, 0);<br>}</pre><p>We also apply the color property to other CSS properties, such as background-color, border-color, and outline-color in controlling the color of these visual elements.</p><h3>currentColor Keyword</h3><p>The currentColor keyword in CSS is a significant method used in controlling the color of multiple elements at once. With the currentColor keyword, you can easily set the color value with a single line of code, making your stylesheets more efficient and maintainable.</p><p>The currentColor keyword refers to the computed value of the color property for an element, and it returns the color value of that element. For example, if you set the color property as red, properties in that element that use currentColor will have that same color (red in this case). It eliminates the need to set the color of each element separately, making it more efficient and easier to maintain the code</p><p><strong>Usage</strong><br>For example, let’s say you have a button class in which you must have the same color for both text and border. Instead of setting the color for both the text and border separately, you can use the currentColor keyword for the border color, like so:</p><pre>.button {<br>  color: green;<br>  border: 3px solid currentColor;<br>}</pre><p>In the example above, we set the text color to green and the border color to the same color (green) using the currentColor keyword. If you change the text color to red, the border color will also change to red automatically. We no longer need to set the border color separately, making maintaining the code more efficient and easier.</p><p><strong>Drawback</strong><br>We can use the currentColor keyword with other properties, such as background-color, background-image, box-shadow, and so on. But it has a little tweak when it is used to determine other color property values like border.</p><p>The currentColor keyword only works for the color property. If you want to use it with other properties such as background-color, you will need the var() function.</p><p>For example:</p><pre>.element {<br>  background-color: red;<br>  border: 2px solid currentColor;<br>}</pre><p>In the code above, the border for the button will remain black since the currentColor keyword doesn&#39;t inherit colors from other properties besides the color property itself.</p><p>But if we implement the color property, the currentColor keyword works.</p><pre>.element {<br>  color: blue;<br>  background-color: red;<br>  border: 2px solid currentColor;<br>}</pre><p>Now, the currentColor keyword works, and the border will inherit the value of the color property as its value (2px solid blue in this case).</p><p>The currentColor keyword is a powerful tool that helps you create consistent and efficient designs with less code. It allows you to set color values once and reuse them throughout your stylesheet, ‌hence implementing the DRY (Do Not Repeat Yourself) principle. It is a great way to keep your code organized and maintainable.</p><h3>Session Replay for Developers</h3><p><em>Uncover frustrations, understand bugs and fix slowdowns like never before with </em><a href="https://github.com/openreplay/openreplay"><strong><em>OpenReplay</em></strong></a><em> — an open-source session replay suite for developers. It can be </em><strong><em>self-hosted</em></strong><em> in minutes, giving you complete control over your customer data</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*03E1xRt_UhsP6mLq.png" /></figure><p><em>Happy debugging! </em><a href="https://openreplay.com"><em>Try using OpenReplay today.</em></a></p><h3>The Color Types</h3><p>There are diverse ways by which we can define colors in CSS. In this section, we will look at some specific color types in CSS and also explore the benefits and drawbacks of each. Here are the color types to be discussed:</p><ul><li>Color Keyword/Named Colors</li><li>RGB (HEX)</li><li>HSL</li><li>RGBa</li><li>HSLa</li></ul><h3>Color Keyword/Named Colors</h3><p>Named color, also known as the color keyword, is a straightforward method of defining color in CSS. Named colors are predefined keyword that corresponds to specific color values. For instance, the color keyword red corresponds to the color value #FF0000.</p><p>CSS provides a set of predefined named colors, such as azure, beige, bisque red, blue, green, yellow, and so on. Browser support for the color keyword is top-notch, as all modern browsers support it. With that, you can confidently use the color keyword method in defining colors, knowing fully well that they will be displayed correctly across various platforms.</p><p>Just as it is defined, here is the syntax for using the named color:</p><pre>element {<br>  color: red;<br>}</pre><p>In the code snippet above, we used the color keyword method to define a color for an element.</p><p>The color keyword is not limited to setting the color property but also defining other properties, such as background color and border color.</p><p><strong>Benefits</strong></p><ol><li><strong>Usage</strong>: This color type is easy to use since they are predefined keywords. Developers do not need to memorize color values to use them.</li><li><strong>Browser Support</strong>: Modern browsers supports them, making them a convenient and versatile option.</li><li><strong>Maintainability</strong>: You can easily update the color value of an element by changing only that color value at that instance instead of searching for all occurrences of that color value throughout the stylesheet. Hence, the color scheme of your web build is easy to maintain.</li><li><strong>Case Insensitive</strong>: CSS color keywords are not case sensitive, disallowing bugs in our stylesheet. For example, red, Red, and RED will all result in the color value #FF0000.</li></ol><p><strong>Drawbacks</strong><br>One major drawback of using named colors is that they do not have a standard definition across different platforms and devices. The appearance of the same named color across devices or browsers might be fully or partially different, which makes it hard to achieve consistent designs across various devices or browsers.</p><p>Note: the color keyword should be used more in places where you do not need to control the transparency of the color since it does not allow you to specify an alpha channel value.</p><h3>RGB</h3><p>RGB is an additive color model that creates colors via a mixture of red, green, and blue light. This color system accepts three parametric values — red, green, and blue. Each value can be a number between 0 and 255, where 0 represents no color and 255 represents the maximum amount of color. It’s also possible to use percentage values instead of integer values — the values range from 0% to 100%. For example, we can represent the red color in RGB as rgb(100%, 0%, 0%).</p><p>We have two ways to express RGB color values: hexadecimal and functional notation.</p><ul><li><strong>Hexadecimal notation</strong> It is commonly called HEX code, a 6-digit code prefixed with the # symbol followed by three pairs of hexadecimal digits, where the pairs represent the amount of red, green, and blue light. Each value is within the range 00 — FF or 0–255 in decimal notation.</li></ul><p>The syntax:</p><pre>element {<br>  color: #rrggbb;<br>}</pre><p>Note: you can also specify each range value with a single value of red, green, and blue. It is valid. See the syntax below:</p><pre>element {<br>  color: #rgb;<br>}</pre><p>That HEX code originates from the RGB color model makes it entitled to conversion to an RGB value and vice versa. We can calculate the RGB values of a HEX color by converting the two-digit hexadecimal values for red, green, and blue to decimal values. For example, the HEX color #ff0000 is equivalent to the RGB color rgb(255, 0, 0).</p><p>Apart from being shorter than RGB values, HEX values also have some added advantages, such as:</p><ol><li><strong>Consistency</strong>: HEX codes are consistent across different platforms and devices, i.e., the color does not vary across various platforms.</li><li><strong>Widely supported</strong>: They are supported by all modern web browsers, making them a reliable and versatile choice for web developers.</li><li><strong>Easier to convert</strong>: we easily convert them to RGB values. Hex values also have some drawbacks, such as:</li><li><strong>Limited range of colors</strong>: HEX color has a limited range of colors compared to other color methods. The total number of colors HEX notation provides — 256 ^ 3, equivalent to 16,777,216.</li><li><strong>Complexity</strong>: HEX values are hard to comprehend. We often find HEX values complex to interpret, as we can not easily deduce the color.</li><li><strong>Precision</strong>: HEX values are less precise than RGB values, which makes it difficult to interpret or specify the exact color you want without using a color picker tool.</li></ol><ul><li><strong>Functional notation</strong> RGB and RGBa are functional notations. These two methods end with the opening ( and ) braces. It symbolizes a function, just as we have in programming languages like JavaScript. In subsequent sections of this article, we will look into the RGBa method. All you have to know is that RGBa is a higher level of RGB; the only difference is the additional alpha value that determines the opacity of the defined color.</li><li><strong>RGB</strong>: As I mentioned earlier, this is a color scheme that takes three parameters, namely red, green, and blue values, just as its name suggests. This color model is very easy-to-use and human-friendly since we know that the integer 0 means we are not using that color, while the integer 255 or 100% means we used all that color. With the use of RGB, some colors can be easily determined - white and black. From the explanation above, you will agree with me that if we want to define a white color, all we have to do is initiate the max value for each of the three parameters, just like this:</li></ul><pre>.element {<br>  color: rgb(255, 255, 255);<br>  color: rgb(100%, 100%, 100%);<br>}</pre><p>The code snippet above will result in a text color of white. And for black, we will set the values of the three parameters to the least value in the range (0–255).</p><pre>.element {<br>  color: rgb(0, 0, 0);<br>}</pre><p>The code snippet above will result in a text color of black. <br> We believe that the primary colors (red, green, and blue) are the easiest to define since you only need to set the color values of the two other color parameters you do not need to 0, while the value of the one you need in the range integer 1–255.</p><p>RGB color model has various advantages, such as a wide range of colors, flexibility of setting colors from very pale shades to very intense ones, a good option for creating color gradients, and great support across all modern web browsers and devices. On the other hand, the RGB color model has some drawbacks, such as complexity, being less intuitive when compared to the color keyword method, and precision (since RGB are in decimal, it is hard to define a particular color without the use of a color wheel).</p><h3>HSL</h3><p>The fact that it is hard to decipher some color models, such as HEX and RGB (in a way), leaves us with an option to find a color model which is more readable and easily understandable by humans. Here is where HSL comes into the picture.</p><p>HSL is an abbreviation that stands for hue, saturation, and lightness. This color model takes in three parameters, just like RGB. Here, we use it to specify colors, where hue is the color itself, saturation is the amount of gray, and lightness represents the brightness of the color. HSL uses these three values to define a color, making it easier to adjust the hue, saturation, and lightness of a color.</p><p><strong>Hue (The color)</strong><br>Hue is the actual color value for an angle (without the unit) on the color wheel. The hue value is between 0° to 360° representing the shade of color on the color wheel. All other hue falls in between these predefined hue values:</p><ul><li>Red is represented as 0° and 360°</li><li>Yellow is represented as 60°</li><li>Green is represented as 120°</li><li>Cyan is represented as 180°</li><li>Blue is represented as 240°</li><li>Magneta is represented as 300°</li></ul><p><strong>Saturation (Intensity of the color)</strong><br>Saturation refers to the intensity of a color, which is the dominance of hue in the color. The value ranges from 0% to 100%, where 0% means a shade of gray — fully desaturated, while a saturation of 100% is a state of full saturation showing a vibrant color.</p><p><strong>Lightness (How bright)</strong><br>It describes the level of brightness of a color. It ranges from 0% to 100%, where 0% represents a dark/black color, and 100% represents a light color.</p><p>Syntax:</p><pre>.element {<br>  hsl(120, 100%, 50%);<br>}</pre><p>The code above results in a shade of green, where the hue value of 120 represents a green hue on the color wheel, the saturation value of 100% means the color is fully saturated, and the lightness value of 50% represents a medium lightness level.</p><p>Here is an interactive demo of HSL:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fembed%2Fpreview%2FKKBYyKW%3Fdefault-tabs%3Dcss%252Cresult%26height%3D600%26host%3Dhttps%253A%252F%252Fcodepen.io%26slug-hash%3DKKBYyKW&amp;display_name=CodePen&amp;url=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fpen%2FKKBYyKW&amp;image=https%3A%2F%2Fshots.codepen.io%2Fshegz101%2Fpen%2FKKBYyKW-512.jpg%3Fversion%3D1675751417&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/1a67e7aa35c0c01c0f30811bca770724/href">https://medium.com/media/1a67e7aa35c0c01c0f30811bca770724/href</a></iframe><p>In the Iframe above, we created a color palette for the visual representation of the HSL model. The color palette, partitioned, is into ten segments showing the saturation and lightness of colors as we move the slider.</p><h3>The Alpha Channel for HSL and RGB</h3><p>The alpha channel refers to the transparency level of a color, where an alpha value of 1.0 represents a fully opaque color, and an alpha value of 0.0 represents a fully transparent color. With RGB, the RGBa color model extends the number of parameters by 1 — an additional value representing the alpha channel. The syntax for creating using RGBs is</p><pre>RGBa(red value, green value, blue value, alpha channel);</pre><p>Where red, green, and blue represent the intensity of the corresponding color channels, just like in the native RGB and alpha, the newly added value is between 0.0 and 1.0, which denotes the level of transparency. For example, the following code sets the background color of an element to a partially transparent red (Half-translucent red):</p><pre>.element {<br>  background-color: RGBa(255, 0, 0, 0.5);<br>}</pre><p>Similarly, the HSLA color model extends the HSL color model by adding an alpha channel to specify the level of transparency. We define the syntax of an HSLA color value in CSS as:</p><pre>hsla(hue, saturation, lightness, alpha);</pre><p>Where hue, saturation, and lightness are the same as in HSL, and alpha is a value between 0.0 and 1.0, representing the level of transparency. For example, the following code sets the text color of an element to transparent blue:</p><pre>.element {<br>  color: hsla(240, 100%, 50%, 0);<br>}</pre><p>Alternatively, RGBa and HSLA can now be defined in a more expressive manner using the RGB function. In <a href="https://www.w3.org/TR/css-color-4/">CSS Color Module Level 4</a>, the HSLA (Hue, Saturation, Lightness, and Alpha) and RGBa (Red, Green, Blue, and Alpha) color models extend to allow for a more flexible and expressive way of defining colors.</p><p>One of the key features of <a href="https://www.w3.org/TR/css-color-4/">CSS Color Module Level 4</a> is the ability to leave space between parameter values in the HSLA and RGBA color models. It means that developers can specify color values using commas and other separators between the parameters. It is a more human-readable syntax and makes it easier for developers to quickly change color values without having concern for syntax errors. In other to use this new format, leave a space between the parameters and add a forward slash before the last parameter, which is the alpha channel.</p><p>For example, the following code specifies a color in HSLA format with a hue of 120, a saturation of 60%, a lightness of 50%, and an alpha value of 0.5.</p><pre>.element {<br>  color: hsl(120 60% 50% / 0.5);<br>}<br><br>.element {<br>  color: rgb(165 0 0 / 0.4);<br>}</pre><p>The CSS Color Module Level 4 provides a more flexible and expressive way of defining colors.</p><h3>Browser Support</h3><p>Modern browsers like Google Chrome, Mozilla Firefox, Apple Safari, and Microsoft Edge support most color schemes. Older versions of Internet Explorer might be the only exception because they might not fully support some of the most recent color schemes, including RGBa and HSLa. The previous color techniques(hex values, named colors) are still usable in these circumstances and are well-supported even by outdated browsers. Testing your designs in multiple browsers is always a good idea to ensure they display as intended.</p><h3>Other Color Alternatives</h3><p>Besides the methods discussed above, there are several other color models by which we can define colors in CSS. These models include:</p><ul><li><strong>HWB (Hue-Whiteness-Blackness) color model</strong>: we use the HWB color model in creating colors with an emphasis on hue, whiteness, and blackness. It is useful when creating color schemes that are easy to read and have pleasant contrast. HTML does not support this color type.</li><li><strong>CMYK (Cyan-Magenta-Yellow-Black) color model</strong>: The CMYK color model is used in the printing industry and is based on subtractive color mixing. We use it to represent colors based on the amount of cyan, magenta, yellow, and black ink required to produce a particular color. HTML does not support this color model.</li><li><strong>LAB (Luminance-Achromatic-Chromatic) color model</strong>: We use the LAB color model in the image and video processing. It is generated based on human color perception. It represents colors by their luminance, chromaticity, and hue. The LAB color model is useful for color correction and color management.</li></ul><h3>Resources</h3><p>For more understanding of the subject discussed, you can use these websites.</p><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value">https://developer.mozilla.org/en-US/docs/Web/CSS/color_value</a></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hwb">https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hwb</a></li><li><a href="https://www.w3schools.com/css/css_colors.asp">https://www.w3schools.com/css/css_colors.asp</a></li></ul><h3>Conclusion</h3><p>This article explores various color models and their representation, as well as the pros and cons of each. We delve into five commonly used methods for defining colors in CSS. When choosing a color model, it is important to consider your specific needs and personal preference.</p><p>Feel free to leave any comments or questions below. If you found this article informative, please share it with your network. Thank you.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*hnE4Jg4AwDNTIbDU.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=151605b8a299" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/color-types-in-css-151605b8a299">Color types in CSS</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Doing pagination with React Query]]></title>
            <link>https://medium.com/stackanatomy/doing-pagination-with-react-query-d6ba0171e954?source=rss-29cfa9c1c0bd------2</link>
            <guid isPermaLink="false">https://medium.com/p/d6ba0171e954</guid>
            <category><![CDATA[react]]></category>
            <category><![CDATA[react-query]]></category>
            <dc:creator><![CDATA[Bobate Isaac]]></dc:creator>
            <pubDate>Thu, 19 Jan 2023 01:41:46 GMT</pubDate>
            <atom:updated>2023-02-01T01:08:43.104Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*G_jQkAgMDZuV2scMCbAPNA.png" /></figure><p>When getting data from a large dataset (an API or a database), developers frequently struggle with presenting it to the user while keeping in mind specific requirements, such as a short load time and an excellent user interface.</p><p>Pagination is one method of resolving this. Using pagination enables developers to separate the data into pages for the end-users. As a result, chunks of large datasets are displayed on different pages, and as the user interacts with the pagination controls, data for each page is fetched and displayed. Pagination is a feature frequently found in applications like learning management systems, product sites (eCommerce with dozens of goods), blog pages, Google search results, and any page with massive data results.</p><p>Constructing the logic to perform pagination can be daunting, as you’ll have to introduce some mathematical programming techniques coupled with React hooks. However, I’ll show you how to use React-Query to implement pagination in this article.</p><h3>Building the application</h3><p>I have created a starter template repository to bootstrap the build process. You will need to clone this GitHub repository to your local desktop.</p><p>First, open your terminal and change the directory to where you want to save the app folder. For example, I want mine to be on the desktop, and I will run the following command.</p><pre>cd desktop</pre><p>Next, clone the starter application to our desktop:</p><pre>git clone https://github.com/shegz101/Pagination-React-Query.git</pre><p>Your folder structure should have the following directories and files:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/161/0*Zcy61TN4Nuyeimu1.jpg" /></figure><h3>Installing dependencies</h3><p>The application has node packages attached to it, and for the build to run smoothly, we must download all the needed dependencies. To do this, run the following command:</p><pre>cd Pagination-React-Query<br>npm install</pre><p>After running the command above, a node module directory gets added to your folder structure.</p><h3>Disconnect from the Remote Git Repository</h3><p>Since this application is now your setup, and you may like to push it to your GitHub account as your project, you must disconnect it from the remote repository (i.e., the repo you cloned the starter folder from).</p><p>You have first to check if this folder is connected to any remote repository by running this:</p><pre>git remote -v</pre><p>You will get the links in the snapshot below as the result of the command above.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/858/0*GYzn-oIUXc1TOfWR.jpg" /></figure><p>The snapshot above tells us that the folder is connected to the git repository link returned.</p><p>Now, to disconnect the folder, run the command below:</p><pre>git remote remove origin</pre><p>The folder is now disconnected. If you run git remote -v, you notice no repository link is returned (proof that the folder has been disconnected).</p><h3>Starting the application</h3><p>To run this application, type this command in your terminal:</p><pre>//not npm start since we used vite and not CRA<br>npm run dev </pre><p>The command above will compile the application and host it at “ <a href="http://localhost:5173/">http://localhost:5173/</a>&quot;. Simply click on the localhost link, and the application will open in your browser.</p><p>Here is what your browser will display:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*BYwAvXzp2OP2yckW.gif" /></figure><p>So far, what we have done in the app is fetch and display the data. With Axios, a package used for HTTP requests, we could fetch data from the API and display it. Try to understand what the starter files entail and how we’ve been able to get to this point (the snapshot above) because this would form the basis of your foundation for this web build, thus the prerequisites.</p><p>We can now move into the central part of this article, which is how to implement pagination using React-Query. I assume you understand the build-up to this point. Let’s get into the nitty-gritty of this article.</p><p>Remember to tidy up your code before starting to use React Query. Simply deleting the posts state from Posts.jsx and the useEffect we used to collect the data will accomplish this. Remove the code that follows:</p><pre>const [posts, setPosts] = useState([]);<br><br>useEffect(() =&gt; {<br>  getPosts(page).then((json) =&gt; setPosts(json));<br>}, [page]);</pre><h3>Open Source Session Replay</h3><p><a href="https://github.com/openreplay/openreplay"><em>OpenReplay</em></a><em> is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*8Uv4SL144jo1F1do.png" /></figure><p><em>Start enjoying your debugging experience — </em><a href="https://github.com/openreplay/openreplay"><em>start using OpenReplay for free</em></a><em>.</em></p><h3>Initialising React Query</h3><p>The official <a href="https://tanstack.com/query/v4/docs/overview">documentation</a> describes React Query as the missing data-fetching library for React. Still, in more technical terms, it makes fetching, caching, synchronizing, and updating server state in your React applications a breeze. In simple terms, React Query is powerful asynchronous state management for React.</p><p>You first need to install the React Query library to get access to the React Query pagination feature. You can do this by running the following command:</p><pre>npm i react-query</pre><p>Next, navigate to the Posts.jsx file and import the useQuery hook from React Query.</p><pre>import { useQuery } from &#39;react-query&#39;;</pre><p>For the best experience, use the useQuery hook and set the KeepPreviousData option to true. We can then access states like:</p><ul><li>isPreviousData - This lets us know the data the query is currently providing.</li><li>isLoading - This lets us know if the data to be fetched is loading</li><li>isError - This lets us know if an error exists</li><li>error - returns the error object</li><li>data - This is the result we get and display on each page</li><li>isFetching - This is the fetching status.</li></ul><p>It should be noted that every useQuery state with the &#39;is&#39; prefix produces a boolean value (true or false). Additionally, the UI is maintained via the KeepPreviousData option even though several queries are made and discarded for each page of data read.</p><p>The useQuery takes two parameters - the queryKey, and the queryFn. The queryKey is a pair of elements in an array. The first element depends on the URL; navigate to the axios.js file and find the line of code that reads const resp = await axiosRequest.get(&#39;/posts?_page=${pageParam}&#39;);, what comes before the question mark (?) which is /posts is the first element and the second is the page state. While the queryFn comprises calling the function to fetch data from the API and setting the keepPreviousData to true. The queryKey is what React Query utilizes to cache the data for each page, and the queryFn is used to fetch the data.</p><p>Let’s put the previous information into practice. Since we are now utilizing React Query to obtain the data, we will no longer use the ‘useEffect’ hook as we previously did. Additionally, since the “posts” array is no longer defined, we won’t be mapping through it; instead, we’ll be mapping through the data array that react-query produces.</p><p>This is what your Posts.jsx file should look like:</p><pre>import &quot;../App.css&quot;;<br>import { getPosts } from &quot;../api/axios&quot;;<br>import { useState } from &quot;react&quot;;<br>import { useQuery } from &quot;react-query&quot;;<br><br>const Posts = () =&gt; {<br>  const [page, setPage] = useState(1);<br><br>  const { isLoading, isError, error, data, isFetching, isPreviousData } =<br>    useQuery({<br>      queryKey: [&quot;/posts&quot;, page],<br>      queryFn: () =&gt; getPosts(page),<br>      keepPreviousData: true,<br>    });<br><br>  return (<br>    &lt;div className=&quot;posts__section&quot;&gt;<br>      &lt;div className=&quot;pages__section&quot;&gt;<br>        &lt;button&gt;prev&lt;/button&gt;<br>        &lt;button&gt;1&lt;/button&gt;<br>        &lt;button&gt;2&lt;/button&gt;<br>        &lt;button&gt;3&lt;/button&gt;<br>        &lt;p&gt;Page {page}&lt;/p&gt;<br>        &lt;button&gt;4&lt;/button&gt;<br>        &lt;button&gt;5&lt;/button&gt;<br>        &lt;p&gt;...&lt;/p&gt;<br>        &lt;button&gt;10&lt;/button&gt;<br>        &lt;button&gt;Next&lt;/button&gt;<br>      &lt;/div&gt;<br><br>      &lt;div className=&quot;blog__posts&quot;&gt;<br>        &lt;div className=&quot;posts&quot;&gt;<br>          {data.map((post) =&gt; (<br>            &lt;div className=&quot;post&quot;&gt;<br>              &lt;p&gt;{post.id}&lt;/p&gt;<br>              &lt;p&gt;{post.title}&lt;/p&gt;<br>              &lt;p&gt;{post.body}&lt;/p&gt;<br>            &lt;/div&gt;<br>          ))}<br>        &lt;/div&gt;<br>      &lt;/div&gt;<br>    &lt;/div&gt;<br>  );<br>};<br><br>export default Posts;</pre><h3>Fixing the No QueryClient Error</h3><p>Finally, React-Query is all set. But there is one crucial piece missing. If you check your browser’s developer tools, you should see a warning in the Console -tab, which says No Queryclient declared.<br> Let&#39;s fix that.</p><ul><li>First, reinstall React-Query with this command:</li></ul><pre>npm i @tanstack/react-query</pre><p>Next, once you’ve reinstalled the library using the npm command above, you’ll also have to re-import the library into your React component by replacing this command:</p><pre>import { useQuery } from &#39;react-query&#39;</pre><p>With this command:</p><pre>import {<br>  QueryClient,<br>  QueryClientProvider,<br>  useQuery,<br>} from &quot;@tanstack/react-query&quot;;</pre><p>We can now override the error we were getting because we have access to the QueryClient.</p><p>It is advisable to create the queryClient outside of your component (Posts), so as not to get your cache (generated from the queryCache, which is embedded in the queryClient) thrown away whenever things like re-rendering occur in the component. This makes it referentially stable. <br> Declare a ‘queryClient’ variable outside of your component to accomplish this:</p><pre>//Create a Client<br>const queryClient = new QueryClient()</pre><p>The next thing is to declare the QueryClient Provider, which creates a context to store the QueryClient and makes it accessible throughout the app.</p><p>Declare the Provider and export it as default using the following code:</p><pre>const PostApp = () =&gt; {<br>  return (<br>    &lt;QueryClientProvider client={queryClient}&gt;<br>      &lt;Posts /&gt;<br>    &lt;/QueryClientProvider&gt;<br>  );<br>};<br><br>export default PostApp;</pre><p>Navigate to your App.jsx file and import the Provider. Your code block in the App.jsx file should look like this:</p><pre>import React from &quot;react&quot;;<br>import &quot;./App.css&quot;;<br>import PostApp from &quot;./components/Posts&quot;;<br><br>function App() {<br>  return (<br>    &lt;div className=&quot;app&quot;&gt;<br>      &lt;h1 className=&quot;app__header&quot;&gt;Random Generated Posts.&lt;/h1&gt;<br>      &lt;PostApp /&gt;<br>    &lt;/div&gt;<br>  );<br>}<br><br>export default App;</pre><h3>Implementing Pagination using the Query Result</h3><p>The query result is returned by useQuery, and contains the information/states needed to use the data. Navigate to the Posts component (Posts.jsx) file; that&#39;s where we would implement pagination.</p><p>We would first map through the data outside of the return block. Rendering of data will be based explicitly on the states/status react-query provides. We want to render data only when it isn’t in the loading/fetching state, and there aren’t any errors while fetching data. This can be done with the help of a control statement — the if, else if, and else statements.</p><p>Create a variable for mapping through the data:</p><pre>const newFetch = (<br>  &lt;div className=&quot;posts&quot;&gt;<br>    {data.map((post) =&gt; (<br>      &lt;div className=&quot;post&quot;&gt;<br>        &lt;p&gt;{post.id}&lt;/p&gt;<br>        &lt;p&gt;{post.title}&lt;/p&gt;<br>        &lt;p&gt;{post.body}&lt;/p&gt;<br>      &lt;/div&gt;<br>    ))}<br>  &lt;/div&gt;<br>);</pre><p>Next, create a function that handles data rendering using control statements.</p><pre>const isPostFetched = () =&gt; {<br>  if (isLoading || isFetching) {<br>    return (<br>      &lt;p style={{ color: &quot;white&quot;, fontSize: &quot;30px&quot;, marginTop: &quot;20px&quot; }}&gt;<br>        Loading Posts....<br>      &lt;/p&gt;<br>    );<br>  } else if (isError) {<br>    return (<br>      &lt;p style={{ color: &quot;white&quot;, fontSize: &quot;30px&quot;, marginTop: &quot;20px&quot; }}&gt;<br>        The Error is: {error.message}<br>      &lt;/p&gt;<br>    );<br>  } else {<br>    return newFetch;<br>  }<br>};</pre><p>To determine what should be rendered on the webpage, we are just checking the status of the data in the code above. We first check if it is in the fetching or loading state, where it should display loading posts...., then we check whether there is an error; if so, we display the error message, and finally, if it is not in any of the aforementioned states, it should provide us with the actual data.</p><p>We can now call the isPostFetched function inside the return block to render data on the web page.</p><pre>&lt;div className=&quot;blog__posts&quot;&gt;{isPostFetched()}&lt;/div&gt;;</pre><h3>The Button Functions</h3><p>Be aware that the functions for the buttons would be hard coded because the API doesn’t return certain helpful information that would have allowed us to perform the task more efficiently. <br> The functions are as follows:</p><pre>const prevPage = () =&gt; setPage((prev) =&gt; prev - 1);<br>const pageOne = () =&gt; setPage(1);<br>const pageTwo = () =&gt; setPage(2);<br>const pageThree = () =&gt; setPage(3);<br>const pageFour = () =&gt; setPage(4);<br>const pageFive = () =&gt; setPage(5);<br>const pageTen = () =&gt; setPage(10);<br>const nextPage = () =&gt; setPage((next) =&gt; next + 1);</pre><p>Next, update the div where the buttons are embedded to this:</p><pre>&lt;div className=&quot;pages__section&quot;&gt;<br>  &lt;button onClick={prevPage} disabled={isPreviousData || page === 1}&gt;<br>    prev<br>  &lt;/button&gt;<br>  &lt;button onClick={pageOne}&gt;1&lt;/button&gt;<br>  &lt;button onClick={pageTwo}&gt;2&lt;/button&gt;<br>  &lt;button onClick={pageThree}&gt;3&lt;/button&gt;<br>  &lt;p&gt;Page {page}&lt;/p&gt;<br>  &lt;button onClick={pageFour}&gt;4&lt;/button&gt;<br>  &lt;button onClick={pageFive}&gt;5&lt;/button&gt;<br>  &lt;p&gt;...&lt;/p&gt;<br>  &lt;button onClick={pageTen}&gt;10&lt;/button&gt;<br>  &lt;button onClick={nextPage} disabled={isPreviousData || page === 10}&gt;<br>    Next<br>  &lt;/button&gt;<br>&lt;/div&gt;;</pre><p>The function for each button was activated in the div above using the onClick event. We also implemented a feature that would disable the prev button if we were on the first page and the next button if we were on the last page.</p><p>Navigate to the App.css file and add this code:</p><pre>button: disabled {<br>  opacity: 0.5;<br>  cursor: not - allowed;<br>}</pre><p>The style code above reduces the opacity of the button color when it is disabled.</p><h3>Final Thoughts</h3><p>The function that triggers each page button to display data was hard coded in this case because the API we used did not return the value of the total number of pages for us.<br>When building an API for a webpage that uses pagination, be sure to return the following data: the current page, the amount of data that will be displayed on each page, the total amount of data being retrieved from the API, and the number of pages based on the formula: total data generated minus total data to be displayed on each page.</p><p>If these are provided, you can easily get the pages array:</p><pre>const pgArray = Array(totalpages {number of pages})<br>  .fill()<br>  .map((_, id) =&gt; id + 1 {id + 1 because index are zero based});</pre><p>Render the page buttons by referencing the PgButtons component.</p><pre>{<br>  pgArray.map((pageNumber) =&gt; (<br>    &lt;PgButtons<br>      key={pageNumber}<br>      pageNumber={pageNumber}<br>      setPage={setPage}<br>      isPreviousData={isPreviousData}<br>    /&gt;<br>  ));<br>}</pre><p>Next, you can create a separate component to display the buttons to keep things clean. Pass the page number, the setPage, and isPreviousData as props.</p><pre>const PgButtons = ({ pageNumber, setPage, isPreviousData }) =&gt; {<br>  return (<br>    &lt;button onClick={() =&gt; setpage(pg)} disabled={isPreviousData}&gt;<br>      {pageNumber}<br>    &lt;/button&gt;<br>  );<br>};</pre><p>That’s how the buttons should be implemented and not hard coded.</p><h3>Overview of the Posts Component</h3><p>If your application still has trouble rendering, check your code in the Posts.jsx file against the following:</p><pre>import &quot;../App.css&quot;;<br>import { getPosts } from &quot;../api/axios&quot;;<br>import { useState } from &quot;react&quot;;<br>// import { useQuery } from &#39;react-query&#39;;<br>import {<br>  QueryClient,<br>  QueryClientProvider,<br>  useQuery,<br>} from &quot;@tanstack/react-query&quot;;<br><br>//Create a Client<br>const queryClient = new QueryClient();<br><br>const Posts = () =&gt; {<br>  const [page, setPage] = useState(1);<br><br>  const { isLoading, isError, error, data, isFetching, isPreviousData } =<br>    useQuery({<br>      queryKey: [&quot;/posts&quot;, page], //used internally for refetching, caching, and sharing your queries throughout your application.<br>      queryFn: () =&gt; getPosts(page),<br>      keepPreviousData: true,<br>    });<br><br>  const newFetch = (<br>    &lt;div className=&quot;posts&quot;&gt;<br>      {data.map((post) =&gt; (<br>        &lt;div className=&quot;post&quot;&gt;<br>          &lt;p&gt;{post.id}&lt;/p&gt;<br>          &lt;p&gt;{post.title}&lt;/p&gt;<br>          &lt;p&gt;{post.body}&lt;/p&gt;<br>        &lt;/div&gt;<br>      ))}<br>    &lt;/div&gt;<br>  );<br><br>  const isPostFetched = () =&gt; {<br>    if (isLoading || isFetching) {<br>      return (<br>        &lt;p style={{ color: &quot;white&quot;, fontSize: &quot;30px&quot;, marginTop: &quot;20px&quot; }}&gt;<br>          Loading Posts....<br>        &lt;/p&gt;<br>      );<br>    } else if (isError) {<br>      return (<br>        &lt;p style={{ color: &quot;white&quot;, fontSize: &quot;30px&quot;, marginTop: &quot;20px&quot; }}&gt;<br>          The Error is: {error.message}<br>        &lt;/p&gt;<br>      );<br>    } else {<br>      return newFetch;<br>    }<br>  };<br><br>  const prevPage = () =&gt; setPage((prev) =&gt; prev - 1);<br>  const pageOne = () =&gt; setPage(1);<br>  const pageTwo = () =&gt; setPage(2);<br>  const pageThree = () =&gt; setPage(3);<br>  const pageFour = () =&gt; setPage(4);<br>  const pageFive = () =&gt; setPage(5);<br>  const pageTen = () =&gt; setPage(10);<br>  const nextPage = () =&gt; setPage((next) =&gt; next + 1);<br><br>  return (<br>    &lt;div className=&quot;posts__section&quot;&gt;<br>      &lt;div className=&quot;pages__section&quot;&gt;<br>        &lt;button onClick={prevPage} disabled={isPreviousData || page === 1}&gt;<br>          prev<br>        &lt;/button&gt;<br>        &lt;button onClick={pageOne}&gt;1&lt;/button&gt;<br>        &lt;button onClick={pageTwo}&gt;2&lt;/button&gt;<br>        &lt;button onClick={pageThree}&gt;3&lt;/button&gt;<br>        &lt;p&gt;Page {page}&lt;/p&gt;<br>        &lt;button onClick={pageFour}&gt;4&lt;/button&gt;<br>        &lt;button onClick={pageFive}&gt;5&lt;/button&gt;<br>        &lt;p&gt;...&lt;/p&gt;<br>        &lt;button onClick={pageTen}&gt;10&lt;/button&gt;<br>        &lt;button onClick={nextPage} disabled={isPreviousData || page === 10}&gt;<br>          Next<br>        &lt;/button&gt;<br>      &lt;/div&gt;<br><br>      &lt;div className=&quot;blog__posts&quot;&gt;{isPostFetched()}&lt;/div&gt;<br>    &lt;/div&gt;<br>  );<br>};<br><br>const PostApp = () =&gt; {<br>  return (<br>    &lt;QueryClientProvider client={queryClient}&gt;<br>      &lt;Posts /&gt;<br>    &lt;/QueryClientProvider&gt;<br>  );<br>};<br><br>export default PostApp;</pre><h3>Conclusion</h3><p>In this article, we learned how to implement pagination using <a href="https://react-query-v3.tanstack.com/">react-query</a>. We learned about the perks of using react-query for handling pagination in our web apps.</p><blockquote><em>A TIP FROM THE EDITOR: If you want infinite scrolling instead of paging, don’t miss </em><a href="https://blog.openreplay.com/infinite-scrolling-with-react-query/"><em>Infinite Scrolling With React Query</em></a><em>.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*D240xkIJxMV6K4yY.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/doing-pagination-with-react-query/"><em>blog.openreplay.com</em></a><em> on January 19, 2023.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d6ba0171e954" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/doing-pagination-with-react-query-d6ba0171e954">Doing pagination with React Query</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CSS Pseudo Elements: A Definite Guide]]></title>
            <link>https://medium.com/stackanatomy/css-pseudo-elements-a-definite-guide-e33516370933?source=rss-29cfa9c1c0bd------2</link>
            <guid isPermaLink="false">https://medium.com/p/e33516370933</guid>
            <category><![CDATA[css]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[pseudo]]></category>
            <category><![CDATA[css3]]></category>
            <dc:creator><![CDATA[Bobate Isaac]]></dc:creator>
            <pubDate>Tue, 06 Dec 2022 01:54:35 GMT</pubDate>
            <atom:updated>2022-12-07T23:04:53.120Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FfR8l-C6t3G-rDyl2EINfQ.png" /></figure><p>Cascading Style Sheet (CSS) pseudo-elements are a handful of CSS features that help us keep our Hypertext Markup Language (HTML) minimal by adding and modifying it directly from the CSS code. For example, you may want to add text before a particular HTML element used in multiple places in the entire code. As we progress in this tutorial, we will examine different CSS pseudo-elements and how to apply them.</p><p>At the end of this article, we’ll have fully grasped the concept behind CSS Pseudo Elements and how to apply them.</p><p>You’ll need a fundamental knowledge of CSS to follow along with the code samples and understand the terminologies used in the article.</p><h3>What are CSS Pseudo Elements?</h3><p>Pseudo-elements are elements that are virtually added to the HTML via CSS code. These elements do not exist in the Document Object Model (DOM). In simple terms, pseudo-elements are elements that can be visualized on the webpage but are created using CSS.</p><p><strong>Note</strong>: Without using the content property, pseudo-elements won’t reflect.</p><h3>Pseudo Elements syntax: CSS 2 vs. CSS 3 syntax</h3><p>The syntax changes between CSS versions:</p><p>CSS 2 Syntax</p><pre>selector:pseudo-element {<br>      property: value;<br>}</pre><p>CSS 3 Syntax</p><pre>selector::pseudo-element {<br>     property: value;<br>}</pre><p>The pseudo-element was initially introduced in CSS2. At that time, the convention for declaring a pseudo-element was that a single colon (:) comes before the pseudo-element text. But now, in CSS3, we use a double colon (::) before the pseudo-element text. This approach was introduced mainly to differentiate between pseudo-classes and pseudo-elements.</p><p>It is believed that if you use either of the two pseudo-elements writing conventions, your code will still work. However, some pseudo-elements only support usage with a double colon (::). Hence, it is advisable to always use a double colon (::) when using pseudo-elements and a single colon (:) when using pseudo-classes.</p><p>As we continue this article, pseudo-elements that support single and double colons will be shown with their respective notation.</p><h3>Types of Pseudo Element</h3><p>For this article, we will only examine five types of pseudo-elements to keep things concise. A study has it that these five types of pseudo-elements are the ones you will often use. The following are the five different CSS pseudo-elements to be discussed:</p><ul><li>::before</li><li>::after</li><li>::first-letter</li><li>::first-line</li><li>::selection</li></ul><p>Pseudo Elements Description</p><p><strong>::before</strong></p><p>This inserts the specified content before the element selected</p><p><strong>::after</strong></p><p>This inserts the specified content after the element selected</p><p><strong>::first-letter</strong></p><p>This is used to style the first letter of the element selected</p><p><strong>::first-line</strong></p><p>This selects the first line of the element selected</p><p><strong>::selection</strong></p><p>This selects and adds styles to the part of the document that the user has highlighted</p><h3>Application/Usage of Pseudo-Elements</h3><p><strong>Note</strong>: To use pseudo-elements, you must first declare the content property and assign it a value. The content property can be assigned the following values and is not limited to these value types:</p><ul><li>String</li></ul><pre>Selector::pseudo-element {<br>    Content: “string”;<br>}</pre><ul><li>Empty String</li></ul><pre> Selector::pseudo-element {<br>    Content: &quot;&quot;;<br> }</pre><ul><li>Url pointing to an image</li></ul><pre>Selector::pseudo-element {<br>    //Just like how background-images are declared<br>    Content: url(“link to image goes in here”);<br>}</pre><p><strong>Note</strong>, when using the URL reference as the `content` property value, you shouldn’t wrap it in quotation marks. Wrapping it in quotation marks makes it be regarded as a string and not a URL reference thereby a string value is returned.</p><p>For example:</p><pre>Selector::pseudo-element {<br>  Content: “url(“link to image goes in here”)”;<br>}</pre><p>The code snippet above will return this string — url() as the content property value.</p><h3>::before (:before)</h3><p>This pseudo-element adds content before the selected Hypertext Hypertext Markup Language (HTML) element. As the name implies, this pseudo-element adds the value assigned to the content property before the selected/targeted element.</p><pre>Selector::before {<br>  content:&quot; &quot;;<br>}</pre><p>We will use the ::before pseudo-element to add a particular text to a group of list items. In place of the text, you can use the url() to add a link to an image to the front of the HTML element you selected.</p><p><strong>Demo</strong>:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fembed%2Fpreview%2FOJZqzyq%3Fdefault-tabs%3Dhtml%252Cresult%26height%3D600%26host%3Dhttps%253A%252F%252Fcodepen.io%26slug-hash%3DOJZqzyq&amp;display_name=CodePen&amp;url=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fpen%2FOJZqzyq&amp;image=https%3A%2F%2Fshots.codepen.io%2Fshegz101%2Fpen%2FOJZqzyq-512.jpg%3Fversion%3D1665834608&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/551fbfc1192f050eb0e308ce9453d438/href">https://medium.com/media/551fbfc1192f050eb0e308ce9453d438/href</a></iframe><h3>::after (:after)</h3><p>The ::after pseudo-element adds content after an HTML element. Like its counterpart (the ::before pseudo-element), this pseudo-element also inserts content, but it&#39;s after the selected element.</p><pre>Selector::after {<br>  content:&quot; &quot;;<br>}</pre><p>Just like the example above, we will use this pseudo-element to display content after selecting the HTML element.</p><p><strong>Demo</strong>:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fembed%2Fpreview%2FvYjPdBq%3Fdefault-tabs%3Dhtml%252Cresult%26height%3D600%26host%3Dhttps%253A%252F%252Fcodepen.io%26slug-hash%3DvYjPdBq&amp;display_name=CodePen&amp;url=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fpen%2FvYjPdBq&amp;image=https%3A%2F%2Fshots.codepen.io%2Fshegz101%2Fpen%2FvYjPdBq-512.jpg%3Fversion%3D1665835588&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/cb73b7844c47c98827a9a72d8d8e6f37/href">https://medium.com/media/cb73b7844c47c98827a9a72d8d8e6f37/href</a></iframe><p><strong>Note</strong>: the two pseudo-elements discussed above are the most used.</p><h3>::first-letter (:first-letter)</h3><p>We often see text whereby the first letter covers one line or more. This letter starts the first word on the number of lines it covers. The ::first-letter pseudo-element is the key to implementing the feature mentioned above. In simple terms, this pseudo-element selects and styles the first letter of the selected element.</p><pre>Selector::first-letter {<br>  content:&quot; &quot;;<br>}</pre><p>Here, we will take a look at how to use this pseudo-element.</p><p><strong>Demo</strong>:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fembed%2Fpreview%2FgOzEdgq%3Fdefault-tabs%3Dhtml%252Cresult%26height%3D600%26host%3Dhttps%253A%252F%252Fcodepen.io%26slug-hash%3DgOzEdgq&amp;display_name=CodePen&amp;url=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fpen%2FgOzEdgq&amp;image=https%3A%2F%2Fshots.codepen.io%2Fshegz101%2Fpen%2FgOzEdgq-512.jpg%3Fversion%3D1665861234&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/77942739af95f1e74bedab1aa4f206b4/href">https://medium.com/media/77942739af95f1e74bedab1aa4f206b4/href</a></iframe><p>You are limited to a set of CSS properties when using this pseudo-element. Properties about layout, such as position, display, and so on, can’t be modified. Also, the browser compatibility for digraphs is very low when using this pseudo-element.</p><h3>::first-line (:first-line)</h3><p>This ::first-line pseudo-element targets just the first line of the selected element and styles it provided it&#39;s a block-level element, not the inline block-level element.</p><pre>Selector::first-line {<br>  content:&quot; &quot;;<br>}</pre><p>Let’s take a look at how we can apply this pseudo-element.</p><p><strong>Demo</strong>:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fembed%2Fpreview%2FQWrPLMg%3Fdefault-tabs%3Dhtml%252Cresult%26height%3D600%26host%3Dhttps%253A%252F%252Fcodepen.io%26slug-hash%3DQWrPLMg&amp;display_name=CodePen&amp;url=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fpen%2FQWrPLMg&amp;image=https%3A%2F%2Fshots.codepen.io%2Fshegz101%2Fpen%2FQWrPLMg-512.jpg%3Fversion%3D1665930914&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/f365b2aaa14546446156c4ad85404af1/href">https://medium.com/media/f365b2aaa14546446156c4ad85404af1/href</a></iframe><h3>::selection (:selection)</h3><p>The ::selection pseudo-element targets any highlighted section on the webpage. When using this pseudo-element, you are limited to specific properties such as color, outline, background, etc.</p><p>Note: this pseudo-element can be used globally in the webpage, whereby any element highlighted gets the defined styles. Below is the syntax for using this pseudo-element globally and for a specific element.</p><pre>//global element syntax<br>::selection {<br>  content:&quot; &quot;;<br>}<br><br>//specific element syntax<br>Selector::selection {<br>  content:&quot; &quot;;<br>}</pre><p>Try highlighting the paragraph and any other text in the demo; you will see the style applied.</p><p><strong>Demo</strong>:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fembed%2Fpreview%2FvYjMBVN%3Fdefault-tabs%3Dhtml%252Cresult%26height%3D600%26host%3Dhttps%253A%252F%252Fcodepen.io%26slug-hash%3DvYjMBVN&amp;display_name=CodePen&amp;url=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fpen%2FvYjMBVN&amp;image=https%3A%2F%2Fshots.codepen.io%2Fshegz101%2Fpen%2FvYjMBVN-512.jpg%3Fversion%3D1665932605&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/8222464cacf1fcba55fb7e108e29d1d4/href">https://medium.com/media/8222464cacf1fcba55fb7e108e29d1d4/href</a></iframe><h3>Open Source Session Replay</h3><p><a href="https://github.com/openreplay/openreplay"><em>OpenReplay</em></a><em> is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*H5D46_mTHC2KCz18.png" /></figure><p><em>Start enjoying your debugging experience — </em><a href="https://github.com/openreplay/openreplay"><em>start using OpenReplay for free</em></a><em>.</em></p><h3>Combination Of the ::before and ::after pseudo-elements</h3><p>In this segment, we will take a deeper look at the two most common pseudo-elements as we will build a simple card box with a default loader design.</p><p>Here is the demo:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fembed%2Fpreview%2FyLjZjXM%3Fdefault-tabs%3Dcss%252Cresult%26height%3D600%26host%3Dhttps%253A%252F%252Fcodepen.io%26slug-hash%3DyLjZjXM&amp;display_name=CodePen&amp;url=https%3A%2F%2Fcodepen.io%2Fshegz101%2Fpen%2FyLjZjXM&amp;image=https%3A%2F%2Fshots.codepen.io%2Fshegz101%2Fpen%2FyLjZjXM-512.jpg%3Fversion%3D1665686329&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/e85e3097f7ba5ff3db036be2ba3747bd/href">https://medium.com/media/e85e3097f7ba5ff3db036be2ba3747bd/href</a></iframe><h3>Resources</h3><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements">MDN docs</a></li><li><a href="https://www.w3schools.com/css/css_pseudo_elements.asp">W3schools</a></li></ul><h3>Conclusion</h3><p>In this article, we learned how to style the content on our webpage using the most used pseudo-elements. Using the example scripts in the demo area, we also learned about the guidelines for using pseudo-elements, when to use them, and how to apply them.</p><blockquote><em>A TIP FROM THE EDITOR: Do not miss our </em><a href="https://blog.openreplay.com/modern-css-selectors/"><em>Modern CSS Selectors</em></a><em> article for more on current CSS features!</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gAIrJoHribKzIIvq.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/css-pseudo-elements--a-definite-guide/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e33516370933" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/css-pseudo-elements-a-definite-guide-e33516370933">CSS Pseudo Elements: A Definite Guide</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a Video Player with React and Material UI]]></title>
            <link>https://medium.com/stackanatomy/building-a-video-player-with-react-and-material-ui-1e4cc105e084?source=rss-29cfa9c1c0bd------2</link>
            <guid isPermaLink="false">https://medium.com/p/1e4cc105e084</guid>
            <category><![CDATA[material-design]]></category>
            <category><![CDATA[material-ui]]></category>
            <category><![CDATA[videos]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Bobate Isaac]]></dc:creator>
            <pubDate>Wed, 19 Oct 2022 23:08:00 GMT</pubDate>
            <atom:updated>2022-10-19T23:08:00.953Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1_rZGhAtcU4DXIrVMbVm_w.png" /></figure><p>Video assets are quickly taking over as the preferred method of product promotion on websites. Thus, developers need to understand how to create and modify video players to meet the requirements of their websites.</p><p>In this article, I’ll demonstrate how to develop a video player using the <a href="https://www.npmjs.com/package/react-player">react-player</a> package and style it with <a href="https://mui.com/">Material UI</a>, so you can make a video player that perfectly suits the requirements of your next web build.</p><p>This article’s primary purpose is to assist readers in creating and customizing their video players in accordance with their preferences. However, if you prefer a program that you can simply install to gain access to a fully developed and personalized video player, take a look at the <a href="https://muiplayer.js.org/">Mui player</a>. Also, be aware that this service has drawbacks, including the inability to adjust the video player to your preferences.</p><h3>What is React Player?</h3><p>React player is a component used in rendering various video assets, including YouTube, Facebook, Twitch, SoundCloud, Streamable, Vimeo, Wistia, Mixcloud, DailyMotion, and so on. React player is a package used to create video players that supports various video sources and types.</p><p>The first thing to do is to bootstrap a new React project using the Create React App (CRA) bundler. Inside the project folder, install the needed dependencies.</p><p>First, we have to install the <a href="https://www.npmjs.com/package/react-player">react-player</a> by typing the code below into your project terminal:</p><pre>npm i react-player</pre><p>Next, we have to install <a href="https://mui.com/">Material UI</a> for styling the video player:</p><pre>npm install @mui/material @emotion/react @emotion/styled</pre><p>Still, on <a href="https://mui.com/">Material UI</a>, we have to install the SVG icons. Icons are the major thing we want to import from Material UI. Use the code below to import and have access to the material UI icons:</p><pre>npm install @mui/icons-material</pre><p>And lastly, we will install <a href="https://www.npmjs.com/package/screenfull">screenfull</a>, the package for bringing our video player into full-screen mode.</p><pre>npm i screenfull</pre><p>You have to clean up the default folder structure for the build by deleting the logo file and removing everything in the return block inside the App.js file.</p><p>Your App.js file should look like this:</p><pre>import * as React from &#39;react&#39;; <br>import &#39;./App.css&#39;;  <br>function App() { <br>  return (      <br>     &lt;&gt; <br>      <br>     &lt;/&gt;    <br>  ); <br>}  <br>export default App;</pre><p>Next, import the react-player and screenfull in your App.js file.</p><pre>import ReactPlayer from &#39;react-player&#39;;<br>import screenfull from &#39;screenfull&#39;;</pre><p>Let’s create a simple header for the web app by updating our App.js file with this:</p><pre>import &#39;./App.css&#39;;<br>import ReactPlayer from &#39;react-player&#39;;<br>import screenfull from &#39;screenfull&#39;;</pre><pre>function App() {<br>  return (<br>    &lt;&gt;<br>      &lt;header className=&#39;header__section&#39;&gt;<br>        &lt;p className=&#39;header__text&#39;&gt;Build a Video Player - Tutorial&lt;/p&gt;<br>      &lt;/header&gt;<br>    &lt;/&gt;<br>  );<br>}</pre><pre>export default App;</pre><p>Navigate to your App.css file and add the code below to style the header:</p><pre>* {<br>  margin: 0;<br>  box-sizing: border-box;<br>}</pre><pre>.header__section {<br>  text-align: center;<br>  justify-content: center;<br>  align-items: center;<br>  height: 40px;<br>  background-color: rgb(70, 70, 172);<br>}</pre><pre>.header__text {<br>  color: white;<br>  font-size: 28px;<br>  font-weight: 800;<br>  font-family: Georgia, &#39;Times New Roman&#39;, Times, serif;<br>  padding-top: 5px;<br>  padding-bottom: 5px;<br>}</pre><p>Note, clean up the App.css file before adding the code above.</p><p>We want to get our video URL and preview the video using the react-player package.</p><p><a href="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4">Here</a> is the link to the video sample we will use in this article, and we get the link from this <a href="https://gist.github.com/deepakpk009/99fd994da714996b296f11c3c371d5ee">github gist sample for free video URLs</a>.</p><p>In the App.js file, import the container wrapper from the Material UI, where we&#39;ll include our React player and Controls.</p><pre>import * as React from &#39;react&#39;;<br>import &#39;./App.css&#39;;<br>import ReactPlayer from &#39;react-player&#39;;<br>import screenfull from &#39;screenfull&#39;;<br>import Container from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>/Container&#39;;</pre><pre>function App() {<br>  return (<br>    &lt;&gt;<br>      &lt;header className=&#39;header__section&#39;&gt;<br>        &lt;p className=&#39;header__text&#39;&gt;Build a Video Player - Tutorial&lt;/p&gt;<br>      &lt;/header&gt;<br>      &lt;Container maxWidth=&quot;md&quot;&gt;<br>        &lt;div className=&#39;playerDiv&#39;&gt;<br>          &lt;ReactPlayer width={&#39;100%&#39;} height=&#39;100%&#39; url=&quot;<a href="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4">http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4</a>&quot;/&gt;<br>        &lt;/div&gt;<br>      &lt;/Container&gt;<br>    &lt;/&gt;<br>  );<br>}</pre><pre>export default App;</pre><p>Navigate to your App.css file and style the Player Div using the code below:</p><pre>.playerDiv {<br>  width:100%;<br>  position: relative;<br>}</pre><p>If you run npm start to preview the video player on the browser, you will see this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rWg6OoLnY7xLNure.jpg" /></figure><p>In the snapshot above, the react-player renders our sample video. Still, there seems not to be any video displayed because we’ve not added the needed props for that functionality.</p><p>To fix that, add a playing prop and a muted prop to the ReactPlayer component, and set the props to true, as shown in the code below:</p><pre>&lt;ReactPlayer width={&#39;100%&#39;} height=&#39;100%&#39;    <br>url=&quot;<a href="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4">http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4</a>&quot;<br>playing={true}<br>muted={true}<br>/&gt;</pre><p>In the code above, we included the playing and muted props to enable our sample video to play. In place of the props’ default values of false, we set a value of true. The code above produces the playing video seen in the illustration below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/839/0*KARsWipELLzdeohs.jpg" /></figure><p>Since there are no controls present, the video player is not interactive. Controls, a prop in the react-player package, has the value false by default. The video player’s controls are automatically added when the value is updated to true.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/843/0*R1zt-MR37fwtofqd.jpg" /></figure><p>The controls prop adds the controls in the image above to your video player. But some controls we want our video player to have are not part of the controls react-player provides. For example, we don&#39;t have the fast forward and rewind features, hence the reason for customizing ours.</p><h3>The Controls</h3><p>The picture below is a visual representation of the functionalities of our Video Player.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/837/0*YHVle6hlz_v6ooHm.jpg" /></figure><p>From the image above, we can see that this video player has the following features:</p><ul><li>Movie title</li><li>Pause and Play</li><li>Fast Forward and Rewind</li><li>Muting</li><li>Volume increase and decrease</li><li>Playback Speed</li><li>Fullscreen Mode</li></ul><h3>Importing and Styling the Controls</h3><p>The controls are divided into the top, middle, and bottom.</p><p>Let’s get into the code:</p><p>First, import the ControlIcons component into the App.js file by updating your App.js file with the following code:</p><pre>import * as React from &#39;react&#39;;<br>import &#39;./App.css&#39;;<br>import ReactPlayer from &#39;react-player&#39;;<br>import screenfull from &#39;screenfull&#39;;<br>import Container from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>/Container&#39;;<br>import ControlIcons from &#39;./Components/ControlIcons&#39;;</pre><pre>function App() {<br>  return (<br>    &lt;&gt;<br>      &lt;header className=&#39;header__section&#39;&gt;<br>        &lt;p className=&#39;header__text&#39;&gt;Build a Video Player - Tutorial&lt;/p&gt;<br>      &lt;/header&gt;<br>      &lt;Container maxWidth=&quot;md&quot;&gt;<br>        &lt;div className=&#39;playerDiv&#39;&gt;<br>          &lt;ReactPlayer width={&#39;100%&#39;} height=&#39;100%&#39;<br>          url=&quot;<a href="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4">http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4</a>&quot;<br>          playing={true}<br>          muted={true}<br>          controls={true}<br>          /&gt;<br>          &lt;ControlIcons/&gt;<br>        &lt;/div&gt;<br>      &lt;/Container&gt;<br>    &lt;/&gt;<br>  );<br>}</pre><pre>export default App;</pre><p>Next, navigate to ControlIcons.jsx file, and let’s get right into importing the controls segment by segment. Update its contents:</p><pre>import React from &#39;react&#39;;<br>import &#39;./ControlIcons.css&#39;;</pre><pre>const ControlIcons = () =&gt; {<br>    return (<br>        &lt;div className=&quot;controls__div&quot;&gt;<br>            <br>        &lt;/div&gt;<br>    )<br>}</pre><pre>export default ControlIcons;</pre><p>We must apply some styles, such as the position of absolute, to the div with a className of controls__div to allow our controls to overlap the video.</p><p>Inside the ControlsIcons.css file, add this:</p><pre>.controls__div {<br>    position:absolute;<br>    top: 0;<br>    bottom: 0;<br>    left: 0;<br>    right: 0;<br>    display: flex;<br>    flex-direction: column;<br>    justify-content: space-between;<br>    z-index: 2;<br>    background: rgba(0,0,0,0.6);<br>}</pre><p>Our style will use the Grid wrapper from Material UI. We now begin with the top section, where we only want the word &quot;Player&quot; to be visible.</p><p>For this, we first have to import Grid and Typography (where the text to be displayed is written; this is the way to display a text when using material UI for styling).</p><pre>import React from &#39;react&#39;;<br>import &#39;./ControlIcons.css&#39;;<br>import Grid from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>/Grid&#39;;<br>import Typography from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>/Typography&#39;;</pre><pre>const ControlIcons = () =&gt; {<br>    return (<br>        &lt;div className=&quot;controls__div&quot;&gt;<br>            <br>        &lt;/div&gt;<br>    )<br>}</pre><pre>export default ControlIcons;</pre><p>The following code should be added to your ControlIcons.jsx file to display the top section text (which is &quot;Player&quot; ):</p><pre>import React from &#39;react&#39;;<br>import &#39;./ControlIcons.css&#39;;<br>import Grid from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>/Grid&#39;;<br>import Typography from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>/Typography&#39;;</pre><pre>const ControlIcons = () =&gt; {<br>    return (<br>        &lt;div className=&quot;controls__div&quot;&gt;<br>            {/* Top Segment */}<br>           &lt;Grid container direction=&#39;row&#39; alignItems=&#39;center&#39; justifyContent=&#39;start&#39; style={{padding: 16 }}&gt;<br>              &lt;Grid item&gt;<br>                &lt;Typography variant=&#39;h5&#39; style={{color:&#39;white&#39;}}&gt;Player&lt;/Typography&gt;<br>              &lt;/Grid&gt;<br>           &lt;/Grid&gt;<br>        &lt;/div&gt;<br>    )<br>}</pre><pre>export default ControlIcons;</pre><p>In the code snippet above, we employ a Grid wrapper that acts as a container to hold the text “Player”. This Grid was given some positional parameters, and we then added the inline style padding: 16px to it. The item to be placed inside the container was then represented by another Grid wrapper, and the text was then displayed using the Typography wrapper.</p><p>Let’s move on to the middle section. Here we have three buttons: rewind, play, and fast-forward.</p><p>As usual, the first step is to import the needed icons. Add the following imports to your ControlIcons.jsx file.</p><pre>import { IconButton } from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>&#39;;<br>import { FastRewind } from &#39;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&#39;;<br>import { FastForwardSharp } from &#39;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&#39;;<br>import { PlayArrowSharp } from &#39;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&#39;;</pre><p>Next, let’s make use of the icons that we imported. Do this:</p><pre>&lt;Grid container direction=&#39;row&#39; alignItems=&#39;center&#39; justifyContent=&#39;center&#39;&gt;<br>        &lt;IconButton className=&#39;controls__icons&#39; aria-label=&#39;reqind&#39;&gt;<br>           &lt;FastRewind fontSize=&#39;large&#39; style={{color:&#39;white&#39;}}/&gt;<br>        &lt;/IconButton&gt;</pre><pre>&lt;IconButton className=&#39;controls__icons&#39; aria-label=&#39;reqind&#39;&gt;<br>             &lt;PlayArrowSharp fontSize=&#39;large&#39; style={{color:&#39;white&#39;}}/&gt;<br>        &lt;/IconButton&gt;</pre><pre>&lt;IconButton className=&#39;controls__icons&#39; aria-label=&#39;reqind&#39;&gt;<br>             &lt;FastForwardSharp fontSize=&#39;large&#39; style={{color:&#39;white&#39;}}/&gt;<br>        &lt;/IconButton&gt;<br> &lt;/Grid&gt;</pre><p>In the code above, we simply created a Grid (Container) where all three icons live; we applied some value to this Grid which determines how the icons are positioned. And lastly, we displayed all three icons using the IconButton wrapper Material UI provides. For each of the IconButton wrappers, we added a className called controls__icons. In the code above, all three icons are contained in a Grid (Container), and a value is applied to this Grid to determine how the icons are positioned. And lastly, we displayed all three icons using the IconButton wrapper Material UI provides. For each of the IconButton wrappers, we added a className called controls__icons.</p><p>Here is the style for the div with className of controls__icons:</p><pre>.controls__icons {<br>    color: white;<br>    font-size: 50;<br>    transform:scale(0.9);<br>}</pre><pre>.controls__icons:hover {<br>    color: #fff;<br>    transform:scale(1);<br>}</pre><p>And lastly, we move to the third section. This section has sub-sections: the video’s title, the player slider, and the last group of controls.</p><p>First, import the icons using the following code:</p><pre>import Button from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>/Button&#39;;<br>import Slider from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>/Slider&#39;;<br>import { styled } from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>/styles&#39;;<br>import { VolumeUp } from &#39;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&#39;;<br>import { Fullscreen } from &#39;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&#39;;</pre><p>We then add the code for the first category (the video title) in this section and create the Grid (container) that houses the entire bottom segment. Here is the code to execute the previous statement:</p><pre>{/* Bottom Section */}<br>&lt;Grid container direction=&#39;row&#39; alignItems=&#39;center&#39; justifyContent=&#39;space-between&#39; style={{padding: 16}}&gt;<br>      &lt;Grid item&gt;<br>            &lt;Typography variant=&#39;h5&#39; style={{color:&#39;white&#39;}}&gt;Tears Of Steel&lt;/Typography&gt;<br>       &lt;/Grid&gt;<br>&lt;/Grid&gt;</pre><p>From the code above, it can be derived that this bottom section is embedded inside a container given a direction of row and justifyContent of space-between, which renders the bottom component with equal space between all the categories.</p><p>Let’s go on to the next category (the video player slider). We’ll use the ‘PrettoSlider’ pre-built slider from the material UI. There is a function needed to use the slider. We will use the PrettoSlider as a component wherever we want to display it after adding the function from the code snippet below to your “ControlIcons.jsx” file.</p><p>PrettoSlider Function:</p><pre>const PrettoSlider = styled(Slider)({<br>  height: 5,<br>  &quot;&amp; .MuiSlider-track&quot;: {<br>    border: &quot;none&quot;,<br>  },<br>  &quot;&amp; .MuiSlider-thumb&quot;: {<br>    height: 16,<br>    width: 16,<br>    backgroundColor: &quot;#fff&quot;,<br>    border: &quot;2px solid currentColor&quot;,<br>    &quot;&amp;:focus, &amp;:hover, &amp;.Mui-active, &amp;.Mui-focusVisible&quot;: {<br>      boxShadow: &quot;inherit&quot;,<br>    },<br>    &quot;&amp;:before&quot;: {<br>      display: &quot;none&quot;,<br>    },<br>  },<br>  &quot;&amp; .MuiSlider-valueLabel&quot;: {<br>    lineHeight: 1.2,<br>    fontSize: 12,<br>    background: &quot;unset&quot;,<br>    padding: 0,<br>    width: 32,<br>    height: 32,<br>    borderRadius: &quot;50% 50% 50% 0&quot;,<br>    backgroundColor: &quot;#52af77&quot;,<br>    transformOrigin: &quot;bottom left&quot;,<br>    transform: &quot;translate(50%, -100%) rotate(-45deg) scale(0)&quot;,<br>    &quot;&amp;:before&quot;: { display: &quot;none&quot; },<br>    &quot;&amp;.MuiSlider-valueLabelOpen&quot;: {<br>      transform: &quot;translate(50%, -100%) rotate(-45deg) scale(1)&quot;,<br>    },<br>    &quot;&amp; &gt; *&quot;: {<br>      transform: &quot;rotate(45deg)&quot;,<br>    },<br>  },<br>});</pre><p>Now use the PrettoSlider as a component:</p><pre>{/* Bottom Section */}<br>&lt;Grid<br>  container<br>  direction=&quot;row&quot;<br>  alignItems=&quot;center&quot;<br>  justifyContent=&quot;space-between&quot;<br>  style={{ padding: 16 }}<br>&gt;<br>  &lt;Grid item&gt;<br>    &lt;Typography variant=&quot;h5&quot; style={{ color: &quot;white&quot; }}&gt;<br>      Tears Of Steel<br>    &lt;/Typography&gt;<br>  &lt;/Grid&gt;</pre><pre>&lt;Grid item xs={12}&gt;<br>    &lt;PrettoSlider min={0} max={100} defaultValue={20} /&gt;<br>    &lt;Grid container direction=&quot;row&quot; justifyContent=&quot;space-between&quot;&gt;<br>      &lt;Typography variant=&quot;h7&quot; style={{ color: &quot;white&quot; }}&gt;<br>        00:26<br>      &lt;/Typography&gt;<br>      &lt;Typography variant=&quot;h7&quot; style={{ color: &quot;white&quot; }}&gt;<br>        12:30<br>      &lt;/Typography&gt;<br>    &lt;/Grid&gt;<br>  &lt;/Grid&gt;<br>&lt;/Grid&gt;</pre><p>We provided the PrettoSlider with specific props, including a default value, the terms “min” for minimum value and “max” for maximum value. Next, we added some digits to show the video’s duration and total watch time.</p><p>The play button, volume up, volume slider, playback speed, and full screen are the icons found in the last category.</p><p>We will use the “IconButton wrapper” to display the icons and render the volume slider by giving it the className “volume slider” and some parameters with default values.</p><pre>&lt;Grid item&gt;<br>  &lt;Grid container alignItems=&quot;center&quot; direction=&quot;row&quot;&gt;<br>    &lt;IconButton className=&quot;controls__icons&quot; aria-label=&quot;reqind&quot;&gt;<br>      &lt;PlayArrowSharp fontSize=&quot;large&quot; style={{ color: &quot;white&quot; }} /&gt;<br>    &lt;/IconButton&gt;</pre><pre>&lt;IconButton className=&quot;controls__icons&quot; aria-label=&quot;reqind&quot;&gt;<br>      &lt;VolumeUp fontSize=&quot;large&quot; style={{ color: &quot;white&quot; }} /&gt;<br>    &lt;/IconButton&gt;</pre><pre>&lt;Typography style={{ color: &quot;#fff&quot;, paddingTop: &quot;5px&quot; }}&gt;40&lt;/Typography&gt;<br>    &lt;Slider min={0} max={100} defaultValue={100} className=&quot;volume__slider&quot; /&gt;<br>  &lt;/Grid&gt;<br>&lt;/Grid&gt;</pre><p>Here is the code to style the Volume Slider:</p><pre>.volume__slider {<br>    width: 100;<br>    margin-top: -50px;<br>    margin-left: 130px;<br>}</pre><p>Now let’s add the playback speed rate and the full-screen icon. Using the code below, display the text and icon in your video player.</p><pre>&lt;Grid item&gt;<br>  &lt;Button variant=&quot;text&quot; className=&quot;bottom__icons&quot;&gt;<br>    &lt;Typography&gt;1X&lt;/Typography&gt;<br>  &lt;/Button&gt;</pre><pre>&lt;IconButton className=&quot;bottom__icons&quot;&gt;<br>    &lt;Fullscreen fontSize=&quot;large&quot; /&gt;<br>  &lt;/IconButton&gt;<br>&lt;/Grid&gt;</pre><p>Here is the style for the className of bottom__icons:</p><pre>.bottom__icons {<br>    color:#999;<br>}</pre><pre>.bottom__icons:hover {<br>    color: white;<br>}</pre><p>When you preview the app, you should see a video player rendered with all the imported and styled buttons and icons.</p><p>In case you are running into errors at this point, simply crosscheck your code with the one below:</p><pre>import React from &quot;react&quot;;<br>import &quot;./ControlIcons.css&quot;;<br>import Grid from &quot;<a href="http://twitter.com/mui/material">@mui/material</a>/Grid&quot;;<br>import Typography from &quot;<a href="http://twitter.com/mui/material">@mui/material</a>/Typography&quot;;<br>import { IconButton } from &quot;<a href="http://twitter.com/mui/material">@mui/material</a>&quot;;<br>import { FastRewind } from &quot;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&quot;;<br>import { FastForwardSharp } from &quot;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&quot;;<br>import { PlayArrowSharp } from &quot;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&quot;;<br>import Button from &quot;<a href="http://twitter.com/mui/material">@mui/material</a>/Button&quot;;<br>import Slider from &quot;<a href="http://twitter.com/mui/material">@mui/material</a>/Slider&quot;;<br>import { styled } from &quot;<a href="http://twitter.com/mui/material">@mui/material</a>/styles&quot;;<br>import { VolumeUp } from &quot;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&quot;;<br>import { Fullscreen } from &quot;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&quot;;</pre><pre>const ControlIcons = () =&gt; {<br>  const PrettoSlider = styled(Slider)({<br>    height: 5,<br>    &quot;&amp; .MuiSlider-track&quot;: {<br>      border: &quot;none&quot;,<br>    },<br>    &quot;&amp; .MuiSlider-thumb&quot;: {<br>      height: 16,<br>      width: 16,<br>      backgroundColor: &quot;#fff&quot;,<br>      border: &quot;2px solid currentColor&quot;,<br>      &quot;&amp;:focus, &amp;:hover, &amp;.Mui-active, &amp;.Mui-focusVisible&quot;: {<br>        boxShadow: &quot;inherit&quot;,<br>      },<br>      &quot;&amp;:before&quot;: {<br>        display: &quot;none&quot;,<br>      },<br>    },<br>    &quot;&amp; .MuiSlider-valueLabel&quot;: {<br>      lineHeight: 1.2,<br>      fontSize: 12,<br>      background: &quot;unset&quot;,<br>      padding: 0,<br>      width: 32,<br>      height: 32,<br>      borderRadius: &quot;50% 50% 50% 0&quot;,<br>      backgroundColor: &quot;#52af77&quot;,<br>      transformOrigin: &quot;bottom left&quot;,<br>      transform: &quot;translate(50%, -100%) rotate(-45deg) scale(0)&quot;,<br>      &quot;&amp;:before&quot;: { display: &quot;none&quot; },<br>      &quot;&amp;.MuiSlider-valueLabelOpen&quot;: {<br>        transform: &quot;translate(50%, -100%) rotate(-45deg) scale(1)&quot;,<br>      },<br>      &quot;&amp; &gt; *&quot;: {<br>        transform: &quot;rotate(45deg)&quot;,<br>      },<br>    },<br>  });<br>  return (<br>    &lt;div className=&quot;controls__div&quot;&gt;<br>      {/* Top Segment */}<br>      &lt;Grid<br>        container<br>        direction=&quot;row&quot;<br>        alignItems=&quot;center&quot;<br>        justifyContent=&quot;start&quot;<br>        style={{ padding: 16 }}<br>      &gt;<br>        &lt;Grid item&gt;<br>          &lt;Typography variant=&quot;h5&quot; style={{ color: &quot;white&quot; }}&gt;<br>            Player<br>          &lt;/Typography&gt;<br>        &lt;/Grid&gt;<br>      &lt;/Grid&gt;</pre><pre>{/* Middle Segment */}<br>      &lt;Grid<br>        container<br>        direction=&quot;row&quot;<br>        alignItems=&quot;center&quot;<br>        justifyContent=&quot;center&quot;<br>      &gt;<br>        &lt;IconButton className=&quot;controls__icons&quot; aria-label=&quot;reqind&quot;&gt;<br>          &lt;FastRewind fontSize=&quot;large&quot; style={{ color: &quot;white&quot; }} /&gt;<br>        &lt;/IconButton&gt;</pre><pre>&lt;IconButton className=&quot;controls__icons&quot; aria-label=&quot;reqind&quot;&gt;<br>          &lt;PlayArrowSharp fontSize=&quot;large&quot; style={{ color: &quot;white&quot; }} /&gt;<br>        &lt;/IconButton&gt;</pre><pre>&lt;IconButton className=&quot;controls__icons&quot; aria-label=&quot;reqind&quot;&gt;<br>          &lt;FastForwardSharp fontSize=&quot;large&quot; style={{ color: &quot;white&quot; }} /&gt;<br>        &lt;/IconButton&gt;<br>      &lt;/Grid&gt;</pre><pre>{/* Bottom Segment */}<br>      &lt;Grid<br>        container<br>        direction=&quot;row&quot;<br>        alignItems=&quot;center&quot;<br>        justifyContent=&quot;space-between&quot;<br>        style={{ padding: 16 }}<br>      &gt;<br>        &lt;Grid item&gt;<br>          &lt;Typography variant=&quot;h5&quot; style={{ color: &quot;white&quot; }}&gt;<br>            Tears Of Steel<br>          &lt;/Typography&gt;<br>        &lt;/Grid&gt;</pre><pre>&lt;Grid item xs={12}&gt;<br>          &lt;PrettoSlider min={0} max={100} defaultValue={20} /&gt;<br>          &lt;Grid container direction=&quot;row&quot; justifyContent=&quot;space-between&quot;&gt;<br>            &lt;Typography variant=&quot;h7&quot; style={{ color: &quot;white&quot; }}&gt;<br>              00:26<br>            &lt;/Typography&gt;<br>            &lt;Typography variant=&quot;h7&quot; style={{ color: &quot;white&quot; }}&gt;<br>              12:30<br>            &lt;/Typography&gt;<br>          &lt;/Grid&gt;<br>        &lt;/Grid&gt;</pre><pre>&lt;Grid item&gt;<br>          &lt;Grid container alignItems=&quot;center&quot; direction=&quot;row&quot;&gt;<br>            &lt;IconButton className=&quot;controls__icons&quot; aria-label=&quot;reqind&quot;&gt;<br>              &lt;PlayArrowSharp fontSize=&quot;large&quot; style={{ color: &quot;white&quot; }} /&gt;<br>            &lt;/IconButton&gt;</pre><pre>&lt;IconButton className=&quot;controls__icons&quot; aria-label=&quot;reqind&quot;&gt;<br>              &lt;VolumeUp fontSize=&quot;large&quot; style={{ color: &quot;white&quot; }} /&gt;<br>            &lt;/IconButton&gt;</pre><pre>&lt;Typography style={{ color: &quot;#fff&quot;, paddingTop: &quot;5px&quot; }}&gt;<br>              40<br>            &lt;/Typography&gt;<br>            &lt;Slider<br>              min={0}<br>              max={100}<br>              defaultValue={100}<br>              className=&quot;volume__slider&quot;<br>            /&gt;<br>          &lt;/Grid&gt;<br>        &lt;/Grid&gt;</pre><pre>&lt;Grid item&gt;<br>          &lt;Button variant=&quot;text&quot; className=&quot;bottom__icons&quot;&gt;<br>            &lt;Typography&gt;1X&lt;/Typography&gt;<br>          &lt;/Button&gt;</pre><pre>&lt;IconButton className=&quot;bottom__icons&quot;&gt;<br>            &lt;Fullscreen fontSize=&quot;large&quot; /&gt;<br>          &lt;/IconButton&gt;<br>        &lt;/Grid&gt;<br>      &lt;/Grid&gt;<br>    &lt;/div&gt;<br>  );<br>};</pre><pre>export default ControlIcons;</pre><p>When you preview, you should have a replica of the image below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/837/0*kkqEIEnxSzYjkMu-.jpg" /></figure><p>You’ll see that the buttons are not interactive and must be activated if you try clicking on them. This brings us to the article’s final section, Activating the Controls.</p><h3>Open Source Session Replay</h3><p><a href="https://github.com/openreplay/openreplay"><em>OpenReplay</em></a><em> is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/768/0*ZWG5ybRugw_Isdeb.png" /></figure><p><em>Start enjoying your debugging experience — </em><a href="https://github.com/openreplay/openreplay"><em>start using OpenReplay for free</em></a><em>.</em></p><h3>Activating the Controls</h3><p>We will proceed in this part in a logical order, beginning at the top. This means we’ll start by activating the controls for the middle part.</p><p>Navigate into the App.js file, and we’ll start by creating a state called playerState. This state is an object with six properties: playing, mute, playerbackRate, played, volume, and seeking.</p><pre>const [playerstate, setPlayerState] = useState({<br>    playing: true,<br>    mute: true,<br>    volume: 0.5,<br>    playerbackRate:1.0,<br>    played:0,<br>    seeking: false,<br>})</pre><p>Note, in other for you to be able to use the useState hook, you need to import it at the top like this:</p><pre>import { useState } from &#39;react&#39;;</pre><p>Next, destructure the state to access its properties.</p><pre>//Destructure State in other to get the values in it<br>const { playing, mute, volume, playerbackRate, played, seeking} = playerstate;</pre><p>Update the React Player component by replacing the values for playing and muted props from true to playing and mute, respectively.</p><pre>&lt;ReactPlayer width={&#39;100%&#39;} <br>height=&#39;100%&#39;  url=&quot;<a href="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4">http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4</a>&quot;<br>playing={playing}<br>muted={mute}<br> /&gt;</pre><p>We now develop a feature that determines whether our video is playing or paused. For this, we’ll use the spread operator to store the values of our current playerState, and anytime this function is called, we’ll update the playing property in the state to return the inverse of its current value.</p><p>Here is the function:</p><pre>const handlePlayAndPause = () =&gt; {<br>    setPlayerState({<br>      ...playerstate, <br>      playing: !playerstate.playing<br>    })<br>}</pre><p>We have to send the function as a prop to the ControlIcons component so that the play button may access this feature. Just like this, pass the function as a prop:</p><pre>&lt;ControlIcons playandpause={handlePlayAndPause} /&gt;</pre><p>Destructure the prop in the ControlIcons Component. We are now left with making use of the prop gotten.</p><p>Update the IconButton Wrapper where the play button icon is embedded, with onClick={playandpause}:</p><pre>&lt;IconButton className=&#39;controls__icons&#39; aria-label=&#39;reqind&#39; onClick={playandpause}&gt;<br>     &lt;PlayArrowSharp fontSize=&#39;large&#39; style={{color:&#39;white&#39;}}/&gt;<br> &lt;/IconButton&gt;</pre><p>Use the code above to update the icon’s two instances.</p><p>Let’s include the capability to switch between play and pause. The playing attribute from our “playerState” will be used to conditionally render the icons and import the pause button.</p><p>Import the Pause Icon.</p><pre>import { PauseSharp } from &#39;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&#39;;</pre><p>Pass the playing prop to the ControlIcons component</p><pre>&lt;ControlIcons playandpause={handlePlayAndPause} playing={playing}/&gt;</pre><p>Destructure the prop</p><pre>const ControlIcons = ({ playandpause, playing }) =&gt; { }</pre><p>Replace the two instances of the play icon wrapper with this:</p><pre>&lt;IconButton<br>  className=&quot;controls__icons&quot;<br>  aria-label=&quot;reqind&quot;<br>  onClick={playandpause}<br>&gt;<br>  {playing ? (<br>    &lt;PauseSharp fontSize=&quot;large&quot; style={{ color: &quot;white&quot; }} /&gt;<br>  ) : (<br>    &lt;PlayArrowSharp fontSize=&quot;large&quot; style={{ color: &quot;white&quot; }} /&gt;<br>  )}<br>&lt;/IconButton&gt;</pre><p>You should be able to play and pause the video now.</p><p>We must now construct a new set of functions to manage the rewind and fast-forward features. Just like the Windows Media Player on Windows PCs, we want to fast-forward the video by 30 seconds and rewind it by 10 seconds.</p><p>To do this, we must first establish a reference to the React player component to determine the video’s current time.</p><p>First, import the useRef hook and create the reference for the react-player component.</p><pre>import { useState, useRef } from &#39;react&#39;;</pre><pre>//refer to the react-player component<br> const playerRef = useRef(null);</pre><pre>//And lastly, add the reference to the react-player component by updating it with this code<br>&lt;ReactPlayer width={&#39;100%&#39;} height=&#39;100%&#39;  <br>url=&quot;<a href="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4">http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4</a>&quot;<br>ref={playerRef} //here is the reference<br>playing={playing}<br>muted={mute}<br>/&gt;</pre><p>Let’s make the rewinding function, which we’ll call handleRewind(). Note that we have access to several instance methods through the react-player library, and we utilize the ‘playerRef’ to call instance methods on the player. We will utilize the two instance methods “seekTo(amount, type)” and “getCurrentTime()” for the rewind and fast-forward operations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/756/0*X94Vc6p_3xjk1TjN.jpg" /></figure><pre>//function to handle rewinding<br> const handleRewind = () =&gt; {<br>    playerRef.current.seekTo(playerRef.current.getCurrentTime() - 10, ‘seconds’)<br> }</pre><pre>//function to handle fast-forward<br>//The major difference between this function and that of rewinding is the addition of 30 seconds to the video&#39;s current time.<br>const handleFastForward = () =&gt; {<br>    playerRef.current.seekTo(playerRef.current.getCurrentTime() + 30, &#39;seconds&#39;)<br>}</pre><p>The “ControlIcons component will then get the functions as a prop, which will be destructured inside the component before the icons are activated.</p><p>For that, do this:</p><pre>//Pass the functions as props<br>&lt;ControlIcons<br> playandpause={handlePlayAndPause}<br> playing={playing}<br> rewind={handleRewind}<br> fastForward={handleFastForward}<br> /&gt;</pre><pre>//Destructure the props inside the ControlIcons.jsx file<br>const ControlIcons = ({ playandpause, playing, rewind, fastForward }) =&gt; { }</pre><p>Next, call the onClick event on the rewind and fast-forward icons passing the rewind and fastForward props to the event.</p><pre>//The rewind icon<br>&lt;IconButton className=&#39;controls__icons&#39; aria-label=&#39;reqind&#39; onClick={rewind}&gt;<br>     &lt;FastRewind fontSize=&#39;large&#39; style={{color:&#39;white&#39;}}/&gt;<br>&lt;/IconButton&gt;</pre><pre>//The fast-forward icon<br>&lt;IconButton className=&#39;controls__icons&#39; aria-label=&#39;reqind&#39; onClick={fastForward}&gt;<br>     &lt;FastForwardSharp fontSize=&#39;large&#39; style={{color:&#39;white&#39;}}/&gt;<br>&lt;/IconButton&gt;</pre><p>With the code above, we can now rewind and fast-forward the video. You’ll note that the video player slider doesn’t move to the current time when we rewind or fast-forward the video, and let’s change that as we enter the third section of the controls.</p><p>The seek bar on the video player is our next goal (the slider). In addition to implementing the ability to click (seek) a specific time on the seek bar and view the video from that moment, we also want it to move as we fast-forward or rewind.</p><p>For that, we have to use a callback prop react-player provides — onProgress.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/742/0*yhRwul_a9rB21m2x.jpg" /></figure><p>Add the value handlePlayerProgress (a function we will later write) to the callback props for the react-player component list. Use the following code to update your React player component:</p><pre>&lt;ReactPlayer width={&#39;100%&#39;} height=&#39;100%&#39;<br>url=&quot;<a href="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4">http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4</a>&quot;<br>ref={playerRef}<br>playing={playing}<br>muted={mute}<br>onProgress={handlePlayerProgress}<br> /&gt;</pre><p>The function handlePlayerProgress accepts a state argument. This state argument represents an object with other states embedded. Some sets of states are changed, and new values are returned whenever the video player seek bar (the player’s timing) changes. In this function, we retain the values of the previously altered States and our playerstate attributes. We want this to happen only when the seeking property value in our playerstate is negated.</p><p>You can observe the changing states in your console if you log the newly altered state. We simply require the played state, which is the duration of the video in seconds. This is the played property in our playerstate.</p><pre>const handlePlayerProgress = (state) =&gt; {<br>    console.log(&#39;onProgress&#39;, state);<br>    if (!playerstate.seeking) {<br>      setPlayerState({...playerstate, ...state})<br>    }<br>    console.log(&#39;afterProgress&#39;, state);<br> }</pre><p>Next, pass played as a prop to the ControlIcons component:</p><pre>&lt;ControlIcons<br>    playandpause={handlePlayAndPause}<br>    playing={playing}<br>    rewind={handleRewind}<br>    fastForward={handleFastForward}<br>    played={played}<br>/&gt;</pre><p>Navigate to the ControlIcons.jsx file and destructure the played prop in it.</p><pre>const ControlIcons = ({ playandpause, playing, rewind, fastForward, played }) =&gt; { }</pre><p>Update your prettoslider with the code below:</p><pre>&lt;PrettoSlider <br> min={0} <br> max={100} <br> value={played*100}<br> /&gt;</pre><p>Since our slider has a maximum value of 100, we simply removed the defaultValue and introduced the value prop, which uses the played prop as its value but multiplies it by 100. As the video plays and when we fast-forward or rewind, the seek bar on the video player now moves.</p><p>We must create functions that enable us to seek a particular time using the video player slider. To do this, we will create two functions: handlePlayerSeek() and handlePlayerMouseSeekUp().</p><p>The handlePlayerSeek() is the function triggered when we seek a particular time of the video (when the slider value changes), while the handlePlayerMouseSeekUp() is the function triggered when the mouseup event is activated.</p><pre>const handlePlayerSeek = (newValue) =&gt; {<br>    setPlayerState({...playerstate, played: parseFloat(newValue/100)});]<br>    playerRef.current.seekTo(parseFloat(newValue / 100));<br>}</pre><pre>const handlePlayerMouseSeekUp = (newValue) =&gt; {<br>    setPlayerState({...playerstate, seeking: false});<br>    playerRef.current.seekTo(newValue / 100);<br>}</pre><p>For the handlePlayerSeek(), whenever the slider moves, automatically we get a new value - this is the parameter passed to the function. We then updated the playerState by keeping all we have in the state and updating only the played value to the newValue (which is a string) divided by 100 since played only takes a value between 0 and 1.</p><p>And for the handlePlayerMouseSeekUp(), we passed the parameter of newValue. We updated the playerState by keeping all we have in the state and updating only the seeking value to false. Afterward, we set the video&#39;s current time to the time sought.</p><p>We must pass the functions as props to the ControlIcons component by updating your ControlIcons component.</p><pre>&lt;ControlIcons<br> playandpause={handlePlayAndPause}<br> playing={playing}<br> rewind={handleRewind}<br> fastForward={handleFastForward}<br> played={played}<br> onSeek={handlePlayerSeek}  <br> onSeekMouseUp={handlePlayerMouseSeekUp}<br> /&gt;</pre><p>Next, destructure the newly added props in your ControlIcons.jsx file:</p><pre>const ControlIcons = ({ playandpause, playing, rewind, fastForward, played, onSeek, onSeekMouseUp }) =&gt; { }</pre><p>In order to use the onSeek and onSeekMouseUp props, we need onChange and onChangeCommitted props, respectively.</p><p>The snapshot below explains what these props do.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/661/0*se6Aig6yk0k4Kpiz.jpg" /></figure><p>Now, update your prettoslider component with the code below:</p><pre>&lt;PrettoSlider <br> min={0} <br> max={100} <br> value={played*100}<br> onChange={onSeek} <br> onChangeCommitted={onSeekMouseUp}<br>/&gt;</pre><p>We can now seek a particular video time.</p><p>Next, right below the video player slider, we want to display the video’s total played time and length.</p><p>To do this, we need two instance methods react-player provides for us. The methods are: getCurrentTime() and getDuration(). The snapshot below explains their use.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/733/0*Mi43YOVcUOk_BOdz.jpg" /></figure><pre>const currentPlayerTime = playerRef.current ? playerRef.current.getCurrentTime() : &#39;00:00&#39;;<br>const movieDuration = playerRef.current ? playerRef.current.getDuration() : &#39;00:00&#39;</pre><p>The timing values were displayed using ternary operators in the code mentioned above sample. However, we still need to format the time returned to our preferences. For this, a globally scoped function is required.</p><p>Here is the globally scoped function (I defined it at the top, outside the App component function):</p><pre>const format = (seconds) =&gt; {<br>  if (isNaN(seconds)) {<br>    return &#39;00:00&#39;<br>  }</pre><pre>const date = new Date(seconds * 1000);<br>  const hh = date.getUTCHours();<br>  const mm = date.getUTCMinutes();<br>  const ss = date.getUTCSeconds().toString().padStart(2, &quot;0&quot;);</pre><pre>if (hh) {<br>    return `${hh}:${mm.toString().padStart(2, &quot;0&quot;)}:${ss}`<br>  } else {<br>      return `${mm}:${ss}`<br>  }<br>};</pre><p>Call the function doing this:</p><pre>const currentPlayerTime = playerRef.current ? playerRef.current.getCurrentTime() : &#39;00:00&#39;;<br>const movieDuration =  playerRef.current ? playerRef.current.getDuration() : &#39;00:00&#39;;<br>const playedTime = format(currentPlayerTime);<br>const fullMovieTime = format(movieDuration);</pre><p>Pass playedTime and fullMovieTime as props to the ControlIcons component. Update the component call using the code below:</p><pre>&lt;ControlIcons<br>  playandpause={handlePlayAndPause}<br>  playing={playing}<br>  rewind={handleRewind}<br>  fastForward={handleFastForward}<br>  played={played}<br>  onSeek={handlePlayerSeek}<br>  onSeekMouseUp={handlePlayerMouseSeekUp}<br>  playedTime={playedTime}<br>  fullMovieTime={fullMovieTime}<br>/&gt;</pre><p>As usual, destructure them inside the ControlIcons.jsx file:</p><pre>const ControlIcons = ({ playandpause, playing, rewind, fastForward, played, onSeek, onSeekMouseUp, playedTime, fullMovieTime }) =&gt; { }</pre><p>Finally, update the timing default value after the prettoslider component with this:</p><pre>&lt;Typography variant=&#39;h7&#39; style={{color:&#39;white&#39;}}&gt;{playedTime}&lt;/Typography&gt;<br>&lt;Typography variant=&#39;h7&#39; style={{color:&#39;white&#39;}}&gt;{fullMovieTime}&lt;/Typography&gt;</pre><p>You can now view the played time and the movie duration live as the video plays.</p><p>And finally, let’s work on the last category of the third segment. Let’s start with the volume icon. When we click it, we should be able to switch between muted and volume up. In that case, depending on the current volume level, the icon should change to muted or volume-up. Navigate into the App.js file, where we’ll create the function that handles the muting state.</p><pre>const handleMuting = () =&gt; {<br>    setPlayerState({...playerstate, muted: !playerstate.muted})<br>}</pre><p>For the handleMuting(), we kept all that is in the playerstate and updated the muted property to an inverse value of the current state of muted. Pass the function and muted property as props into the ControlIcons component by modifying your code with this:</p><pre>&lt;ControlIcons<br>  playandpause={handlePlayAndPause}<br>  playing={playing}<br>  rewind={handleRewind}<br>  fastForward={handleFastForward}<br>  played={played}<br>  onSeek={handlePlayerSeek}<br>  onSeekMouseUp={handlePlayerMouseSeekUp}<br>  playedTime={playedTime}<br>  fullMovieTime={fullMovieTime}<br>  muting={handleMuting}<br>  muted={mute}<br>/&gt;</pre><p>Destructure the muting and muted props in the ControlIcons.jsx file:</p><pre>const ControlIcons = ({ playandpause, playing, rewind, fastForward, played, onSeek, onSeekMouseUp, playedTime, fullMovieTime,muting, muted }) =&gt; { }</pre><p>Next, import the icon that symbolizes volume off or muted.</p><pre>import { VolumeOff } from &#39;<a href="http://twitter.com/mui/icons-material">@mui/icons-material</a>&#39;;</pre><p>Now, update the whole wrapper for the volume icon with the code below:</p><pre>&lt;IconButton className=&#39;controls__icons&#39; aria-label=&#39;reqind&#39; onClick={muting}&gt;<br>   {<br>      muted ? (<br>        &lt;VolumeOff fontSize=&#39;large&#39; style={{color:&#39;white&#39;}}/&gt;<br>         ) : (<br>        &lt;VolumeUp fontSize=&#39;large&#39; style={{color:&#39;white&#39;}}/&gt;<br>     )<br>   }<br>&lt;/IconButton&gt;</pre><p>We conditionally rendered two icons in the aforementioned IconButton wrapper based on the value of the “muted” attribute in the “playerstate”. Additionally, we added an onClick() event to the wrapper and specified the value to be muting.</p><p>For the volume slider, just like the PrettoSlider, we have two functions to define, one for the onChange event and the other for the onChangeCommitted event.</p><pre>//function for the `onChange` event<br>const handleVolumeChange = (e, newValue) =&gt; {<br>    setPlayerState({...playerstate, volume:parseFloat(newValue/100), mute:newValue === 0 ? true : false, });<br>}</pre><pre>//function for the `onChangeCommitted` event<br>const handleVolumeSeek = (e, newValue) =&gt; {<br>    setPlayerState({...playerstate, volume:parseFloat(newValue/100), mute:newValue === 0 ? true : false, });<br>}</pre><p>For the functions above, we simply updated the playerstate by keeping all that is in it and the values of the volume and mute properties.</p><p>We then pass the function as props:</p><pre>&lt;ControlIcons<br>  playandpause={handlePlayAndPause}<br>  playing={playing}<br>  rewind={handleRewind}<br>  fastForward={handleFastForward}<br>  played={played}<br>  onSeek={handlePlayerSeek}<br>  onSeekMouseUp={handlePlayerMouseSeekUp}<br>  playedTime={playedTime}<br>  fullMovieTime={fullMovieTime}<br>  muting={handleMuting}<br>  muted={mute}<br>  volume={volume}<br>  volumeChange={handleVolumeChange}<br>  volumeSeek={handleVolumeSeek}<br>/&gt;</pre><p>Next, we update the volume slider by adding two new props: the onChange event and the onChangeCommitted event, and passing the volumeChange and volumeSeek props as their value, respectively. Also, we update the default value, which defines the volume pitch with the code below:</p><pre>&lt;Typography style={{color:&#39;#fff&#39;, paddingTop:&#39;5px&#39;}}&gt;{volume * 100}&lt;/Typography&gt;<br>&lt;Slider<br> min={0}<br> max={100}<br> value={volume * 100}<br> className=&#39;volume__slider&#39;<br> onChange={volumeChange}<br> onChangeCommitted={volumeSeek}<br> /&gt;</pre><p>Regarding the playback speed/rate. Here, we want to include a function that lets us change the speed at which the video plays.</p><p>In this section, we’ll work with the playbackRate props react-player provides.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/735/0*Dp69AiQb6v7Cbytw.jpg" /></figure><p>We have to create the function that handles the playback rate. This function updates the playerstate by simply keeping all that is in it and updating only playerbackRate value to its parameter (rate).</p><p>Here is the function:</p><pre>const handlePlayerRate = (rate) =&gt; {<br>    setPlayerState({...playerstate, playerbackRate: rate});<br>}</pre><p>We have to pass this playerbackRate property from the playerstate as the value for the playbackRate prop that we&#39;ll add to the React Player component.</p><p>According to the statement above, your React Player component should have the following props.</p><pre>&lt;ReactPlayer width={&#39;100%&#39;} height=&#39;100%&#39;<br>  url=&quot;<a href="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4">http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4</a>&quot;<br>  ref={playerRef}<br>  playing={playing}<br>  muted={mute}<br>  onProgress={handlePlayerProgress}<br>  playbackRate={playerbackRate}<br>/&gt;</pre><p>In the code snippet above, we added the playbackRate prop to the React Player component.</p><p>Next, we have to pass both playerbackRate property from the playerstate and handlePlayerRate() as props to ControlIcons component.</p><pre>&lt;ControlIcons<br>  playandpause={handlePlayAndPause}<br>  playing={playing}<br>  rewind={handleRewind}<br>  fastForward={handleFastForward}<br>  played={played}<br>  onSeek={handlePlayerSeek}  <br>  onSeekMouseUp={handlePlayerMouseSeekUp}<br>  playedTime={playedTime}<br>  fullMovieTime={fullMovieTime}<br>  muting={handleMuting}<br>  muted={mute}<br>  volume={volume}<br>  volumeChange={handleVolumeChange}<br>  volumeSeek={handleVolumeSeek}<br>  playerbackRate={playerbackRate}<br>  playRate={handlePlayerRate}<br> /&gt;</pre><p>Let’s move into the ControlIcons.jsx file, where we&#39;ll create the popover and use the recently passed props.</p><p>The first thing we have to do here is to set up the Popover where we&#39;ll embed the various speed rates.</p><p>Import Popover component from Material UI.</p><pre>import Popover from &#39;<a href="http://twitter.com/mui/material">@mui/material</a>/Popover&#39;;</pre><p>Next, destructure the props inside the ControlIcons.jsx file:</p><pre>const ControlIcons = ({ playandpause, playing, rewind, fastForward, played, onSeek, onSeekMouseUp, playedTime, fullMovieTime, muting, muted, volume, volumeChange, volumeSeek , playRate, playerbackRate}) =&gt; { }</pre><p>The Popover component from MUI comes with a series of things: a state, two functions that trigger the opening and closing of the popover, and two variables. You can find them in the code snippet below:</p><pre>const [anchorEl, setAnchorEl] = React.useState(null);<br>const handlePopOver = (event) =&gt; {<br>     setAnchorEl(event.currentTarget);<br>};</pre><pre>const handleClose = () =&gt; {<br>     setAnchorEl(null);<br> };</pre><pre>const open = Boolean(anchorEl);<br> const id = open ? &#39;playbackrate-popover&#39; : undefined;</pre><p>Let’s systematically activate the popover starting with the displayed value of 1x in the Video player.</p><p>The Button Wrappper, which displays the current playback rate of the video, should be updated with the code below:</p><pre>&lt;Button variant=&#39;text&#39; onClick={handlePopOver} className=&#39;bottom__icons&#39;&gt;<br>     &lt;Typography&gt;{playerbackRate}X&lt;/Typography&gt;<br>&lt;/Button&gt;</pre><p>For the code above, we added the onClick event to the Button Wrapper, which we passed the handlePopOver() as its value. After that, we updated the current value of the playback rate using the playbackRate prop.</p><p>Immediately after the code above, add this:</p><pre>&lt;Popover<br>    id={id}<br>    open={open}<br>    anchorEl={anchorEl}<br>    onClose={handleClose}<br>    anchorOrigin={{<br>        vertical: &#39;top&#39;,<br>        horizontal: &#39;center&#39;,<br>    }}<br>    transformOrigin={{<br>      vertical: &#39;bottom&#39;,<br>      horizontal: &#39;center<br>   }}&gt;<br>        &lt;Grid container direction=&#39;column-reverse&#39;&gt;<br>                 {<br>                      [0.5,1,1.5,2].map((rate) =&gt; (<br>                           &lt;Button variant=&#39;text&#39; onClick={() =&gt; playRate(rate)}&gt;<br>                               &lt;Typography color={rate === playerbackRate ? &#39;secondary&#39; : &#39;default&#39;}&gt;{rate}&lt;/Typography&gt;<br>                           &lt;/Button&gt;<br>                      ))<br>               }<br>       &lt;/Grid&gt;<br>&lt;/Popover&gt;</pre><p>In the code above, we simply passed id, open, anchorE!, and onClose as props to the Popover wrapper. We also structured the position of the Popover using the anchorOrigin and transformOrigin. Finally, inside the Popover wrapper, we mapped the values which symbolize the playback rate, then they are passed as the argument to the playRate.</p><p>Now, we can toggle through four values for our playback rate. By default, the playback rate is set to 1.</p><p>Navigate to the App.js.</p><p>Finally, let’s implement the Full-Screen Mode. Remember that we imported screenfull from the screenfull package.</p><p>We need to make a reference to the wrapper for the whole video player, i.e., the div with a className of playerDiv.</p><p>Create the reference using useRef:</p><pre>const playerDivRef = useRef(null);</pre><p>Call the reference on the Video player wrapper:</p><pre>&lt;div className=&#39;playerDiv&#39; ref={playerDivRef}&gt;&lt;/div&gt;</pre><p>Create the function that triggers full-screen mode when we toggle the icon.</p><pre>const handleFullScreenMode = () =&gt; {<br>    screenfull.toggle(playerDivRef.current);<br>}</pre><p>Pass the function as a prop to the ControlIcons component. Update the ControlIcons component with this:</p><pre>&lt;ControlIcons<br>  playandpause={handlePlayAndPause}<br>  playing={playing} <br>  rewind={handleRewind}<br>  fastForward={handleFastForward}<br>  played={played}<br>  onSeek={handlePlayerSeek}  <br>  onSeekMouseUp={handlePlayerMouseSeekUp}<br>  playedTime={playedTime}<br>  fullMovieTime={fullMovieTime}<br>  muting={handleMuting}<br>  muted={mute}<br>  volume={volume}<br>  volumeChange={handleVolumeChange}<br>  volumeSeek={handleVolumeSeek}<br>  playerbackRate={playerbackRate}<br>  playRate={handlePlayerRate}<br>  fullScreenMode={handleFullScreenMode}<br>/&gt;</pre><p>Destructure the fullScreenMode prop inside the ControlIcons.jsx file.</p><pre>const ControlIcons = ({ playandpause, playing, rewind, fastForward, played, onSeek, onSeekMouseUp, playedTime, fullMovieTime, muting, muted, volume, volumeChange, volumeSeek , playRate, playerbackRate, fullScreenMode}) =&gt; { }</pre><p>Add the onClick event (with the fullScreenMode prop as its value) to the IconButton wrapper where the full-screen icon is embedded.</p><pre>&lt;IconButton className=&#39;bottom__icons&#39; onClick={fullScreenMode}&gt;<br>      &lt;Fullscreen fontSize=&#39;large&#39;/&gt;<br>&lt;/IconButton&gt;</pre><h3>Conclusion</h3><p>In this article, we learned how to build and customize a video player using the <a href="https://www.npmjs.com/package/react-player">react-player package</a> and <a href="https://mui.com/">Mui</a> to style and import the needed icons. However, you can always take the build further by adding some unique features to make the player suit your taste completely.</p><p>Here is the <a href="https://github.com/shegz101/Video-player">source code</a> and the <a href="https://video-player-theta-seven.vercel.app/">deployed version</a>.</p><blockquote><em>A TIP FROM THE EDITOR: If you are interested in showing videos, please also look at our </em><a href="https://blog.openreplay.com/picture-in-picture-video-with-html5-and-javascript/"><em>Picture-In-Picture Video With HTML5 And JavaScript</em></a><em> article.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*HOKxfW3k7ptJZ7Vp.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/building-a-video-player-with-React-and-Material-UI/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1e4cc105e084" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/building-a-video-player-with-react-and-material-ui-1e4cc105e084">Building a Video Player with React and Material UI</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[DAOs using Dework]]></title>
            <link>https://medium.com/@bobateisaac/daos-using-dework-9c8faa3f3bec?source=rss-29cfa9c1c0bd------2</link>
            <guid isPermaLink="false">https://medium.com/p/9c8faa3f3bec</guid>
            <category><![CDATA[dework]]></category>
            <category><![CDATA[tools]]></category>
            <category><![CDATA[dao]]></category>
            <dc:creator><![CDATA[Bobate Isaac]]></dc:creator>
            <pubDate>Mon, 16 May 2022 17:41:22 GMT</pubDate>
            <atom:updated>2022-05-16T17:41:22.787Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*9nzYAcc4OaVlhQIu7LI0FA.jpeg" /><figcaption>Dework Logo</figcaption></figure><p><strong>What are DAOs?</strong></p><p>Decentralized Autonomous Organizations (DAOs) represent the term for a group of like-minded people coming together to work as one for the same purpose like investing in start-ups, managing a stablecoin, or buying a bunch of NFTs. There’s no central governing authority, hence the “decentralization”. Decisions are made collectively, whereby everyone’s vote counts — the DAO token represents a vote. In simple terms, more tokens mean more votes. According to ConsenSys, a blockchain organization, DAOs are “governing bodies that oversee the allocation of resources tied to the projects they are associated with and are also tasked with ensuring the long-term success of the project they support.”</p><p><strong>What is Dework?</strong></p><p><a href="https://dework.xyz/">Dework</a> is a web3-native tool like Trello, creating a medium for managing tasks and bounties all in one place. It goes further to offer some other incredible services like getting contributor applicants for your tasks, sync with <a href="https://discord.com/">discord</a>, boost the reputation of contributors and even pay using your DAO token.</p><p><strong>Integrating your DAO with Dework</strong></p><p>First, create an account <a href="https://app.dework.xyz/dework">here</a>. You will be directed to a page just like the snapshot below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*OzxLN-9W2XYosVs9RffXWg.png" /></figure><p>After you might have created the account and directed to the page above, they expect you to connect your discord and also establish a payment method (preferably metamask).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/584/1*UVO7bFelJlOLBbVijzb-Mw.png" /></figure><p>Now, you left with creating a project for your organization. You can decide to create a new project or just import an existing project from either <a href="https://www.notion.so/">Notion</a>, <a href="https://trello.com/">Trello</a> or <a href="https://github.com/">Github</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qP6AUOqiL6VakfRYKjgbQw.jpeg" /></figure><p><strong>Popular DAOs on Dework</strong></p><p>Navigate <a href="https://dework.xyz/">here</a> to view on the popular DAOs on Dework.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E3yHkN2KUMITxJ76uRhx2Q.png" /></figure><p>We regard the DAOs below as the popular DAOs on Dework. As a contributor, you can join any of this DAO, provided you’ve done all that is required by Dework.</p><ul><li><a href="https://app.dework.xyz/poapathon/board">POAPathon</a></li><li><a href="https://app.dework.xyz/the-opendao">The Open DAO</a></li><li>SuperUMAn</li><li><a href="https://app.dework.xyz/pandadao">PandaDAO</a></li><li><a href="https://app.dework.xyz/lexdao-1">LexDAO</a></li><li><a href="https://app.dework.xyz/citydao">CityDAO</a></li></ul><p>In no particular order, let’s take a deeper view of some of the DAOs.</p><p><a href="https://app.dework.xyz/the-opendao"><strong>The OpenDAO</strong></a></p><p>This DAO creates a community of digital natives united base on the following goals:</p><ul><li>Building $SOS to be the central asset for the metaverse and web3 communities</li><li>Bridging the gap between existing intellectual property and the metaverse</li><li>Building core infrastructure for the non-fungible tokens (NFTs) ecosystem.</li></ul><p>If Open DAO sounds like something you resonate with, you can go further by checking out the open tasks in the organization. With over 100+ active contributors, it’s no news that Open DAO is really growing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-JRDl4mhTkVPBly8_tOkHg.png" /></figure><p>The Open DAO has various open tasks spanning through development, design, translation, writing, marketing, community, product, research, legal, operations. Indeed the Open DAO covers a lot so everyone can find open tasks that we most likely tally with what they can do. If you feel there is a space you like in this organization, search for open tasks related to it then take a bold step to start contributing.</p><p><a href="https://app.dework.xyz/pandadao"><strong>The PandaDAO</strong></a></p><p>The PandaDAO is an organization taking the responsibility to reduce the control centralized organization have over information, and instead put personal data in the hands of the people (this is simply the practical definition of web 3). PandaDAO also aim to produce tools for DAOs, allowing more individuals to work full-time for this new type of organization. Another interesting thing about this organization is that it has lots of projects for various types of devopers be it frontend developer, backend developer, smart contracts (blockchain developers) and so on.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cThklSPfgyHqh6Eq6L6nDA.png" /></figure><p>PandaDAO is more than just a decentralized media organization. They are developing new decentralized data systems and liberating internet products and human resources from Web2. They are making full use of web 3.</p><p><a href="https://app.dework.xyz/citydao"><strong>CityDAO</strong></a></p><p>This organization is an on-chain city — cities that occur on a blockchain that are reflected on the distributed, public ledger. This organization is building metaverse where they are replicating cities in blockchain format.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MLPodLAp2hcPCVv-q5ZpOw.png" /></figure><p>There are also lots of projects provided in this organization be you a designer, developer, crypto enthusiasts and many more. If you have idea about real estate management, Iencourage to check out this organization in particular their real estate project section.</p><p>Dework has one unique feature which is the fact that you can easily integrate your github to work, making it easy for you as a contributor to submit your codes for project tasks contributed to. As DAO you can connect all your projects using github and also all the needed resources germane to contributors workflow.</p><p>Dework enables DAOs to create and manage tasks with current and new contributors, as well as reward them with their native token. With the <strong>Gnosis Safe</strong>, all contributors canbe paid at the same time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*dv73t_LDHZv8n_psYtp44w.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9c8faa3f3bec" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Dework: Profile and reputation features]]></title>
            <link>https://medium.com/@bobateisaac/dework-profile-and-reputation-features-ece358320946?source=rss-29cfa9c1c0bd------2</link>
            <guid isPermaLink="false">https://medium.com/p/ece358320946</guid>
            <category><![CDATA[dework]]></category>
            <category><![CDATA[dao]]></category>
            <category><![CDATA[reputation]]></category>
            <dc:creator><![CDATA[Bobate Isaac]]></dc:creator>
            <pubDate>Sun, 15 May 2022 16:02:17 GMT</pubDate>
            <atom:updated>2022-05-15T16:02:17.610Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bG_zqmfFvie1mr5YeqXzMQ.png" /></figure><p><strong>Dework, the newly found web 3.0-native Trello.</strong></p><p><a href="https://dework.xyz/">Dework</a>, a task manager for <a href="https://cointelegraph.com/decentralized-automated-organizations-daos-guide-for-beginners/what-is-decentralized-autonomous-organization-and-how-does-a-dao-work#:~:text=A%20decentralized%20autonomous%20organization%20(DAO,and%20managed%20by%20their%20members.">DAOs</a> supporting token payments, credentialing, and bounties, should be your best option for getting web3 opportunities. It is also regarded as the web 3.0 <a href="https://trello.com/?&amp;aceid=&amp;adposition=&amp;adgroup=105703213888&amp;campaign=9843285526&amp;creative=437184392305&amp;device=c&amp;keyword=trello&amp;matchtype=e&amp;network=g&amp;placement=&amp;ds_kids=p53016482445&amp;ds_e=GOOGLE&amp;ds_eid=700000001557344&amp;ds_e1=GOOGLE&amp;gclid=Cj0KCQjwyYKUBhDJARIsAMj9lkG8CNiQrN4F9CSQkR-ZsN0NgAMnj3fflEKP_6Vkfa7vsIc0fe3-U2YaArzyEALw_wcB&amp;gclsrc=aw.ds">Trello</a>, offering what a native <a href="https://trello.com/?&amp;aceid=&amp;adposition=&amp;adgroup=105703213888&amp;campaign=9843285526&amp;creative=437184392305&amp;device=c&amp;keyword=trello&amp;matchtype=e&amp;network=g&amp;placement=&amp;ds_kids=p53016482445&amp;ds_e=GOOGLE&amp;ds_eid=700000001557344&amp;ds_e1=GOOGLE&amp;gclid=Cj0KCQjwyYKUBhDJARIsAMj9lkG8CNiQrN4F9CSQkR-ZsN0NgAMnj3fflEKP_6Vkfa7vsIc0fe3-U2YaArzyEALw_wcB&amp;gclsrc=aw.ds">Trello</a> can do — things like (managing tasks and bounties).</p><p><strong>Dework Services</strong></p><p><a href="https://dework.xyz/">Dework</a> does:</p><ul><li>Creates a platform where DAOs can create tasks and also add bounties</li><li>Connects available DAOs to interested contributors</li><li>Integrates payment methods like <a href="https://metamask.io/">metamask</a> in other for contributors to quickly get paid.</li></ul><p>With the seamless profile structure for contributors on<a href="https://dework.xyz/"> Dework</a>, we can call it a web 3.0 <a href="https://www.linkedin.com/">LinkedIn</a>. Each contributor’s profile structure gets to see the list of all tasks contributed.</p><h3>Profile and Reputation Features in Dework</h3><p>Dework has quite several unique features that benefit both DAOs and contributors. This article aims to enlighten you about the profile and reputation features that Dework provides. A lot can be done with this tool.</p><p>I will explain this section by sighting two case studies — DAO management View and the Contributor’s View.</p><p><strong>DAO management:</strong></p><p>First, set up your DAO by clicking on the ‘Setup Project’ button on Dework’s homepage. This won’t take more than a minute of your time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FlDRz_u_j4l5pvAoQiGWPQ.jpeg" /></figure><p>After setting up your DAO, you can add all the tasks you need a contributor for, by embedding them all in a Todo, just like the snapshot below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EQ31T47vcEq-SeZXRboQgg.jpeg" /></figure><p>The next phase is to create a task and attach a bounty to it, then wait for interested contributors to apply. In most cases, when a contributor accepts your task, you need to review/scrutinize their profile, though you can accept any contributor provided that you believe they are qualified for the task.</p><p>In other to make things more formal, you can take a step further by building a comprehensive task board and then adding segmented sections like (application review, work assignment, work in progress, work submitted for review, and work completed), just the way we have it for a typical Trello board.</p><p>Incorporating the Trello board-like feature in your DAO, make things look well structured, simple and clear.</p><p>Now, you can decide to use Dework to organize projects. Dework shows us the power of web 3.</p><p><strong>The Contributor’s View:</strong></p><p><a href="https://dework.xyz/">Dework</a> is a great tool that helps contributors access freelance web 3.0 gigs. By navigating to the Bounty section or Projects, you’ll discover open tasks to which you can decide to contribute to.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tdh64XFTScCXgHbD31az1g.jpeg" /></figure><p>By clicking on a task you are interested in, you get to see more content information regarding that task, like the amount to be paid, instructions to follow, and so on.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HUA5mKn9htZRyE9f9qNPDA.png" /></figure><p>If you feel comfortable with a skill, you can take your job surfing a step forward by simply using the search field to find available task regarding that skill you comfortable with.</p><p><strong>What you stand to gain as a contributor using Dework:</strong></p><ul><li>Dework let’s existing contributors to easily handle tasks</li><li>As a contributor, you can decide to recruit new contributors to help you in completing a task, this is what we regard as outsourcing</li><li>Contributors get paid very fast due to the integration of payment platform. When you are signing up on with this tool, you are regarded to submit your wallet address, but you can also decide not to until you have completed a task using Dework.</li></ul><p>The next section will help you in setting up your payment method.</p><p><strong>Payment Structure:</strong></p><p>In case you haven&#39;t linked your wallet address, just navigate to your profile settings.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Y8Rj19jWvmMkkQ4fBfSxSw.jpeg" /></figure><p><strong>Concluding note:</strong></p><p>Dework is your number one DAO management and Contributor’s platform. A place where contributors that have their expertise in the web 3.0 field can easily get a job where they match up to. This platform helps to manage DAOs, contributor’s experience, and build on-chain reputation.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ece358320946" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>