<?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 Stevanus Satria on Medium]]></title>
        <description><![CDATA[Stories by Stevanus Satria on Medium]]></description>
        <link>https://medium.com/@stevahnes?source=rss-76aa3ea36bc6------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*eRF5M7pxYVO9aFb6v-0fNA.jpeg</url>
            <title>Stories by Stevanus Satria on Medium</title>
            <link>https://medium.com/@stevahnes?source=rss-76aa3ea36bc6------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 23:59:42 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@stevahnes/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[With a Pinch of Salt]]></title>
            <link>https://stevahnes.medium.com/with-a-pinch-of-salt-e8d46b54969?source=rss-76aa3ea36bc6------2</link>
            <guid isPermaLink="false">https://medium.com/p/e8d46b54969</guid>
            <category><![CDATA[career-advice]]></category>
            <category><![CDATA[slice-of-life]]></category>
            <category><![CDATA[career-development]]></category>
            <category><![CDATA[job-hunting]]></category>
            <category><![CDATA[personal-growth]]></category>
            <dc:creator><![CDATA[Stevanus Satria]]></dc:creator>
            <pubDate>Thu, 18 Mar 2021 12:15:05 GMT</pubDate>
            <atom:updated>2021-03-21T06:38:12.026Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*z2bfRhU4OXDxCpu6" /><figcaption>Photo by <a href="https://unsplash.com/@wjtuinstra?utm_source=medium&amp;utm_medium=referral">Jason Tuinstra</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h4>What I learned from switching roles as an experienced hire.</h4><p>Despite being in the early stages of my professional career, I’ve had 3 role switches over the past 4.5 years. The first was due to the end of my research contract, whereas the second was in pursuit of growth and learning opportunities. It was only on my most recent switch that I joined a company as an experienced hire.</p><p>Unlike joining as a “freshie” or “trainee”, joining as an experienced hire comes with additional expectations. This is no surprise. What caught me off guard, however, was the extent to which everything has to be taken and approached with a pinch of salt.</p><p>I’ve only been in the new role for a few weeks, but here are the 3 things that shocked me the most so far:</p><ol><li>Suboptimal practices can outperform the best practices</li><li>Context change both externally and internally</li><li>Balancing expectation, personal drive, and acclimatisation is difficult</li></ol><h3>Suboptimal practices can outperform the best practices</h3><p>One of the biggest and most widely-used buzzwords in the IT industry is Agile. For those who are unfamiliar, a couple of software developers came together 20 years ago and wrote a manifesto dictating their view on how to develop software better. These 4 ideals led to the inception of various frameworks designed to encapsulate them in a formulaic manner.</p><p>One of the most popular frameworks today is Scrum. 94% of all agile businesses use Scrum. Even though the framework is open-source, its creators are now billionaires, and countless certifications sprung up as a result of its popularity.</p><p>And yet companies are still struggling to yield highly motivated and performing teams. There are still countless poorly-implemented softwares being sold to the market. Most ironically was how in ComparativeAgility — the tool provided by ScrumAlliance to compare a team’s agility against various benchmarks — even the global benchmark lies on the poorest performing quadrant.</p><p>I became a firm believer of Agile and Scrum ever since I learned more about it, and I still am. However, having seen how much my current employer outperform some of the other firms who claim to be “Agile”, I no longer believe that it is the one true solution for excellent software craftsmanship.</p><p>A framework, ultimately, is just a guideline. We should always make the best decision based on the context we are in, and that includes our software development approach and methodology.</p><h3>Context change both externally and internally</h3><p>When switching roles we often pay more attention to the apparent changes that will happen: new workplace, new colleagues, new culture. In anticipation to these changes, we may proactively conduct research: reading Glassdoor reviews, asking friends who work in the firm, stalking our future manager and colleagues on Linkedin. Having done exactly this, I believed that I had a strong, bullet-proof game plan to acclimatise myself to my the work environment I soon find myself in once I moved.</p><p>However, I learned that I forgot to account for one very important context change: my increased wealth of knowledge and experience.</p><p>My previous manager once encouraged me to get out there and try things out while the stakes were low. Why? Because I was a “freshie”. Hiring me came with the expectation that I was bound to stumble, fail, and make mistakes. It also came with the expectation that I would learn from them and grow professionally.</p><p>And grow I did, by trying out new things, always embodying the “can-do” attitude, taking initiatives, and promoting changes/new practices internally. Through all my actions, I built a reputation as a capable, creative, proactive, outspoken, and dependable contributor to the company.</p><p>When preparing for my most recent switch, I accounted for the less forgiving culture and my status as an experienced hire. I told myself to make a strong positive impression, apply all that I know, and ensure I do not make the same rookie mistakes I made 2 years ago. Initially, it all seemed to work just fine; I was commended for my speed of onboarding and proactive nature.</p><p>However, I came to realise that while my plan was fine considering just the external context changes, it was flawed if I accounted for the internal context changes. These internal context changes encompassed my skillsets and experiences, and they affect the way my colleagues perceive me and my actions just as much as the culture of the company I just joined. I learned that whereas my eagerness, candid nature, and “can-do” attitude were all seen as proactivity and openness in the context of a “freshie”, it came across as arrogance and overstepping in the context of an experienced hire.</p><h3>Balancing expectation, personal drive, and acclimatisation is difficult</h3><p>Which brings me to my last point, and that is the fact that balancing the expectation of a being an experienced hire, my own personal aspirations, and the need to adopt to a new culture and establish professional relationship with new colleagues is not easy. On the one hand, the need to convince the manager that he made the right choice in hiring me is evident (I am, after all, still under probation). In an environment with informal onboarding and minimal handholding, taking initiatives and trying things out may be required. On the other hand, doing so may make me come across as trying to impose myself too much without first understanding the ins-and-outs of the company today.</p><p>Getting over these points, especially the last 2, definitely require more contemplation, pondering, and adjustment on my end. However, if there was anything I could immediately adopt as of this writing, it was that context matters more than we think, and as such everything has to be taken with a pinch of salt, with more salt pinched the more uncertain the context became.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e8d46b54969" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Among Us]]></title>
            <link>https://stevahnes.medium.com/among-us-489cc2d95a40?source=rss-76aa3ea36bc6------2</link>
            <guid isPermaLink="false">https://medium.com/p/489cc2d95a40</guid>
            <category><![CDATA[communication]]></category>
            <category><![CDATA[remote-working]]></category>
            <category><![CDATA[team]]></category>
            <category><![CDATA[community]]></category>
            <category><![CDATA[teamwork]]></category>
            <dc:creator><![CDATA[Stevanus Satria]]></dc:creator>
            <pubDate>Mon, 15 Feb 2021 14:40:03 GMT</pubDate>
            <atom:updated>2021-02-15T14:40:03.849Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*KunahGzkUOzsxuN0" /><figcaption>Photo by <a href="https://unsplash.com/@hannahbusing?utm_source=medium&amp;utm_medium=referral">Hannah Busing</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h4>Maintaining human connection throughout remote working.</h4><p>Roughly a year ago, I wrote some tips on how to stay connected with our loved ones while working overseas, far away from where they are. What I did not expect was how pervasive the struggle to maintain human connection would be, so much so that we began to lose that human touch with the people we typically spend most of our time with: our colleagues.</p><p>I began noticing this around the 3rd quarter of 2020. Superficially, it looked like business as usual; everyone was busy working towards completing their sprint tasks and goals, and every day we would see our “burndown chart” steadily charting our progress. However, I could sense that something was not quite right, that interactions with my fellow teammates felt more curt and transactional, and all conversations began with the need to extract some information from the other party. For a while, I pondered the reason why this was the case until the obvious hit me: whereas the office setting catalyzes impromptu casual conversations (whether through accidental bumps along the hallway, tea breaks in the pantry, or lunch breaks), remote working meant all interactions were confined within the remote working tools we were using (Microsoft Teams and Webex), typically accessed only when we are deep into our work.</p><p>The question, then, was how we could bring back those catalytic moments into our remote working setup, and the answer to that question for our team was a combination of an online collaboration tool and a tinge of fun.</p><p>Inspired by a sharing done during a Friends of Figma Singapore Meetup, I decided to adopt the idea of an “emotional scale” into our team. At that time, the online multiplier game Among Us was taking the world by storm, and I thought what better way to incorporate fun than to design the avatars based on the Among Us characters. Within a few minutes, I whipped up a prototype on Miro and showed it to my manager.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/750/1*N51qHZysFW-av400Qc6_5Q.png" /><figcaption>The “Among Us” Board</figcaption></figure><p>The above board is a duplicate of the one we actually used in alternate Daily Scrum Meetings, but the principle is identical. Each person within the team is assigned an avatar (they are allowed to customize the color insofar as no 2 people end up with the exact same color). At the start of the meeting, everyone will log onto the platform and move their avatars onto the scale in the middle based on how they are feeling that day, with 1 being the worst and 10 being the best. The meeting facilitator (in our case the Scrum Master) will then facilitate either (a) an open forum for everyone to chit-chat for a few minutes and share their feelings or (b) dedicated sharing time for each person. The idea was for the Board and the sharing session to become a substitute for those casual conversation moments that happen in the office.</p><p>The idea was approved and we are still doing using the “Among Us” Board up to this moment. Personally, I found an open forum to be a better format than a dedicated sharing time for each person, as the latter is bound to feel obligatory and routine-like. However, an open forum brings forward the challenge of encouraging everyone to speak, instead of just a handful of people. My manager found it useful to actually graph out the ratings given by each person in order to deduce some patterns, and hopefully intervene when necessary before it’s too late.</p><p>Should you wish to give this a shot with your team, I have made a version of the file available for duplication in <a href="https://www.figma.com/community/file/943138867666782894/Team-Morale---Among-Us">Figma</a>. I sincerely hope you find it useful in navigating this new way of working!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=489cc2d95a40" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Integrate Smoothstate.js to WordPress Portfolio]]></title>
            <link>https://stevahnes.medium.com/integrate-smoothstate-js-to-wordpress-portfolio-cb41d4badc7?source=rss-76aa3ea36bc6------2</link>
            <guid isPermaLink="false">https://medium.com/p/cb41d4badc7</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[jquery]]></category>
            <category><![CDATA[wordpress-web-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[wordpress]]></category>
            <dc:creator><![CDATA[Stevanus Satria]]></dc:creator>
            <pubDate>Sat, 26 Sep 2020 16:59:22 GMT</pubDate>
            <atom:updated>2021-11-14T15:32:45.437Z</atom:updated>
            <content:encoded><![CDATA[<h4>How I structured my CSS and modified my Child Theme to get that snazzy Single-Page Application transition.</h4><p>I have always used WordPress for my personal website/portfolio. I started with the SaaS version that is WordPress.com, before transitioning into WordPress.org earlier this year. Like many have told me, WordPress.org indeed opened up a lot more possibilities compared to WordPress.com, courtesy of its mature theme and plugin ecosystem, as well as better access to HTML and CSS customizations. It was truly a state of “whatever you can think of, you can build”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_K9ifySV4R4hmOFb_MCZOA.gif" /><figcaption>A traditional WordPress site, where the whole page refreshes on navigation into another page. (Credit: <a href="http://perkcoffee.co/">https://perkcoffee.co/</a>)</figcaption></figure><p>However, for the longest time, I thought a WordPress site would always be that: a WordPress site. I thought there was no way I could get the transition that modern site builders offer, where only part of the page refreshes on navigation into another page.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Liw6lSPgOqAehWTtEZQ4zQ.gif" /><figcaption>What we are aiming for! As you can see, only the “difference” is re-rendered; the rest (in this case the header) is unchanged. (Credit: <a href="https://thedieline.com/">https://thedieline.com/</a>)</figcaption></figure><p>Until I came across a certain JavaScript library called Smoothstate.js (and its close competitor, Barba.js).</p><p>I looked at tutorials on how to integrate Smoothstate.js into WordPress, and truthfully it looked simple. However, none of the tutorials provide a comprehensive guide on how to organize your WordPress site in order to ensure that everything works as it was prior to Smoothstate.js integration. After spending a whole weekend overcoming the obstacles I came across and ironing out small kinks here and there, I decided to write the whole process out with the hope that others who encounter similar struggles may benefit from this documentation.</p><h3>Creating a Child Theme</h3><p>First things first, like many of the tutorials I found, I recommend creating a child theme to host all the customizations we will be doing, unless you built your own theme from scratch. The reason being that any customizations made to the parent theme would be lost when it is updated to the latest version, and updating all your 3rd party dependencies is highly recommended to patch up any possible security vulnerabilities.</p><p>I won’t go into the details of creating a child theme, but should you need help you can find plenty of tutorials online. I would recommend following the steps provided by the 3rd party theme you selected. For example, Astra has great <a href="https://wpastra.com/docs/install-astra-child-theme/">documentation</a> on this and even provides a <a href="https://wpastra.com/child-theme-generator/">tool</a> to generate the child theme for you! Once you are done, activate that child theme and we’ll be good to start!</p><h3>Aggregating Your Custom CSS</h3><p>The next thing we need to do is to aggregate any custom CSS you may have written into a single file that will be enqueued on the initial load of your site, regardless of which page it’s loaded from. Whereas inline CSS added directly into your HTML will still be rendered properly with Smoothstate.js, the same cannot be said with styles applied through a class attribute. I believe if you use a plugin like <a href="https://wordpress.org/plugins/autoptimize/">Autoptimize</a> that has the option to aggregate your CSS into a single file, you may be able to skip this step. However, should you decide to do it anyway, let me share with you the two ways this can be done:</p><ol><li>Adding all your CSS directly in WordPress Customizer’s built-in CSS editor. You can access this through <strong>Appearance → Customize → Additional CSS</strong>. The advantage of doing it this way is that you can preview your changes live, as long as you’ve added the respective classes into your HTML in each page.</li><li>Adding all your CSS into the stylesheet of your child theme. You can access this <strong>Appearance → Theme Editor</strong>. Select your child theme, and edit the <strong>style.css</strong> file. You won’t be able to see the changes live if you take this route, but I personally decided to do it this way because I installed a plugin called <a href="https://wordpress.org/plugins/html-editor-syntax-highlighter/">HTML Editor Syntax Highlighter</a>, which color codes my classes and CSS attributes nicely.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*6IlBuFEyTOh4NP9wFe6hMw.jpeg" /><figcaption>The two methods to aggregate all CSS: Customizer’s Built-In Editor (Top) or Theme Editor’s Stylesheet (Bottom).</figcaption></figure><h3>Adding Smoothstate.js into Your Site</h3><p>Finally, the steps we are all here for! For integrating Smoothstate.js into WordPress, I followed the steps outlined by this <a href="https://webdesign.tutsplus.com/tutorials/how-to-integrate-smoothstatejs-into-a-wordpress-theme--cms-26610">tutorial</a>. I liked this one more than the others simply because it skipped the creation of a wrapper div tag in the HTML, which may not be easy to do if you use a 3rd party theme. Both the element with “page” as an id and the element with “site-content” class seemed to be universal WordPress elements, but I might be wrong (my Astra theme do have them). If upon following this tutorial Smoothstate.js does not work, you may want to inspect your HTML in your browser.</p><p>For reference, the element with “page” as an id on my site is the div tag which is the direct child of the body tag, and the element with “site-content” class is the sibling of the header tag, located directly after the latter.</p><p>The first thing to do is to download the latest <a href="https://raw.githubusercontent.com/miguel-perez/smoothState.js/master/src/jquery.smoothState.js">Smoothstate.js</a>. Then, add the downloaded script file and another file containing the script gist below into the same folder. I personally prefer adding them both in <strong>assets/js </strong>under my child theme folder, because they will then appear under the Theme Editor together with the child theme’s stylesheet and PHP files, making editing that much easier. To do so, use your hosting provider’s FTP client.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/65eef527b72a75665fd4cdeaedaa7302/href">https://medium.com/media/65eef527b72a75665fd4cdeaedaa7302/href</a></iframe><p>The opening of the script above is slightly different than the tutorial’s because I opted to use the jQuery bundled with WordPress, which has use-strict enabled.</p><p>Once the above is done, all that’s left are to enqueue the scripts and add some CSS. For the latter, you may adopt and modify the tutorial’s CSS, as the classes it affects are not changed in the script above. Or you may copy my version below which does not include the sliding animation.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9dd6a862f4d6aa010303af426d73a1b5/href">https://medium.com/media/9dd6a862f4d6aa010303af426d73a1b5/href</a></iframe><p>Remember to add the CSS the same way following the way CSS is aggregated in the previous section. With that out of the way, open <strong>Appearance → Theme Editor</strong> and add the following lines to the functions.php file:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6f950f23f55e472af88bebc898101ef4/href">https://medium.com/media/6f950f23f55e472af88bebc898101ef4/href</a></iframe><p>You need to replace <em>your-child-theme</em> with the name of your child theme. However, if you decided to place your scripts elsewhere then you need to trace the directory accordingly.</p><p>Save your changes, and run your site to see Smoothstate.js applying partial update when you navigate around your site!</p><h3>Ironing Out Kinks</h3><p>So are we done? Unfortunately not, unless you don’t use any other plugins in your site then probably you are done (then you might want to go straight to the next section). However, if you do use any other plugins to generate your site’s content, then chances are they don’t work or render properly. The reason is that when applying the changes, Smoothstate.js does not reload any stylesheet or run functions specific to that page, because technically the page is not reloaded; it’s just “updated”.</p><p>Personally, none of the content-generating plugins I use require any scripts to run on load. If the same applies to you, then it’s a matter of enqueuing the required CSS file on the initial load of your site. To know what stylesheet needs to be enqueued, you can follow these simple steps:</p><ol><li>Open an incognito tab on your browser.</li><li>Launch the browser’s developer console (you can do a quick Google on how to do this since the instructions are specific to each browser).</li><li>Click on the Network tab of the developer console, and apply the “CSS” filter.</li><li>Now, launch your site’s homepage and see what files are loaded by the browser. Take note of them.</li><li>Once that’s done, open a new incognito page and repeat steps 2 to 4.</li><li>If you notice any file being loaded that was not on the previous list, click on that file in the developer console and then click on the Headers tab.</li><li>Look at the Request URL. It will point out where that file is fetched from. Take note of the path from “wp-content” onwards.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vJdVBeCusqfJt2a1k7Hftg.png" /><figcaption>A screenshot of Chrome’s developer console, showing one of the CSS files fetched on this page. Notice the highlighted path? That is what you should take note of.</figcaption></figure><p>Do this for any page where you notice a rendering issue. Once you got all the additional stylesheets’ paths, head to <strong>Appearance → Theme Editor</strong> and open up the functions.php file. Now, see if there is already a stylesheet enqueuing function there. If not, create a new one and enqueue it following the snippet below:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/401929c80e30226958223c2dfd874bd4/href">https://medium.com/media/401929c80e30226958223c2dfd874bd4/href</a></iframe><p>For every path you noted down, apply the code written in line number 8. Replace <em>my-missing-theme-name</em> with the stylesheet name, <em>my-missing-theme-path</em> with the stylesheet path, and <em>my-missing-theme-version</em> with the stylesheet version, if any (otherwise leave it as ‘’). Click on “Update File”, and try launching and navigating around your site again. Hopefully, all the rendering issues are now fixed.</p><p>The above fix is only applicable to fix the missing stylesheets issue. If your plugin requires one or more functions to be run on page load, then according to this <a href="https://grayscale.com.hk/blog/adding-page-transitions-wordpress/">blogpost</a> you will need to call that function again by adding it to the <strong>onAfter</strong> property of the Smoothstate.js setting.</p><h3>Adding a Loader</h3><p>By this stage, I hope you have a revamped site with Smoothstate.js properly integrated. If you host your site on a managed hosting plan with excellent bandwidth, then chances are you would not need this. However, if like me, you host your site on a shared hosting plan, then sometimes your site might take longer than expected to transition from one page to another. This is where the loader comes to the rescue!</p><p>The idea of a loader is to provide an indicator to the user that the site is not broken. I believe that showing a visitor something is better than nothing. Yet, having a loader shown in each page transition will also be annoying to the user. Hence it’s important to tune the tolerance time before the loader is displayed.</p><p>As our site now applies Smoothstate.js transitions, this loader will only be shown when a visitor is already inside your site and is transitioning between pages. It will not be shown on the initial load of your site.</p><p>As we are transitioning the div tag with the “site-content” class, we will need to add the loader as a sibling to this element. We will also need to ensure that the loader takes up only the remaining space below the header, which remains unchanged throughout the visitor’s visit to the site.</p><p>To do this, we would need to modify the child theme’s header.php file. However, chances are the child theme you created did not come with a header.php file. If so, all you need to do is copy the parent theme’s header.php file into the child theme using your hosting provider’s FTP client. Once that’s done, you can go to <strong>Appearance → Theme Editor </strong>and access the child theme’s header.php file. There, look for the HTML tag with the “site-content” class.</p><p>Before modifying the header.php file, browser the web for or design yourself a good pure CSS loader. If you prefer adopting someone’s design, I recommend getting one from <a href="https://loading.io/css/">loading.io</a>. The 12 designs shown in the hyperlink are all CC0 licensed and can thus be used freely.</p><p>Copy your choice loader’s HTML tags right above the HTML tag with the “site-content” class. Give an id property to your loader so that we can easily refer to it in our script later on. You can refer to the snippet below for reference. Don’t forget to add the CSS into the aggregated CSS file following the steps in the previous section.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e95a3ef3082aadd2905ce07fb1adbee3/href">https://medium.com/media/e95a3ef3082aadd2905ce07fb1adbee3/href</a></iframe><p>As you can see, the loader is initialized with an inline “display: none” style attribute. We will handle the display and hiding of both the content and loader with some jQuery by augmenting the custom script we did above.</p><p>With that said, head to the custom script file in the <strong>assets/js</strong> folder (or wherever you put yours just now) and prepare to do some modifications. The first thing we need to do is to tell Smoothstate.js to do something while the page is rendering. This is done by adding an <strong>onProgress</strong> property to its settings object. During <strong>onProgress</strong>, we would display the loader and hide the content. And then, in <strong>onAfter</strong> we would do the reverse.</p><p>However, as discussed before, we do not want the loader to display right away all the time. Hence, we need to set a tolerance window. Only when loading takes more than the tolerance window will we show the loader to alert the visitor of the unfortunate delay. We can easily do this by calling the “setTimeout” function provided by JavaScript.</p><p>However, now comes another problem! Imagine we provide a tolerance window of 1 second (1000ms). When the page is refreshing, the <strong>onProgress</strong> state initialized an internal timer to show the loader after 1 second. However, the page actually loads after 700ms, during which the <strong>onAfter</strong> procedure takes place. If we do not tell the code to stop and reset the internal timer, the loader will be shown after the page is loaded, which is wrong! Hence, we also need to modify the <strong>onAfter</strong> by adding a “clearTimeout” to reset any initiated timer before rendering the page.</p><p>With all that said, the complete code can be seen in the snippet below:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cfddf4e7862bdf214982f5dd8fae018a/href">https://medium.com/media/cfddf4e7862bdf214982f5dd8fae018a/href</a></iframe><p>In the sample above, we assign a tolerance window of 1 second (1000ms). When the page is loading, the set an internal timer and assign it to the <em>loaderTimer</em> variable. If the page is loaded before the tolerance window, the check on if <em>loaderTimer</em> exists would return true and we would reset the internal timer. However, if the page takes more than 1 second to load, the internal timer would render the loader, which would be removed once the page is rendered.</p><h3>Adding (or Restoring) Google Analytics</h3><p>With the above implemented properly, your site’s UI/UX should look snazzy and modern. Unfortunately, if you’ve incorporated Google Analytics into your WordPress site, it will not work correctly anymore.</p><p>The reason being that when readers navigate around your site, the Analytics script is fired only once during the initial page load. Any navigation afterwards results in only partial updates of the HTML body tag. As such, scripts that normally run when page reload completes will not be run.</p><p>In order to make Google Analytics track page navigations within your website again, we will need to use Autotrack, which is the official Google plugin to make Analytics work on AJAX-based website. Thus, we need to make the following changes:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3369cd8e8ff0bb06aeffbd7303cb98d9/href">https://medium.com/media/3369cd8e8ff0bb06aeffbd7303cb98d9/href</a></iframe><ol><li>If you use the Google Site Kit plugin (which, you should if you haven’t), head to <strong>Settings → Analytics </strong>and switch off the “Let Site Kit place code on your site” feature.</li><li>Before we re-insert the analytics script back into our site manually, we will create another custom JavaScript file (see the <strong>analytics-autotrack.js</strong> file in the gist above) and add it to our child theme’s <strong>assets/js</strong> folder.<br>That script is basically a modification of the default script provided by Google. You can actually keep the default script if all you are interested in is the page view.</li><li>Finally, let’s head to the functions.php<strong> </strong>file of the child theme and add the following code to enqueue the custom script above together with the analytics.js and autotrack.js files into our site’s header file.</li></ol><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7129809767960eebc2b67370aab3300e/href">https://medium.com/media/7129809767960eebc2b67370aab3300e/href</a></iframe><p>With the above changes, when an AJAX call is fired to navigate reader to a new page, this information will be sent to Google Analytics, thus providing you with accurate data again. What’s also nice is that any other event tracker added into the custom JavaScript file above will also be sent to Google Analytics as and when they are triggered. Neat!</p><p>Phew! That was rather long. If you’ve made it to the end, congratulations, and I hope you’ve successfully applied Smoothstate.js to your WordPress site! If you read through it all but have yet to give it a go, I would strongly recommend you to do so. It is not as difficult as it looks 😄 And if you need more encouragement to do it, I hope <a href="https://stevanussatria.com/">my portfolio website</a> will do just that!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DXHB-i0f0MYnhs_WtutN9A.gif" /><figcaption>The end product of all the steps above, so worth it! As you can see, I am on a rather slow network, and the loader helped provide that “I’m working, please wait” feedback to the visitor.</figcaption></figure><h3>References</h3><ol><li><a href="https://github.com/miguel-perez/smoothState.js">smoothState.js</a> official GitHub repository</li><li><a href="https://github.com/googleanalytics/autotrack">autotrack</a> official GitHub repository</li><li><a href="https://grayscale.com.hk/blog/adding-page-transitions-wordpress/">Adding page transitions to WordPress</a></li><li><a href="https://webdesign.tutsplus.com/tutorials/how-to-integrate-smoothstatejs-into-a-wordpress-theme--cms-26610">How to Integrate SmoothState.js Into a WordPress Theme</a></li><li><a href="https://hirecollin.com/2016/05/integrating-smoothstate-wordpress/">Page Transitions in WordPress with SmoothState</a></li><li><a href="https://pixelgrade.com/docs/timber/social-networks/using-google-analytics-ajax-powered-themes/">Using Google Analytics for Ajax Powered Themes</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cb41d4badc7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Achieving Mockup Freeze in Figma]]></title>
            <link>https://stevahnes.medium.com/achieving-mockup-freeze-in-figma-c050d36fb34d?source=rss-76aa3ea36bc6------2</link>
            <guid isPermaLink="false">https://medium.com/p/c050d36fb34d</guid>
            <category><![CDATA[version-control]]></category>
            <category><![CDATA[mockup]]></category>
            <category><![CDATA[figma-plugin]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[figma]]></category>
            <dc:creator><![CDATA[Stevanus Satria]]></dc:creator>
            <pubDate>Thu, 16 Apr 2020 04:01:00 GMT</pubDate>
            <atom:updated>2021-02-15T13:57:34.701Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*QpXxtZ3P01pQdqLB" /><figcaption>Photo by <a href="https://unsplash.com/@kevnbhagat?utm_source=medium&amp;utm_medium=referral">Kevin Bhagat</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h4><em>Figma has its built-in solution, but I am proposing an alternative.</em></h4><p>You are the Product Owner of a Web-App. You are looking for ideas on how to further enrich the current version with more useful features. You decided to go to your team’s design software and browse through the mockups of the App and as you go page by page, you saw something you had not seen in the latest version.</p><p>“Wait, has this been implemented? If not, why?”</p><p>You quickly try to trace the history of this feature; you look through past User Stories, presentation slides, even Release Notes. Yet after a few minutes of backtracking, you still could not find out the reason behind this discrepancy. What’s more unfortunate is that the UX Team makes edits directly on the same file without proper versioning.</p><p>How you wish there is some form of versioning of the mockups…</p><p>As one of the leading design tools, Figma has a very robust <a href="https://help.figma.com/hc/en-us/articles/360038006754-Version-History">Version History</a>. Here are the key features it offers:</p><ol><li>Automatically saves when left idle for 30 minutes</li><li>Supports manual save with custom names</li><li>Allows restoration of versions in-file</li><li>Allows duplication of any version into a separate file</li></ol><p>The beautiful thing about the last feature is that components are cloned instead of instantiated. This means that changes on the components in the original file will not affect the duplicated file, which is perfect when you want to freeze your mockup.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*vQZZAilVeaJFRVBjEaHFxg.gif" /></figure><p>There are a couple of drawbacks to this. Firstly, imagine the amount of file you will end up with after a while, especially if you’re dealing with an enterprise software with multiple components…</p><figure><img alt="After a few duplications, your folder quickly becomes a clutter…" src="https://cdn-images-1.medium.com/max/1024/1*ZEUfwhSu4o-9-SaYUZADgQ.jpeg" /></figure><p>The second one is the fact that duplicating a version clones the entire file, not just the page you are interested in. Hence, if your design file has multiple pages, your clone will contain all of them as well.</p><p>You may be able to avoid cluttering your project by cloning and maintaining a limited number of versions backward. Unfortunately, it still won’t solve the issue of cloning the entire file.</p><p>Enter, <a href="https://www.figma.com/blog/introducing-figma-plugins/">Figma Plugins</a>!</p><p>As early as August 2019, Figma finally supports plugins, and with it comes an API that allows anyone to create plugins. Since then, numerous developers and designers have come up with small utilities that make their work easier and faster.</p><p>It is this support for plugins that make my alternative proposal feasible. Instead of cloning the entire file, we can clone only a page within that file. Now you might ask, “Why do you need a plugin? I can just duplicate the page using Figma’s built-in function, no?”</p><p>Well, here’s why…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SD4cF9lqEybRdFxl4Nx7xw.gif" /></figure><p>If you focus on my erratic mouse movement after duplication, you will see that in the new page, the “Components (Hidden)” frame contains not the components, but instances of the components. This means that any changes made to the components in “Page 1” will affect the instances in “Page 2” as well!</p><p>To prevent this, I would need something that duplicates the page while ensuring the new page is completely detached from the old page so that any changes to the components linked to instances in the original will not affect the duplicate in any way.</p><p>Anyone can create a plugin that achieves all the above points. However, to illustrate how this can be done and how the result may look like, I will be using one which I created: <a href="https://www.figma.com/community/plugin/824942413886528676/PageClone-%7C-A-Better-Page-Cloning-Utility">PageClone</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YzUiPcOVbMyfwfqsEJ2-aw.gif" /></figure><p>As you can see from the image above, when PageClone is run on “Original”, it created a copy of the said page within the same file. However, inspecting the duplicate page more closely and one will notice the absence of any components or instances. This is because every component or instance in the original page is converted into standalone frames in the duplicate, which ensures that the copied page stands separate from any other pages within or even outside of the file.</p><p>However, having too many pages in the same file will make the latter heavy and take longer to load initially. As with using Version Control, you can alleviate this by maintaining only several versions backward.</p><p>So, am I saying to ditch Figma’s built-in functionalities and exclusively use a plugin instead? Well, not really.</p><p>On the contrary, I believe that the best way of achieving mockup freeze is to combine both of them hand in hand. I propose using something like PageClone for short-term freezes based on your team’s SDLC. Once enough cycles have passed, you can then archive the file using Version History (or just simply duplicate the file), which would allow you to delete the plugin-created pages from the original file, hence keeping it lightweight.</p><p>For example, if a team follows a monthly sprint and releases a major version of the application every 4 sprints, the team can:</p><ol><li>Use a plugin (e.g. PageClone) for freezing the mockup corresponding to each sprint’s delivery</li><li>Use Version History (or duplicate the file) to create a new file containing the last 4 sprints, which corresponds to a release</li><li>Once the file is duplicated, the last 4 sprints’ pages can be removed from the original page</li></ol><p>This, I believe, brings out the best of both worlds.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c050d36fb34d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Ohana Mau Loa]]></title>
            <link>https://stevahnes.medium.com/ohana-mau-loa-2c23ca7e211?source=rss-76aa3ea36bc6------2</link>
            <guid isPermaLink="false">https://medium.com/p/2c23ca7e211</guid>
            <category><![CDATA[overcoming-obstacles]]></category>
            <category><![CDATA[family]]></category>
            <category><![CDATA[connection]]></category>
            <category><![CDATA[relationships]]></category>
            <category><![CDATA[covid19]]></category>
            <dc:creator><![CDATA[Stevanus Satria]]></dc:creator>
            <pubDate>Tue, 07 Apr 2020 04:01:00 GMT</pubDate>
            <atom:updated>2021-02-15T14:11:44.111Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*i8HjlIm-Fe6jBVqh" /><figcaption>Photo by <a href="https://unsplash.com/@airdography?utm_source=medium&amp;utm_medium=referral">Benji Aird</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h4><em>Staying connected with your loved ones amidst global immobility.</em></h4><p>The best thing one can have when riding through a difficult time is the companion of one’s dearests; to be able to share the pain with them, and to have them reassure you in their own unique ways that “everything will be alright”. In ordinary times we frequently get annoyed over their presence, yet in extraordinary times the sense of comfort they provide is beyond words.</p><p>As an immigrant in a foreign land, their constant presence has long been a privilege that is out of my reach. My family is one of those that pushed the definition of “global citizenship” to the limit: my brother works in Hong Kong, my mother and girlfriend are both in Jakarta, and I mostly call Singapore my home. We rely on messaging, voice, and video calls to stay in touch on a day-to-day basis. Thus, for 11 years the reliefs to my longing for their physical presence are periodic temporary gatherings, usually on special occasions like Christmas, college graduations, or Lunar New Year. They may be short, but in retrospect, they make the distance that much more bearable.</p><p>It will all be different this year, however, in light of the COVID-19 pandemic. I was lucky to still be able to meet all three of them back in January, and the last time I met my mother was in March when we traveled to Medan together. With the ongoing global lockdown and looking at how rampant the virus spreads, it is unlikely that the situation will get better anytime soon. Who knows how much longer will it be before I can be reunited with any one of them.</p><p>Nonetheless, I believe that there will be light at the end of the tunnel, and it is in our best interest to persevere through the tunnel together so that emerging from it will taste that much sweeter. Thus I am sharing with you the three simple pointers I am adopting keeping the relationship with my loved ones strong as ever:</p><ol><li><strong><em>Stay in touch.</em></strong> This one goes without saying, whether it is simply by text, voice, or video calls. Before you send good morning messages on your team’s Slack workspace, send your greetings to those miles apart from you first. Ask them how was their night, and what they plan to do today. Show them pictures of your home-cooked meals during lunch and of your “Work From Home” desk setup. Distance is no excuse for not doing the things you would normally do when they are around.</li><li><strong><em>Stay updated with the situation where they reside.</em></strong> I have adopted this multiple times, not just during the ongoing COVID-19 pandemic. When the series of riots tore through Hong Kong in 2019, I kept myself updated with the news so that when interacting with my brother, I would not irritate him by falling for false paranoia, but instead engage him in a meaningful and informed conversation about the situation. I also did the same with my mother and girlfriend when the riots broke in Jakarta. Keeping myself updated with their local news gives me a clearer picture of the different challenges each of us is facing, and which allows me to be more empathetic with what they are each experiencing.</li><li><strong><em>Go the extra mile for them.</em></strong> Often we feel powerless in alleviating the inconveniences faced by those who are so far from us. However, remember that technology has made a lot of impossible things possible. Being miles away from them does not mean you are unable to act for them. For the past two months, I have been assisting my mother in getting her health supplements and necessities through Shopee, a popular eCommerce platform in Jakarta. I sourced the items, made the order, and simply provided her with the internet banking number to transfer the payment to (thankfully she knows how to use internet banking). Similarly, when my girlfriend accidentally broke her iPhone 11 case, I got a new one shipped to her in one day so that she does not have to go out and get it herself. They may be small acts in the grand scheme of things, but it shows that you are with them in this trying time.</li></ol><p>Extraordinary times do not always require extraordinary measures, and the above three points prove that. They are simple and very much within your means. Yet I firmly believe that they will go a long way in keeping you and your loved ones engaged and connected while riding out this COVID-19 pandemic, or any situation that reduces mobility. Hopefully, when it passes, all of you emerge stronger and more bonded than ever.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2c23ca7e211" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fetching Document Updates to Plugin UI]]></title>
            <link>https://stevahnes.medium.com/establishing-dialog-between-document-and-plugin-user-interfaces-b4e739465c85?source=rss-76aa3ea36bc6------2</link>
            <guid isPermaLink="false">https://medium.com/p/b4e739465c85</guid>
            <category><![CDATA[responsive]]></category>
            <category><![CDATA[figma-plugin]]></category>
            <category><![CDATA[figma]]></category>
            <category><![CDATA[ui]]></category>
            <category><![CDATA[plugins]]></category>
            <dc:creator><![CDATA[Stevanus Satria]]></dc:creator>
            <pubDate>Sun, 05 Apr 2020 13:22:32 GMT</pubDate>
            <atom:updated>2021-02-15T13:59:04.755Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kjAy2VNkyRT7jXzI" /><figcaption>Photo by <a href="https://unsplash.com/@heftiba?utm_source=medium&amp;utm_medium=referral">Toa Heftiba</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h4><em>Creating an immediate plugin-document-plugin loop based on where the user focuses.</em></h4><p>One of the most confusing parts of writing a Figma Plugin is differentiating between the code.ts and ui.ts (or the JS script within the ui.html file). The way I understand them is as follows:</p><ol><li>code.ts contains the code that is executed on the main Figma Document UI. It has access to the Plugin API as specified in the figma.d.ts file.</li><li>ui.ts (or the JS script within the ui.html file) contains the code that is executed when the user interacts with the Plugin UI (rendered as an iFrame). It does not have access to the Plugin API.</li></ol><p>In many cases, a plugin you are trying to create requires it to extract some information from the Document UI (e.g. current selection). It will then present this information to the user, who then makes some changes or decisions based on it (e.g. wanting to change the size of the selected rectangle). Once the user decides on the appropriate course of action, the plugin needs to tell the Document UI to execute it.</p><p>In order to facilitate this two-way communication, Figma designed a protocol similar to Events for its Plugin API. You can read all about it by going to the <a href="https://www.figma.com/plugin-docs/creating-ui/">official documentation</a>.</p><p>What I want to show you in this article is how to use this protocol to allow the Plugin UI to be aware of changes made in the Document UI without having to re-instantiate itself. In other words, I hope to show you how to establish an immediate plugin-document-plugin feedback loop using the above protocol.</p><p>Essentially, the trick is having the Plugin UI inform the Document UI when the focus is back on the former and then having the latter send an immediate response back. Take a look at the ui.html and code.ts files below:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6a906b52b39e62367a053d0a68be7b66/href">https://medium.com/media/6a906b52b39e62367a053d0a68be7b66/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/209f252776d49e01f5393598729d6abf/href">https://medium.com/media/209f252776d49e01f5393598729d6abf/href</a></iframe><p>What happens is that when you first launch the Plugin, the figma.showUI(__html__, uiOptions) is executed, which renders the Plugin UI. The focus is also automatically set to the Plugin UI.</p><p>When the user shifts focus out of the Plugin UI, nothing happens. However, when the user focuses back into the Plugin UI, it runs the window.onfocus code block, which contains a parent.postMessage call that sends a message back to the Document UI. Notice that instead of sending a simple data type, I decided to send an Object. This allows for the flexibility needed in more complex plugins should there be different types of back-and-forth communication between the Document and Plugin UIs.</p><p>When the Document receives the message from the Plugin UI, it runs the code block within figma.ui.onmessage. In this case, since the Plugin UI has sent a &quot;focus&quot; type of message, it increments the count variable and sends it back to the Plugin UI.</p><p>Finally, the Plugin UI, on receiving the reply from the Document UI, updates the HTML and shows the count as the number of times the user shifts focus out of itself. This is how the working prototype looks like:</p><figure><a href="https://github.com/stevahnes/medium-snippets/tree/master/figma-plugins-how-to/figma-communication-snippet"><img alt="A GIF showing the working prototype in Figma" src="https://cdn-images-1.medium.com/max/400/1*EcqzZE8k-ac1fLCQMcdXqg.gif" /></a><figcaption>Every time I click out of the Plugin UI and back in, the count increments by 1.</figcaption></figure><p>Extending this into a more complex communication mechanism only takes coming up with multiple types of messages which would take different ways of handling within the code.ts code block. Conversely, you may also introduce a type key for the message from the Document to the Plugin UI should you require the extra flexibility on the Plugin UI-side as well. Here is an example of how I used the above implementation to automatically change the suggested name in the plugin’s textbox:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I7CB8vTEtNkJcADeWUYyTA.gif" /><figcaption>When I switched from “Page 1” to “Copy of Page 1” and refocused on the plugin, the textbox automatically adapts to the new page selected.</figcaption></figure><p>And that is how you fetch updates from the Document UI to Plugin UI using the messaging protocol of the Figma Plugin API!</p><p><em>Note: If you want to see the source code, just click on the “Communication Snippet” GIF above.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b4e739465c85" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>