<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Khang</title>
    <description>The latest articles on DEV Community by Khang (@khangnd).</description>
    <link>https://dev.to/khangnd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F493557%2F95de03d9-1145-4565-bd1b-cfe5f5340693.png</url>
      <title>DEV Community: Khang</title>
      <link>https://dev.to/khangnd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/khangnd"/>
    <language>en</language>
    <item>
      <title>Ranking Microsoft Windows versions - 2025 Edition</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Sun, 20 Jul 2025 04:03:58 +0000</pubDate>
      <link>https://dev.to/visnalize/ranking-microsoft-windows-versions-2025-edition-14g0</link>
      <guid>https://dev.to/visnalize/ranking-microsoft-windows-versions-2025-edition-14g0</guid>
      <description>&lt;p&gt;Everyone has their own preferences and opinions on which Windows version is the best, so in this fun little post, I'm going to rank the Windows versions from best to worst in my opinion.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As biased as this sounds, this list is actually backed by facts, statistics, and market share trends (source).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🏆 Windows 7 - the GOAT, no debate
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqirqvh07df19onfjrm9n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqirqvh07df19onfjrm9n.png" alt="Windows 7" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Windows 7, without a doubt, is the best Windows version to this day. It was fast, stable, and had the best user interface. The perfect balance between performance and aesthetics. It took everything people hated about Vista and... didn't do it. Whether you were gaming, working, or just customizing the hell out of your desktop, Windows 7 made you feel like your PC got you. Even after Microsoft ended support, many users clung to it for years, including enterprises, businesses, and individuals.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you disagree, you're against a civilization!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🥈 Windows XP - that startup sound *chefs kiss*
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9ous4pw5fggphyvg1cv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9ous4pw5fggphyvg1cv.png" alt="Windows XP" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Blue skies, green hills, and a startup sound etched into memory. Windows XP was ridiculously lightweight, reliable, and compatible with almost everything. It was the first Windows version to really nail the user experience. It became the backbone of businesses, schools, and homes for years. Paint, Pinball, Clippy, Windows Media Player with custom skins. Enough said. It was the golden age of Windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  🥉 Windows 10 - when Microsoft finally listened
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75zc9g95wybwsrxb62ty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F75zc9g95wybwsrxb62ty.png" alt="Windows 10" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, this one is not on a nostalgia trip, but Windows 10 is a solid operating system. After the mess that was 8 and the "meh" 8.1, this was the comeback we needed. It brought back the Start Menu, improved performance, and finally had users agreeing on something. It was a step in the right direction, even if it had its fair share of bugs and issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  4️⃣ Windows 98 - if you know, you know
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfc120p9nprooixhud6i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfc120p9nprooixhud6i.png" alt="Windows 98" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yet another classic. Windows 98 was &lt;em&gt;the&lt;/em&gt; Windows for anyone growing up in the late 90s. It introduced several features which would become standard in future versions. The aesthetics it inherited from Windows 95 remained iconic. Remember Half-Life, Rollercoaster Tycoon, or Quake? Those games were the reason many of us fell in love with gaming and computers.&lt;/p&gt;

&lt;h2&gt;
  
  
  5️⃣ Windows 11 - trying hard to be cool
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jwgbfxc1hh9gh9phk6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jwgbfxc1hh9gh9phk6d.png" alt="Windows 11" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The latest version of Windows at this point in time. Windows 11 is a mixed bag. It has a sleek design, but it feels like Microsoft is trying too hard to be trendy. The new Start Menu and taskbar are... different. Some people love it, some hate it. It's fast (kinda, if you have the right hardware), but it feels like a glorified Windows 10 update. The new features are nice, but it doesn't feel like a major leap forward. It's like that friend who tries to be cool but ends up being cringy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honorable mentions and conclusion
&lt;/h2&gt;

&lt;p&gt;🎀 &lt;strong&gt;Windows Vista&lt;/strong&gt;: beautiful but slow and buggy, still a solid attempt that paved the way for Windows 7.&lt;/p&gt;

&lt;p&gt;🎀 &lt;strong&gt;Windows 8.1&lt;/strong&gt;: a decent attempt to fix the mess of Windows 8, but just not enough.&lt;/p&gt;

&lt;p&gt;In conclusion, Microsoft has had its ups and downs with Windows versions. Some were revolutionary, while others were just... there.&lt;/p&gt;

&lt;p&gt;But one thing is for sure: if you want to experience the best of Windows 7 and every other Windows version mentioned above, you can always check out &lt;a href="https://visnalize.com/win7simu/about" rel="noopener noreferrer"&gt;Win7 Simu&lt;/a&gt;. It's the closest thing to reliving the glory days of Windows 7 without the hassle of installing it on your machine, or messing around with virtual machines and technical stuff. Just pure nostalgia and fun.&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>I built a Nokia Composer with AI's assistance</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Mon, 10 Mar 2025 04:17:53 +0000</pubDate>
      <link>https://dev.to/visnalize/i-built-a-nokia-composer-with-ais-assistance-a4f</link>
      <guid>https://dev.to/visnalize/i-built-a-nokia-composer-with-ais-assistance-a4f</guid>
      <description>&lt;p&gt;I have recently released a new update to &lt;a href="https://visnalize.com/brick1100/about" rel="noopener noreferrer"&gt;Brick 1100&lt;/a&gt; a few days ago, this update includes the new &lt;a href="https://visnalize.com/brick1100/changelog#_0-0-14-mar-6-2025" rel="noopener noreferrer"&gt;Composer feature&lt;/a&gt; allowing users to make their own ringtones in a monophonic style. It's a feature that I never thought I would be able to implement on my own, having no prior knowledge of music theory and even never having used the Nokia Composer before. However, with the help of AI, I was able to build it, in a considerably short amount of time. In this post, I would like to share the process of building the Nokia Composer and how AI has evolved remarkably to make it possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Nokia Composer?
&lt;/h2&gt;

&lt;p&gt;Composer was a built-in feature on several classic Nokia phones, allowing users to create their own monophonic ringtones. It provided a simple interface where users could manually enter musical notes, defining their pitch and duration. This feature was a popular way for users to personalize their phones in the pre-polyphonic and MP3 ringtone era, enabling them to compose famous tunes, TV theme songs, or even their own musical creations.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;The interface allow users to input notes using the phone's keypad. Each key corresponds to a different musical note, and additional options let users adjust the octave and duration of each note. Once a melody is created, it can be saved and set as the ringtone.&lt;/p&gt;

&lt;p&gt;A typical composing process included:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Opening the Composer – Accessible through the phone's menu, a blank canvas would appear for users to start composing.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Composing the tune – Users could input notes using the phone's keypad:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Numeric keys &lt;code&gt;1&lt;/code&gt;-&lt;code&gt;7&lt;/code&gt; are used to assign musical notes&lt;/li&gt;
&lt;li&gt;Keys &lt;code&gt;8&lt;/code&gt; and &lt;code&gt;9&lt;/code&gt; change the note's duration&lt;/li&gt;
&lt;li&gt;Key &lt;code&gt;0&lt;/code&gt; adds a rest&lt;/li&gt;
&lt;li&gt;Key &lt;code&gt;*&lt;/code&gt; shifts the note's octave&lt;/li&gt;
&lt;li&gt;Key &lt;code&gt;#&lt;/code&gt; makes the note sharp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Editing the tune – The melody could be played back, and individual notes could be modified or deleted as needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Saving and setting as ringtone – Once satisfied, users could save their custom melody and assign it as the default ring&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;



&lt;h3&gt;
  
  
  Deep dive
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvisnalize.com%2Fassets%2Fnote-structure.C8Lt6fjU.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvisnalize.com%2Fassets%2Fnote-structure.C8Lt6fjU.svg" alt="A note's structure" width="368" height="265"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;All possible combinations of a note's structure&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nokia Composer follows a structured approach to note input, using a simplified notation system. Below is a breakdown of the key components involved in composing a melody:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Musical notes:&lt;/strong&gt; Each numeric key, &lt;code&gt;1-7&lt;/code&gt;, is assigned a specific note:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; = C (Do)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2&lt;/code&gt; = D (Re)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3&lt;/code&gt; = E (Mi)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;4&lt;/code&gt; = F (Fa)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;5&lt;/code&gt; = G (Sol)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;6&lt;/code&gt; = A (La)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;7&lt;/code&gt; = B (Ti)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duration:&lt;/strong&gt; Keys &lt;code&gt;8&lt;/code&gt; and &lt;code&gt;9&lt;/code&gt; adjust the note's length. The default duration is a quarter note (1/4 length of a whole note), which is represented by number &lt;code&gt;4&lt;/code&gt;. Pressing &lt;code&gt;8&lt;/code&gt; halves the duration, while &lt;code&gt;9&lt;/code&gt; doubles it. The corresponding values are:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; = whole note&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2&lt;/code&gt; = half note&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;4&lt;/code&gt; = quarter note&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;8&lt;/code&gt; = eighth note&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;16&lt;/code&gt; = sixteenth note&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dotting a note increases its duration by half. For example, a dotted quarter note is 3/8 (1/4 + 1/8) of a whole note.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Octave:&lt;/strong&gt; The &lt;code&gt;*&lt;/code&gt; key is used to shift a note's octave, typically covering 3 octaves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rests:&lt;/strong&gt; The &lt;code&gt;0&lt;/code&gt; key is used to insert a rest (pause between notes). Duration keys can also apply to rests, adjusting their length accordingly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sharp notes:&lt;/strong&gt; The &lt;code&gt;#&lt;/code&gt; key is used to make a note sharp, raising its pitch by a semitone, not applicable to the E and B notes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tempo:&lt;/strong&gt; The beats per minute (BPM) value to control the speed of the melody.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Example
&lt;/h4&gt;

&lt;p&gt;Let's take &lt;code&gt;4c2&lt;/code&gt; as an example, this represents a quarter note C in the second octave, which is also the default note for the Composer. By common convention, a quarter note equals to 1 beat, hence if we set the tempo to 120 BPM, the duration of this note would be 0.5 seconds (60 / 120 = 0.5s). In the same manner, we can interpret other note combinations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;8c2&lt;/code&gt; = eighth note C in the second octave with a duration of 0.25s (half a beat)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2c2&lt;/code&gt; = half note C in the second octave with a duration of 1s (2 beats)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;4.c2&lt;/code&gt; = dotted quarter note C in the second octave with a duration of 0.75s (1 and a half beats)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;4#c2&lt;/code&gt; = quarter note C# in the second octave with a duration of 0.5s&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;16.#d1&lt;/code&gt; = sixteenth note D# in the first octave with a duration of 0.125s (1/4 beat)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How I built it
&lt;/h2&gt;

&lt;p&gt;I hope the above explanation gives you a good understanding of how the Nokia Composer works, because that's something I didn't know prior to building it. I had never used the Composer feature on a Nokia phone either, so I wasn't sure if I would ever get to implement it in Brick 1100. However, the project wouldn't fulfill its purpose as a Nokia 1100 simulator without this iconic feature, and become a let down for users who were expecting it. I decided to give it a shot, and with the help of AI, anything now seems possible.&lt;/p&gt;
&lt;h3&gt;
  
  
  With AI's assistance
&lt;/h3&gt;

&lt;p&gt;In summary, I used &lt;a href="https://cursor.com" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt; (an AI code editor) with the Claude 3.5 Sonnet model to build, the entire process took me 11 prompts, around 3 days to make the Composer fully functional and integrated with the project's codebase.&lt;/p&gt;

&lt;p&gt;It's amazing to see how AI has evolved in such a short time, enabling developers like me to build complex features without prior knowledge or experience in a certain field. I remember just months ago, AI tools like ChatGPT or GitHub Copilot are just making dumb, made-up suggestions when it comes to coding, but now they can actually provide helpful assistance. This is even more impressive with Cursor + Claude's model, which could generate for me a fully functional Composer in the very first prompt. Though to be fair, quite a few iterations were needed to refine the code, especially in handling the core logic of the Composer and integrating it with the existing codebase, but the AI's suggested code was an excellent starting point. It's not an exaggeration to say that, as a software developer, I should be worried about my job security due to the rapid growth of AI, but as an indie maker, it makes me feel like I have a superpower to build anything I want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm48p1ypd8tdi6kw379zq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm48p1ypd8tdi6kw379zq.png" alt="First prompt to build Nokia Composer" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without much instruction, solely from my first simple prompt, the AI agent was able to gather the necessary information of how the Nokia Composer works by searching the web, it then scanned the existing codebase to understand the structure, inspected the relevant parts for the conventions, and reused for generating the code. The result was great, the Composer was functional, but it was nowhere near perfect. There were still flaws, bugs, and inefficiencies that needed to be taken care of. It couldn't understand the way the keypad input was handled (so it improvised, but completely off the mark), the composer interface didn't fit in the overall layout, and the notes' pitch and duration were not accurate. In general, if I were to give the generated code a score, it would get a 6/10, but the most crucial and hardest part was done, so I was pretty happy with it.&lt;/p&gt;


&lt;h3&gt;
  
  
  Iterations and refinements
&lt;/h3&gt;

&lt;p&gt;From reviewing the generated code, I knew where the problems lied, but I had no idea how to fix them at that point. Luckily, I found &lt;a href="https://github.com/zserge/nokia-composer" rel="noopener noreferrer"&gt;this version&lt;/a&gt; of Composer built by &lt;a href="https://zserge.com/" rel="noopener noreferrer"&gt;Serge Zaitsev&lt;/a&gt;, which has a rather simple and clean implementation to follow. I used this as a reference source to feed the AI agent, asking it to explain the code to me and refactor it to be more readable and follow the project's coding style.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fodqnoz02430kywd3pg00.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fodqnoz02430kywd3pg00.png" alt="Feeding the AI with a reference source" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The generated code this time addressed most of the issues related the core logic of the Composer, once again, AI has been proven to be a wonderful tool for learning and adapting as it evolves. After some manual clean-up and adjustments, the Composer was finally in a good shape, the most crucial part of the Composer's logic was then encapsulated within the below function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {Note[]} sequence The sequence of notes to play
 * @param {MediaStreamAudioDestinationNode} [destination] The stream destination to record audio
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;playSequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oscillator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOscillator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gainNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createGain&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;oscillator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gainNode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;oscillator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;square&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;oscillator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;gainNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setAudioParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValueAtTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="nx"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;octave&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSharp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hasDot&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;noteChar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ASCII value of note&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;noteStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;noteChar&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.6&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// map note to the 12-tone scale&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;octaveOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;octave&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;noteIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noteStep&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSharp&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;octaveOffset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isRest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;noteChar&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adjustedVolume&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// adjust volume based on keypad volume&lt;/span&gt;

    &lt;span class="nf"&gt;setAudioParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oscillator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;261.63&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noteIndex&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// convert to frequency (Hz)&lt;/span&gt;
    &lt;span class="nf"&gt;setAudioParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gainNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isRest&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;adjustedVolume&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;noteDuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tempoValue&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasDot&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;noteDuration&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;setAudioParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gainNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// add a small pause between notes&lt;/span&gt;
    &lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;noteDuration&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audioContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In simple words, the function above takes a sequence of notes and plays them back in the correct pitch, duration, and tempo. It uses the Web Audio API to generate the sound, and the function is called whenever a note is inputted or a melody composition is played. It also takes the destination stream as an optional parameter, allowing the composition to be recorded for exporting as a ringtone, an enhancement that wasn't available in the original Nokia Composer.&lt;/p&gt;

&lt;p&gt;From this point, I just had to make some more manual tweaks to make the Composer's UI fit in the project's layout, and used a few more prompts to fix some unknown issues as they popped up when testing the feature on Android and iOS. As mentioned earlier, the total time spent on building it was around 3 days with 11 prompts, and we had a production-ready Nokia Composer in Brick 1100.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building the Nokia Composer was a challenging yet rewarding experience, and it wouldn't have been possible without the help of AI. I wouldn't know where to start to get a sufficient knowledge of music theory, let alone implement a feature like this in a short amount of time. Regardless how you perceive AI, it's undeniable that it has revolutionized the way we build software, and it's only going to get better from here. I'm excited to see what other features I can build with AI's assistance, and I hope you are too.&lt;/p&gt;

&lt;p&gt;If you haven't tried out the Composer feature in Brick 1100 yet, I encourage you to give it a go, and let me know what you think (there's also a &lt;a href="https://discord.gg/6AQDnZa4Xm" rel="noopener noreferrer"&gt;Discord server&lt;/a&gt; to hang out, leave feedback, or share your creations, join us if you're interested).&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Fri, 24 Jan 2025 04:05:55 +0000</pubDate>
      <link>https://dev.to/khangnd/-6im</link>
      <guid>https://dev.to/khangnd/-6im</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/visnalize" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F7434%2F3f904b3c-0bfe-4915-850c-d08fe0b5d5de.png" alt="Visnalize" width="512" height="512"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F493557%2F95de03d9-1145-4565-bd1b-cfe5f5340693.png" alt="" width="460" height="460"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/visnalize/turning-my-codepen-into-an-actual-app-brick-1100-on3" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Turning my codepen into an actual app - Brick 1100&lt;/h2&gt;
      &lt;h3&gt;Khang for Visnalize ・ Oct 7 '23&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#android&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#showdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Turning my codepen into an actual app - Brick 1100</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Sat, 07 Oct 2023 05:26:48 +0000</pubDate>
      <link>https://dev.to/visnalize/turning-my-codepen-into-an-actual-app-brick-1100-on3</link>
      <guid>https://dev.to/visnalize/turning-my-codepen-into-an-actual-app-brick-1100-on3</guid>
      <description>&lt;p&gt;Some time ago, in one of my very first posts on DEV, I shared a silly codepen made from learning for pure fun:&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/khangnd/nokia-1100-simulation-2hef" class="crayons-story__hidden-navigation-link"&gt;Nokia 1100 Simulation&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/khangnd" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F493557%2F95de03d9-1145-4565-bd1b-cfe5f5340693.png" alt="khangnd profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/khangnd" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Khang
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Khang
                
              
              &lt;div id="story-author-preview-content-546477" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/khangnd" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F493557%2F95de03d9-1145-4565-bd1b-cfe5f5340693.png" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Khang&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/khangnd/nokia-1100-simulation-2hef" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Dec 18 '20&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/khangnd/nokia-1100-simulation-2hef" id="article-link-546477"&gt;
          Nokia 1100 Simulation
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/codepen"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;codepen&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/html"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;html&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/css"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;css&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/khangnd/nokia-1100-simulation-2hef" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;173&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/khangnd/nokia-1100-simulation-2hef#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              10&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            1 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;Turned out people found it interesting somehow as the post and the codepen itself was seen receiving a few interactions. Years later, after gaining more skills, and more experience, I came back to this idea to actually complete it. From a mere silly codepen that was barely functional, it has become a full-fledged app (though still in beta) and made its way to &lt;a href="https://play.google.com/store/apps/details?id=com.visnalize.brick1100" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Play&lt;/strong&gt;&lt;/a&gt;. In this article, I'm happy to share the progress, how and what I used to build it, and let's explore some cool and unique features I have brought out with this app.&lt;/p&gt;

&lt;h2&gt;
  
  
  A silly idea that got realized
&lt;/h2&gt;

&lt;p&gt;We, developers, tend to look for project ideas where we can challenge ourselves and put our knowledge and skills into practice. Just like everyone else, when I first got myself into web dev, I had plentiful ideas of what I could build to learn coding more easily, enrich my portfolio with more useless projects, and dazzle the recruiters to land a fulfilling job. However, a little bit out of the ordinary person I am, I actually wanted to build something cool, something original that not many people had thought of and done, so I came up with the idea of replicating the look of an old phone (whoa, how innovative...) and simulate some of its functionalities (so original...). As a result, we have the "Nokia 1100 simulation" codepen above.&lt;/p&gt;

&lt;p&gt;At that time, I stopped where I thought was sufficient for a silly idea as it was, even if I wanted to go further, my skills at that point wouldn't allow it, because I was still a NOOB! (though I still am). I just left it there and forgot about it. Sometime later, after having gained some experience working for companies and leveling up myself a bit, I revisited some past projects to see if I could advance any of them with my new abilities. The Nokia simulation was at the top of that list, considering how much traction it gained at the time (maybe not much for you, but that was a lot for a NOOB!). And here we are, a pet project that actually got finished and made it to the public.&lt;/p&gt;

&lt;h2&gt;
  
  
  The making process
&lt;/h2&gt;

&lt;p&gt;The idea initiated in codepen was made with pure HTML/CSS/JS as I had just started learning the fundamentals. However, this time, applying the wealth of front-end development knowledge I have earned over the years, I rebuilt the project from scratch, making good use of modern web technologies and frameworks to speed up the development, and ease the feature addition and maintenance process as it grows.&lt;/p&gt;

&lt;p&gt;I started spending my free time outside of work hours and weekends to get into it. After about two weeks, I finally made it an MVP (minimum viable product) with most of the &lt;a href="https://visnalize.com/brick1100/changelog.html#_0-0-1" rel="noopener noreferrer"&gt;core features covered&lt;/a&gt;, sort of. So far, the most prominent stuff that I used to build it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vue 2.7&lt;/strong&gt; - the main framework that empowers its UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pinia&lt;/strong&gt; - the state management library to handle shared state across components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vue Router&lt;/strong&gt; - the routing library to ease the navigation within the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capacitor&lt;/strong&gt; - the MVP that helps transition a traditional web app into a mobile app effortlessly.&lt;/li&gt;
&lt;li&gt;And lastly, the most incredible database for managing user data - &lt;strong&gt;localStorage&lt;/strong&gt; 😂&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a few other packages and libraries that enhance the developer experience and contribute to the feature feasibility, e.g several &lt;strong&gt;Capacitor plugins&lt;/strong&gt; wiring up certain native mobile features for the app, &lt;strong&gt;dayjs&lt;/strong&gt; providing out-of-the-box utils to work with date and time, or &lt;strong&gt;voca&lt;/strong&gt; for handy string utils without the needs of reinventing the wheel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Breaking down the components
&lt;/h3&gt;

&lt;p&gt;At a high level, the app is composed of the following major building blocks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65aigdwqjto881os3uax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65aigdwqjto881os3uax.png" alt="Brick 1100 components" width="304" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The container, which is just a freaking image, is layered below the other components. It also holds the responsibility of resizing the app to adapt to the device/browser window's size.&lt;/li&gt;
&lt;li&gt;The screen plays a vital role in rendering what would be otherwise visible to the users.&lt;/li&gt;
&lt;li&gt;The keypad/numpad is in charge of the interactivity of the whole app. The pattern here is that with the help of Pinia, the keypad/numpad would emit respective global events as the users interact with it and the other components then behave accordingly. It is easily the toughest part that I had to deal with as meticulously as possible, to capture the essence of a nostalgic feeling back when we all still used these pads to operate a phone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an outlook on how the above design is implemented for your reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;phone-container&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;phone-screen&lt;/span&gt; &lt;span class="na"&gt;:state=&lt;/span&gt;&lt;span class="s"&gt;"state"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;menu-screen&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Menu"&lt;/span&gt; &lt;span class="na"&gt;:index=&lt;/span&gt;&lt;span class="s"&gt;"index"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;menu-select&lt;/span&gt;
          &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;
          &lt;span class="na"&gt;:items=&lt;/span&gt;&lt;span class="s"&gt;"items"&lt;/span&gt;
          &lt;span class="na"&gt;:current=&lt;/span&gt;&lt;span class="s"&gt;"index"&lt;/span&gt;
          &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;[Event.Back]=&lt;/span&gt;&lt;span class="s"&gt;"handleMenuBack"&lt;/span&gt;
          &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;[Event.Select]=&lt;/span&gt;&lt;span class="s"&gt;"handleMenuSelect"&lt;/span&gt;
          &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;[Event.Change]=&lt;/span&gt;&lt;span class="s"&gt;"handleMenuChange"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/menu-screen&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/phone-screen&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;phone-keypad&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;phone-numpad&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/phone-container&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simplified snippet of the keypad/numpad implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PhoneKeypad.vue&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;isHolding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;mapStores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;useKeypadStore&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearTimer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;press&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearTimer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keypadStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;press&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;HOLD_TOLERANCE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearTimer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;HOLD_TOLERANCE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isHolding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keypadStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isHolding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;hold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isHolding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keypadStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// keypad.js&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useKeypadStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keypad&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;_diff&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// workaround to observe the keypad interaction,&lt;/span&gt;
      &lt;span class="c1"&gt;// as the key before and after the interaction may be the same key.&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_diff&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;press&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Gesture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Press&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Gesture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;hold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Gesture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding some twists
&lt;/h3&gt;

&lt;p&gt;While the project originally aimed to replicate the phone experience faithfully, it also presented an opportunity to add unique twists that, to me, might turn out to be the selling points for the app to be more useful: a collection holder of &lt;strong&gt;mini-games/apps&lt;/strong&gt; where newbie devs can also &lt;strong&gt;learn&lt;/strong&gt; coding by submitting to this collection.&lt;/p&gt;

&lt;p&gt;Due to the simplistic nature of the app and its design, I have a strong belief that it can be perceived as a code playground where people can get their ideas implemented in the rawest form, text-based apps, or apps with pixelated, monotonic graphics. Let's take a look at the simple model below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcllsehc05yilq0orszfc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcllsehc05yilq0orszfc.png" alt="Bridge 1100 model" width="536" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Brick 1100 was built in a way that we could easily extend its functionalities with external games/apps. These external games/apps can communicate with Brick 1100 itself back and forth via an interface called Bridge 1100, you can read more about that &lt;a href="https://github.com/Visnalize/bridge-1100" rel="noopener noreferrer"&gt;in this Github repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's nothing sort of any kind of innovation (as expected from a noob). Those external apps/games are just being gathered and pulled from &lt;a href="https://github.com/Visnalize/brick-1100-apps" rel="noopener noreferrer"&gt;this Github repo&lt;/a&gt;. By the time of this article, you can see from that repo, there are only 2 apps available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pwd Generator&lt;/strong&gt; - a simple password generator from a length input.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Randomizer&lt;/strong&gt; - a simple randomizer app that outputs a random result each time depending on the selected mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of them are super simple, plain text-based apps that can be completed in no time. However, they were developed using different web techs, with the first one using pure HTML/CSS/JS while the latter using the Mithril.js framework. This gives you the freedom of choice when it comes to the web tech that you want to learn by making and takes relatively little of your time and effort to complete an app idea.&lt;/p&gt;

&lt;p&gt;How those apps show up in Brick 1100:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F53cw2mjrfxzu6dpo0zwo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F53cw2mjrfxzu6dpo0zwo.jpg" alt="Brick 1100 online apps" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Despite how silly and ridiculously simple this project looks, I had a really great time building it and felt super proud to see a pet project that actually came to light and got installed on a few user devices. If it has somehow captured your interest and want to try it out, you can install it from &lt;a href="https://play.google.com/store/apps/details?id=com.visnalize.brick1100" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Play&lt;/strong&gt;&lt;/a&gt;. And feel free to join &lt;a href="https://discord.gg/6AQDnZa4Xm" rel="noopener noreferrer"&gt;our Discord&lt;/a&gt; to have some little chit-chat, or if you want to build something on it but getting stuck somewhere, I'm happy to help out there.&lt;/p&gt;

&lt;p&gt;And now, if you will excuse me I have an app to develop, and some users to satisfy. Thank you for reading ✌&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>android</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I rebuilt my portfolio after 2 years</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Sat, 16 Apr 2022 04:40:24 +0000</pubDate>
      <link>https://dev.to/khangnd/i-rebuilt-my-portfolio-after-2-years-1fmk</link>
      <guid>https://dev.to/khangnd/i-rebuilt-my-portfolio-after-2-years-1fmk</guid>
      <description>&lt;p&gt;It's gonna be a long article with many boring things all about me, I believe it's fair to think that some of you just want to see my portfolio. So here you go:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web.archive.org/web/20220509014455/https://khang-nd.github.io/" rel="noopener noreferrer"&gt;Old version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://khangnd.info/" rel="noopener noreferrer"&gt;New version&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;So, after 2 years in the software industry, I officially hit the first milestone of pursuing my passion for front-end development. I was offered the front-end developer role at an &lt;a href="https://unios.com/" rel="noopener noreferrer"&gt;Australia-based company&lt;/a&gt; at the beginning of this year. It was a pleasant coincidence for which I neither searched nor applied for the role I was offered, and the guy who reached out to me was neither an HR nor recruiter, he was a fellow developer who was simply impressed by my silly &lt;a href="https://github.com/khang-nd/7.css" rel="noopener noreferrer"&gt;pet&lt;/a&gt; &lt;a href="https://github.com/khang-nd/win7" rel="noopener noreferrer"&gt;projects&lt;/a&gt;. He is now a colleague and a senior who is always supportive and proactively helps me out in my work. And even better, the working culture here is surprisingly flexible and respectful, I have full control over my time and save a lot of commuting cost and time, as I'm working remotely from home, connecting with the Aussie team via MS Teams, or whenever I feel like to, I'm always welcome at the local office in Vietnam. Lucky me!&lt;/p&gt;

&lt;p&gt;Anyway, that was a little bit sharing of my current status, and you may be wondering, why the hell did I rebuild my portfolio if I wasn't looking for a change of job? Yep, that's a valid question, I rebuilt my personal portfolio website after 2 years, not to impress the recruiters, not to find a new job, but to pick up the new tech stack I use at my current job, a whole lot of things that I have never used before, and because it's enjoyable. So in this blog post, I would like to share with you the experience, and of course, to show off the &lt;a href="https://khangnd.info/" rel="noopener noreferrer"&gt;final product&lt;/a&gt; which I feel so proud and happy to realize how far I have progressed with my skills 😊.&lt;/p&gt;

&lt;h2&gt;
  
  
  A little bragging/motivation
&lt;/h2&gt;

&lt;p&gt;Back when I joined DEV community in late October of 2020, I made my entrance by leaving a comment on the 96th Welcome Thread to introduce myself with my portfolio.&lt;/p&gt;


&lt;div class="liquid-comment"&gt;
    &lt;div class="details"&gt;
      &lt;a href="/khangnd"&gt;
        &lt;img class="profile-pic" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F493557%2F95de03d9-1145-4565-bd1b-cfe5f5340693.png" alt="khangnd profile image"&gt;
      &lt;/a&gt;
      &lt;a href="/khangnd"&gt;
        &lt;span class="comment-username"&gt;Khang&lt;/span&gt;
      &lt;/a&gt;
      &lt;span class="color-base-30 px-2 m:pl-0"&gt;•&lt;/span&gt;

&lt;a href="https://dev.to/khangnd/comment/173o9" class="comment-date crayons-link crayons-link--secondary fs-s"&gt;
  &lt;time class="date-short-year"&gt;
    Oct 21 '20
  &lt;/time&gt;

&lt;/a&gt;

    &lt;/div&gt;
    &lt;div class="body"&gt;
      &lt;p&gt;👋🤓 Hello all,&lt;br&gt;
Here to say what I said, do what I'm about to do: introduce myself through my portfolio - &lt;a href="http://khang-nd.github.io" rel="nofollow noopener noreferrer"&gt;khang-nd.github.io&lt;/a&gt;. I'm glad to be part of the greatness, and all the best to everyone reading any comment here.&lt;/p&gt;


    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;And it turned out, people enjoyed my portfolio, &lt;a href="https://github.com/khang-nd/.info/tree/v1" rel="noopener noreferrer"&gt;the github repo&lt;/a&gt; received around 20⭐, my comment received the most ❤ reactions at that time, and in the end, I was awarded the &lt;a href="https://dev.to/badge/beloved-comment"&gt;Beloved Comment badge&lt;/a&gt;. Totally unexpected, I was super excited, what an epic entrance I had!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdveqe5kffv638aublrc1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdveqe5kffv638aublrc1.gif" alt="Davie504 Epico" width="498" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But yeah, that's that. Just to say I built the first version of my portfolio nearly 2 years ago, and again, it was not to impress the recruiters as I was already working at my &lt;a href="https://www.bosch.com/" rel="noopener noreferrer"&gt;former company&lt;/a&gt;, but rather, I was learning React and tried to find something to practice its fundamental concepts. I had no experience with React prior to joining that company, all I knew was HTML, CSS, JS, and some jQuery, just basic stuff huh. React at that time was something foreign, something fancy to me. In fact, even during the whole time I worked at the former company, we rarely needed to build anything that was complex enough to apply any library or framework, other than jQuery, as most of those things we worked on were just automation scripts and simple plugins. But anyhow, we were still allowed the freedom to apply any new library/framework we preferred in our work per our team's competency skills development policies. And that was the motivation for me to build my first portfolio in React.&lt;/p&gt;

&lt;p&gt;Now at the new workplace, in the role I have been yearning for, having a chance to build UI stuff from the beautiful designs prepped by a strong and professional design team, I'm really enjoying myself here. However, at the same time, I also feel overwhelmed, due to the fact that those 2 years of experience I had barely fit in the new workplace. I'm now helping build a bigger thing, using more advanced and complex web techs, minding about responsiveness and accessibility while sticking to the designs. All brand new experience to me, which is why I need to keep striving, little by little, and the idea of rewriting my portfolio from scratch using the same tech stack the project is using is part of the effort (FYI, our project is using React/NextJS, TypeScript, Theme UI, Framer Motion for the front-end, Storybook for component documentation, and PostgreSQL as the database, Strapi, Prisma, GraphQL for the back-end, and dozens of other packages). Therefore, for this second incarnation of my portfolio, I applied &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;NextJS&lt;/a&gt;, &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;, &lt;a href="https://theme-ui.com/" rel="noopener noreferrer"&gt;Theme UI&lt;/a&gt; and &lt;a href="https://www.framer.com/motion/" rel="noopener noreferrer"&gt;Framer Motion&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The process and experience
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/getting-started" rel="noopener noreferrer"&gt;Getting started with NextJS&lt;/a&gt; was simple and straightforward, just like any other frameworks whose existence is to ease our life as developers. With just a few commands, I got the all the necessary stuff up and running.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/basic-features/typescript" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; came integrated with NextJS, I didn't have to worry about anything like the steps to set up or config TS. By enabling the &lt;code&gt;--ts&lt;/code&gt; flag in the &lt;code&gt;create-next-app&lt;/code&gt; command, NextJS did all the necessary stuff, simple as that.&lt;/p&gt;

&lt;p&gt;Deciding the file/folder structure is probably not a bothersome thing to consider for this kind of project, if not worthless. But still, as someone who prefers things organized and tidy, I did spend quite some time looking up guidelines, best practices and some reference resources. In the end, this is the final structure as of this writing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa8qlqchfpammsoolup5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa8qlqchfpammsoolup5t.png" alt="Winport's project structure" width="345" height="757"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For simplicity, the direction I went for was &lt;strong&gt;file separation by types&lt;/strong&gt;, React components were placed in the &lt;code&gt;components&lt;/code&gt; folder, hooks grouped together in the &lt;code&gt;hooks&lt;/code&gt; folder, contexts in &lt;code&gt;contexts&lt;/code&gt; and so on. Anything else that didn't make sense to group with the others was dumped in &lt;code&gt;misc&lt;/code&gt;. The &lt;code&gt;components&lt;/code&gt; folder was further divided using &lt;a href="https://atomicdesign.bradfrost.com/chapter-2/" rel="noopener noreferrer"&gt;Brad Frost's Atomic Design method&lt;/a&gt;. I can imagine this is a subjective matter with a never-ending argument when working in a team, as even if it was just me with this project, I still had trouble being firm and decisive and sometimes ended up moving files around. I suppose &lt;a href="http://react-file-structure.surge.sh/" rel="noopener noreferrer"&gt;&lt;strong&gt;this&lt;/strong&gt;&lt;/a&gt; makes so much sense after experiencing it myself. All in all, my takeaway is that just pick one template/boilerplate of a project with the same type as yours (there are plenty out there) and get right onto it, or don't waste time defending your ideal if it's not a big deal or causes major refactoring. We have 💩 to do, a lot of it.&lt;/p&gt;

&lt;p&gt;Working with TypeScript turned out to be surprisingly pleasant. Surprising in a sense that I actually have learned and tried static-typed languages before (Java, C# back in the days I was still in college) and didn't quite like those languages due to their complexity from my &lt;strong&gt;personal&lt;/strong&gt; perspective. I grew attached to JavaScript after learning about web dev as it offered the freedom to define and use variables in any way I wanted, I didn't have to worry about what type I should assign or no longer the nightmares of trying to understand the concepts associated to those static types (OOP, polymorphism, abstraction, anyone?). I guess at that point, my brain was not mature enough to accept them as well as the great advantages they bring. As a result, I never expected that I would come back to like static type one day. However, TypeScript changed my mind, the longer I worked with it, the more benefits I could realize and enjoy. There are just way too many benefits that I could easily get obsessed with. But again, this is still my &lt;strong&gt;personal&lt;/strong&gt; experience, it may not be the case for everyone, the key takeaway is that, to learn and realize the benefits of something fully and thoroughly, the only way is to see it for yourself, experience it, and feel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://theme-ui.com/getting-started/" rel="noopener noreferrer"&gt;Theme UI&lt;/a&gt; was an awesome toy to play the "organized" game. All the styling variables, such as spacings, sizes, colors, breakpoints were centrally defined in &lt;a href="https://github.com/khang-nd/khang-nd.github.io/blob/main/src/themes/index.ts" rel="noopener noreferrer"&gt;one place&lt;/a&gt; and they could be used across all our components, making a constraint to enforce the consistency. Even better, the almighty &lt;a href="https://theme-ui.com/sx-prop" rel="noopener noreferrer"&gt;&lt;code&gt;sx&lt;/code&gt; prop&lt;/a&gt; brought a lot of benefits, such as inline styling for our components, and made the pain of coming up with the class names disappear. And as the name implies, Theme UI is perfect for, you know, &lt;a href="https://theme-ui.com/theme-spec" rel="noopener noreferrer"&gt;theming the UI&lt;/a&gt;, it was designed for that and did that job flawlessly. It supported dark/light mode out of the box and offered the hooks to manipulate the color modes so easily. However, my portfolio was slightly unique in the way that it offered several different themes that didn't simply rely on the color mode, but also on some features of the UI.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flat&lt;/th&gt;
&lt;th&gt;Soft&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fksdbpfugmrvygkupy4pc.png" alt="Flat theme" width="398" height="385"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n1er1xc5wve7gxms0g2.png" alt="Soft theme" width="394" height="372"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;The Flat theme has the navigation link in a square shape, while the Soft theme has it mildly rounded with some shadow shades&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To solve this, I made a super simple hook that validated the current theme and use it to style the component correspondingly as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// useMatchTheme&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GlobalContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../contexts/GlobalContext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ThemeMode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../themes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useMatchTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThemeMode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GlobalContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// NavLink.tsx&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;linkStyle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThemeUICSSObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;textReverse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// some more styles here&lt;/span&gt;

    &lt;span class="p"&gt;...(&lt;/span&gt;&lt;span class="nf"&gt;useMatchTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThemeMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Soft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isHomePage&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;boxShadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`inset 3em 3em 3em rgba(255, 255, 255, 0.5), 1em 1em 4em 3em &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;

    &lt;span class="p"&gt;...(&lt;/span&gt;&lt;span class="nf"&gt;useMatchTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ThemeMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Classic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isHomePage&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;boxShadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;inset 0 0 0 2em #000, 3em 3em 0 #000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.framer.com/docs/introduction/" rel="noopener noreferrer"&gt;Framer Motion&lt;/a&gt; was another animation library designed specifically for React and it did it job really well. It was a little tough to get a hang onto at the beginning since I had little experience with React and literally zero experience with any animation library. But once I got a hang of it, I absolutely loved it. The animations are super clean and realistic, I guess it was thanks to these so-called spring and bouncing physics (don't talk to me so deep into Math 😢). The API was simple to use as well as the good documentation with practical examples. (Staring at the old animations in my old porfolio, so fkn 💩). What made Framer Motion even more extreme, from my experience, were these &lt;a href="https://www.framer.com/docs/animation/#layout-animations" rel="noopener noreferrer"&gt;Layout animation&lt;/a&gt; which manipulated the animations on components as if they transitioned from one position to another, and &lt;a href="https://www.framer.com/docs/animate-presence/" rel="noopener noreferrer"&gt;AnimatePresence component&lt;/a&gt; which allows animations on components as they were removed from the React tree.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foahjt019x42aogmb72di.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foahjt019x42aogmb72di.gif" alt="Magic" width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the goal at the beginning was simply to apply a different tech stack to rebuild my portfolio and learn a thing or two out of it, I didn't want to deviate much from the existing core design, but in the end, I felt that there could have been a lot of improvements from the old version, so I think it's interesting to share the look of those differences:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Old&lt;/th&gt;
&lt;th&gt;New&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5setkk5r8vv0a827831.png" alt="Flat old" width="800" height="450"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyb0i052968qmo2oisypo.png" alt="Flat new" width="800" height="450"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4casxddwzs04npx47pw3.png" alt="Neumorphism old" width="800" height="450"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyex2z4g3cjhlku1wx5mv.png" alt="Soft new" width="800" height="450"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzo3od84unipobzchv55p.png" alt="Classic old" width="800" height="450"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn084yvdvii1ehccb0mdo.png" alt="Classic new" width="800" height="450"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaaexff0c1961udu1pf1.png" alt="Old config panel" width="800" height="450"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fitsuny7wcj9wj52kjnwu.png" alt="New config panel" width="800" height="450"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Aside from the improvements on how it looked. There were a couple of other improvements behind the scene, including accessibility, new config options (hide taskbar, reduce motion), hiding the config panel on unfocused, and an entire Blog section which pulls the article lists from my contributed blogging platforms using their public APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;I've got a confession to make. All of this blog was just to &lt;em&gt;brag&lt;/em&gt; about my new portfolio, to make a big fuss out of it as I invested a lot of my spare time doing it 😋 But I still hope it's  helpful and somehow serves as an inspiration for your new portfolio or your next one. Thank you for reading.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://web.archive.org/web/20220509014455/https://khang-nd.github.io/" rel="noopener noreferrer"&gt;Old version of my portfolio&lt;/a&gt; (&lt;a href="https://github.com/khang-nd/.info/tree/v1" rel="noopener noreferrer"&gt;source code&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://khangnd.info/" rel="noopener noreferrer"&gt;New version of my portfolio&lt;/a&gt; (&lt;a href="https://github.com/khang-nd/.info/" rel="noopener noreferrer"&gt;source code&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>showdev</category>
      <category>nextjs</category>
      <category>typescript</category>
      <category>career</category>
    </item>
    <item>
      <title>Understanding CSS Percentage</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Wed, 08 Sep 2021 08:28:31 +0000</pubDate>
      <link>https://dev.to/khangnd/understanding-css-percentage-44gd</link>
      <guid>https://dev.to/khangnd/understanding-css-percentage-44gd</guid>
      <description>&lt;p&gt;Have you ever failed to understand how the percentages work in CSS? Ever wondered why it's so messed up and has zero logic sometimes? Well, I do. That's why I'm writing this post to share my understanding through my researches and readings with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Percentage of what?
&lt;/h2&gt;

&lt;p&gt;As a percentage, obviously there should be a target taken as a reference source. Most answers to this are the &lt;strong&gt;parent block&lt;/strong&gt; of the element we assign the percentage. This is correct, but does not entirely cover all the cases. The most correct answer should be the &lt;strong&gt;containing block&lt;/strong&gt;, meaning the block that contains our element and it doesn't have to be the direct parent.&lt;/p&gt;

&lt;p&gt;Let's take a look at the below example:&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/khangnd/embed/powbjEL?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this example, I created 3 nested &lt;code&gt;div&lt;/code&gt;s, which are 3 squares with the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The outmost &lt;strong&gt;grandparent&lt;/strong&gt; div has a lightgray color with a size of &lt;strong&gt;4x4&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;parent&lt;/strong&gt; div has a darker gray with a size of &lt;strong&gt;2x2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;And the red &lt;strong&gt;child&lt;/strong&gt; div which I assigned the size of &lt;strong&gt;50%&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the percentage unit took the &lt;strong&gt;parent&lt;/strong&gt; as the source, the size of the &lt;strong&gt;child&lt;/strong&gt; should have been 1/2 of it, but no, the &lt;strong&gt;child&lt;/strong&gt; actually has the size equals to the &lt;strong&gt;parent&lt;/strong&gt; and 1/2 of the &lt;strong&gt;grandparent&lt;/strong&gt; as you can see. The reason is the &lt;strong&gt;grandparent&lt;/strong&gt; div is the true &lt;strong&gt;containing block&lt;/strong&gt; of the &lt;strong&gt;child&lt;/strong&gt; div, due to the fact that the &lt;strong&gt;child&lt;/strong&gt; has &lt;code&gt;position: absolute&lt;/code&gt;, corresponding to &lt;code&gt;position: relative&lt;/code&gt; I have set in the &lt;strong&gt;grandparent&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Therefore, to identify which is the actual &lt;strong&gt;containing block&lt;/strong&gt; of an element, it's entirely based on the &lt;code&gt;position&lt;/code&gt; property of the element itself. &lt;em&gt;You can read more on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;However, for certain properties, the reference source for the percentage unit is neither the &lt;em&gt;parent&lt;/em&gt; nor the &lt;em&gt;containing block&lt;/em&gt;, instead, it is itself - &lt;strong&gt;self element&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Percentage by property
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Pretty straightforward, as you have seen in the example above, when an element is assigned a percentage value to its &lt;code&gt;width&lt;/code&gt;, the &lt;code&gt;width&lt;/code&gt; of the &lt;strong&gt;containing block&lt;/strong&gt; is taken as the reference source. Likewise, &lt;code&gt;height&lt;/code&gt; of the element refers to the &lt;code&gt;height&lt;/code&gt; of the &lt;strong&gt;containing block&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;padding&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;For &lt;code&gt;padding&lt;/code&gt;, either vertical (&lt;code&gt;padding-top&lt;/code&gt;/&lt;code&gt;padding-bottom&lt;/code&gt;) or horizontal (&lt;code&gt;padding-left&lt;/code&gt;/&lt;code&gt;padding-right&lt;/code&gt;) refers to the &lt;code&gt;width&lt;/code&gt; of the &lt;strong&gt;containing block&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/khangnd/embed/YzQWWRG?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this example,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;parent&lt;/strong&gt; div has a size of &lt;strong&gt;6x4&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;child&lt;/strong&gt; div has a size of &lt;strong&gt;0&lt;/strong&gt;, but with &lt;code&gt;padding-top&lt;/code&gt; and &lt;code&gt;padding-left&lt;/code&gt; given &lt;strong&gt;50%&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is that the &lt;strong&gt;child&lt;/strong&gt; has a size equivalent to 1/2 &lt;code&gt;width&lt;/code&gt; of the &lt;strong&gt;parent&lt;/strong&gt;, which is a &lt;strong&gt;3x3&lt;/strong&gt; square.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;margin&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Similar to &lt;code&gt;padding&lt;/code&gt;, the percentage of &lt;code&gt;margin&lt;/code&gt; (both vertical and horizontal) refers to the &lt;code&gt;width&lt;/code&gt; of the &lt;strong&gt;containing block&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/khangnd/embed/MWoejWd?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this example,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;parent&lt;/strong&gt; div has a size of &lt;strong&gt;6x4&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;child&lt;/strong&gt; div with &lt;code&gt;margin-top&lt;/code&gt; and &lt;code&gt;margin-left&lt;/code&gt; given &lt;strong&gt;50%&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is that the &lt;strong&gt;child&lt;/strong&gt; is positioned &lt;strong&gt;3&lt;/strong&gt; units away from the top and left margins of the &lt;strong&gt;parent&lt;/strong&gt; (1/2 &lt;code&gt;width&lt;/code&gt; of the &lt;strong&gt;parent&lt;/strong&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;top&lt;/code&gt;/&lt;code&gt;bottom&lt;/code&gt;/&lt;code&gt;left&lt;/code&gt;/&lt;code&gt;right&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;For these properties (usually come with &lt;code&gt;position&lt;/code&gt;), the vertical ones (&lt;code&gt;top&lt;/code&gt;/&lt;code&gt;bottom&lt;/code&gt;) refer to the &lt;code&gt;height&lt;/code&gt; and the horizontal ones (&lt;code&gt;left&lt;/code&gt;/&lt;code&gt;right&lt;/code&gt;) refer to the &lt;code&gt;width&lt;/code&gt; of the &lt;strong&gt;containing block&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/khangnd/embed/MWoerzw?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this example,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;parent&lt;/strong&gt; div has a size of &lt;strong&gt;6x4&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;child&lt;/strong&gt; div has &lt;code&gt;position: absolute&lt;/code&gt; with &lt;code&gt;top&lt;/code&gt; and &lt;code&gt;left&lt;/code&gt; given &lt;strong&gt;50%&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is that the &lt;strong&gt;child&lt;/strong&gt; div is positioned &lt;strong&gt;2&lt;/strong&gt; units away from the &lt;strong&gt;parent&lt;/strong&gt;'s top edge (1/2 &lt;code&gt;height&lt;/code&gt; of the &lt;strong&gt;parent&lt;/strong&gt;), and positioned &lt;strong&gt;3&lt;/strong&gt; units away from the &lt;strong&gt;parent&lt;/strong&gt;'s left edge (1/2 &lt;code&gt;width&lt;/code&gt; of the &lt;strong&gt;parent&lt;/strong&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;transform: translate()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;An incredible property for animation/transition, it also supports percentage value. However, this one does not refer to its &lt;strong&gt;containing block&lt;/strong&gt;, but instead refers to &lt;strong&gt;itself&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/khangnd/embed/QWgEQvy?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this example,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;parent&lt;/strong&gt; div has a size of &lt;strong&gt;6x4&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;child&lt;/strong&gt; div has a size of &lt;strong&gt;2x1&lt;/strong&gt; with &lt;code&gt;transform: translate(50%, 50%)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is that the &lt;strong&gt;child&lt;/strong&gt; div is positioned &lt;strong&gt;0.5&lt;/strong&gt; unit away from the &lt;strong&gt;parent&lt;/strong&gt;'s top edge (1/2 &lt;code&gt;height&lt;/code&gt; of &lt;strong&gt;itself&lt;/strong&gt;), and positioned &lt;strong&gt;1&lt;/strong&gt; unit away from the &lt;strong&gt;parent&lt;/strong&gt;'s left edge (1/2 &lt;code&gt;width&lt;/code&gt; of &lt;strong&gt;itself&lt;/strong&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;background-size&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;background-size&lt;/code&gt; property brings the complexity of percentage unit to a new level 😄&lt;br&gt;
The percentage value of this property now refers to the &lt;strong&gt;background positioning area&lt;/strong&gt;, which I interpret as similar to the &lt;strong&gt;containing block&lt;/strong&gt;, but with an addition of these 3 factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Block with only content (&lt;code&gt;content-box&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Block with content and padding (&lt;code&gt;padding-box&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Block with content, padding and border (&lt;code&gt;border-box&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 3 factors are given by the &lt;code&gt;background-origin&lt;/code&gt; property. &lt;strong&gt;You can read more on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-origin" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/khangnd/embed/rNwLdMZ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this example,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;parent&lt;/strong&gt; div has a size of &lt;strong&gt;6x4&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;child&lt;/strong&gt; div has a size of &lt;strong&gt;3x2&lt;/strong&gt;, no &lt;code&gt;padding&lt;/code&gt;, no &lt;code&gt;border&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;I used a DEV logo (with the ratio of a square &lt;strong&gt;1:1&lt;/strong&gt;) as a &lt;code&gt;background-image&lt;/code&gt; for the &lt;strong&gt;child&lt;/strong&gt; div, with the &lt;code&gt;background-size&lt;/code&gt; property set to &lt;strong&gt;50% 50%&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is that the background image has been stretched to have a size of &lt;strong&gt;1.5x1&lt;/strong&gt;, corresponding to 1/2 size of the &lt;strong&gt;child&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;background-position&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Similar to &lt;code&gt;background-size&lt;/code&gt;, the percentage of the &lt;code&gt;background-position&lt;/code&gt; property also relies on the &lt;strong&gt;background positioning area&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/khangnd/embed/JjJKLaP?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this example, the same image and layout was used as the previous. As we changed the value of &lt;code&gt;background-position&lt;/code&gt;, some observations we can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Without any value (by default, the value is &lt;code&gt;0 0&lt;/code&gt;), the background image is positioned at the &lt;strong&gt;top left&lt;/strong&gt; corner.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;background-position: 0 50%&lt;/code&gt;, the background image is positioned &lt;strong&gt;left center&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;background-position: 50% 50%&lt;/code&gt;, the background image is positioned in the &lt;strong&gt;center&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;background-position: 100% 100%&lt;/code&gt;, the background image is positioned &lt;strong&gt;right bottom&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;code&gt;background-position: 0 50%&lt;/code&gt; is equivalent to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;background-position-x: 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;background-position-y: 50%&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Apparently, there are some calculations behind the percentage of this property, instead of just the distance between the image's top and left edges to the &lt;strong&gt;child&lt;/strong&gt;'s. Through some researching and testing, it appears that the &lt;code&gt;background-position&lt;/code&gt; property relies on the following calculation before yielding an actual value:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;offset X = (container's width - image's width) * background-position-x&lt;/p&gt;

&lt;p&gt;offset Y = (container's height - image's height) * background-position-y&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this case, with&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;container&lt;/em&gt; as the &lt;strong&gt;child&lt;/strong&gt; div&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;image's width/height&lt;/em&gt; is the resulting size of &lt;code&gt;background-size&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;font-size&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;For &lt;code&gt;font-size&lt;/code&gt;, the percentage value solely refers to its direct &lt;strong&gt;parent block&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/khangnd/embed/MWoeXMO?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this example, I use the same layout as the very first example, with the &lt;code&gt;font-size&lt;/code&gt; assigned as below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;13px&lt;/strong&gt; for &lt;strong&gt;grandparent&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;26px&lt;/strong&gt; for &lt;strong&gt;parent&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;50%&lt;/strong&gt; for &lt;strong&gt;child&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, we can clearly see that the &lt;code&gt;font-size&lt;/code&gt; of the &lt;strong&gt;child&lt;/strong&gt; is now equivalent to the &lt;strong&gt;grandparent&lt;/strong&gt; and is 1/2 of the &lt;strong&gt;parent&lt;/strong&gt;, ignoring the fact that the &lt;code&gt;position: relative&lt;/code&gt; is assigned to the &lt;strong&gt;grandparent&lt;/strong&gt;, not the &lt;strong&gt;parent&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;line-height&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;While might not be as popular, I also mention this property as it also supports percentage. The percentage value of &lt;code&gt;line-height&lt;/code&gt; relies on the &lt;code&gt;font-size&lt;/code&gt; of &lt;strong&gt;itself&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/khangnd/embed/oNwLMXR?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this example,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The paragraph has &lt;strong&gt;11&lt;/strong&gt; lines&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;font-size&lt;/code&gt; is set &lt;strong&gt;20px&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;line-height&lt;/code&gt; is set &lt;strong&gt;150%&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The actual &lt;code&gt;height&lt;/code&gt; of the whole block is &lt;strong&gt;~329px&lt;/strong&gt;,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;line-height&lt;/code&gt; in this case is: 20 * 150% = &lt;strong&gt;30px&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;height&lt;/code&gt; is then: 30 * 11 = &lt;strong&gt;330px&lt;/strong&gt;, approximate to the actual &lt;code&gt;height&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;Hope the article cleared up some of your understanding regarding the &lt;strong&gt;percentage value&lt;/strong&gt; in CSS instead of making things worse 😅&lt;/p&gt;

&lt;p&gt;I also tweeted a cheatsheet to summarize what is written so far, maybe it will come in handy to remember the meanings at first:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1433999937365164032-772" src="https://platform.twitter.com/embed/Tweet.html?id=1433999937365164032"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1433999937365164032-772');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1433999937365164032&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;And this is a collection of all the examples in the article: &lt;a href="https://codepen.io/collection/xKwgdW" rel="noopener noreferrer"&gt;https://codepen.io/collection/xKwgdW&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block" rel="noopener noreferrer"&gt;Containing block (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/percentage" rel="noopener noreferrer"&gt;Percentage (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-position#regarding_percentages" rel="noopener noreferrer"&gt;Background position's percentages (MDN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jameshfisher.com/2019/12/29/what-are-css-percentages/" rel="noopener noreferrer"&gt;What are CSS percentages? - Jim Fisher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wattenberger.com/blog/css-percents" rel="noopener noreferrer"&gt;What does 100% mean in CSS? - Amelia Wattenberger&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build a desktop app with Electron and Svelte</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Sat, 27 Mar 2021 17:08:49 +0000</pubDate>
      <link>https://dev.to/khangnd/build-a-desktop-app-with-electron-and-svelte-44dp</link>
      <guid>https://dev.to/khangnd/build-a-desktop-app-with-electron-and-svelte-44dp</guid>
      <description>&lt;p&gt;Hello everyone, welcome to another article in the series &lt;a href="https://dev.to/khangnd/series/11440"&gt;Let's build something!&lt;/a&gt;, a series dedicated to building, well, &lt;em&gt;something&lt;/em&gt; that involves several techs (techniques and technologies) mostly in JavaScript. In this article, I would like to share my first experience building a desktop app with &lt;a href="https://www.electronjs.org/" rel="noopener noreferrer"&gt;Electron&lt;/a&gt; (with the support from &lt;a href="https://www.electron.build/" rel="noopener noreferrer"&gt;Electron Builder&lt;/a&gt;) and &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt;. If you have never heard of any of them, simply click on the links to get to know the awesomeness. Now, let's just dive in.&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Setup
&lt;/h1&gt;

&lt;p&gt;The setup step is pretty simple and straightforward, we're going to start from a Svelte template as it already contains a lot of dependencies gathered in one boilerplate, then we integrate Electron into our app to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.1. Initiate a Svelte project
&lt;/h2&gt;

&lt;p&gt;If you have seen my previous post with the browser extension, you should be familiar with this step already. From the CLI, run &lt;code&gt;npx degit sveltejs/template electron-app-svelte&lt;/code&gt;. This will make a copy of the Svelte template to your machine with the name &lt;code&gt;electron-app-svelte&lt;/code&gt;, and a basic structure as seen in the repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0qk48rw1f4at61vo91mb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0qk48rw1f4at61vo91mb.png" width="241" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npm install&lt;/code&gt; to install all necessary dependencies in the template's &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.2. Integrate Electron
&lt;/h2&gt;

&lt;p&gt;Now we install the Electron package by running &lt;code&gt;npm install electron --save-dev&lt;/code&gt;. Once done, let's create our &lt;code&gt;index.js&lt;/code&gt; file at the root with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BrowserWindow&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;electron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mainWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BrowserWindow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;mainWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public/index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;mainWindow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webContents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;openDevTools&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the minimum content required for Electron to create a window and attempt to load our entry HTML file from the &lt;code&gt;public&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Next, let's make some changes in our &lt;code&gt;package.json&lt;/code&gt; to get it to work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rollup -c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rollup -c -w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"electron ."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, what I did was adding a new field &lt;code&gt;main&lt;/code&gt; and pointing it to the &lt;code&gt;index.js&lt;/code&gt; file we've just created, and also modifying the &lt;code&gt;start&lt;/code&gt; script to invoke Electron to load our compiled code in the app's window. Now, we just need to run &lt;code&gt;npm run dev&lt;/code&gt; to compile our Svelte source code, and subsequently, the start script will be called automatically (as predefined in our Rollup config). Let's try it to see if it already works:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkncxosyx3ewvg3zrmxnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkncxosyx3ewvg3zrmxnn.png" width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nope, our app appears blank with some errors in the Dev Console. Apparently, the relevant resources could not be loaded due to the incorrect path, this is due to the fact that we are not serving our resources through any kind of host. The workaround is fairly simple, let's open our &lt;code&gt;index.html&lt;/code&gt; file and remove all the &lt;strong&gt;/&lt;/strong&gt; at the start of the links, this should fix it. Try running it again:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7nzh9o5xqgd4so7ox9ua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7nzh9o5xqgd4so7ox9ua.png" width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome, we now have our Electron + Svelte app ready for development 🎉&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Development
&lt;/h1&gt;

&lt;p&gt;Once done with the setup, you can now continue the development just like you do with the web apps. The only difference is that our app is now run inside a window instead of a web browser (though they're still partially the same as the window is also using the V8 JavaScript engine under the hood to render web content).&lt;/p&gt;

&lt;p&gt;Simply run &lt;code&gt;npm run dev&lt;/code&gt; to start the development. Any changes in our source code are tracked and automatically re-compiled, we only need to press &lt;code&gt;Ctrl+R&lt;/code&gt; to refresh our window and reflect the changes.&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Build and distribute
&lt;/h1&gt;

&lt;p&gt;After finishing the development, the next thing we must care about is obviously how to distribute our desktop app, how different it might be from the usual distribution of a web app?&lt;/p&gt;

&lt;p&gt;For sure it is different, but not so hard at all. Let's see how this works:&lt;/p&gt;

&lt;p&gt;Literally, all we need is an &lt;code&gt;electron-builder&lt;/code&gt; package, so let's install it first with &lt;code&gt;npm install electron-builder --save-dev&lt;/code&gt;. Next, in our &lt;code&gt;package.json&lt;/code&gt;, add a new script as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;scripts:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dist"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run build &amp;amp;&amp;amp; electron-builder"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it. Our &lt;code&gt;dist&lt;/code&gt; script will produce a built version of our Svelte source code and trigger the &lt;code&gt;electron-builder&lt;/code&gt; command to produce a complete distributable desktop app. Let's try it now and see what it gives us, run &lt;code&gt;npm run dist&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhy002c4kh20cmqa8eded.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhy002c4kh20cmqa8eded.png" width="448" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Look, a &lt;code&gt;dist&lt;/code&gt; folder appears as a result, and inside of it, there are a lot of things, but we only need to concern ourselves with those 2 highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;.exe&lt;/code&gt; installer package (as Windows was my target OS), which is what we need to distribute our app to the users.&lt;/li&gt;
&lt;li&gt;Upon installing, the &lt;code&gt;.exe&lt;/code&gt; package will just extract exactly what is inside the &lt;code&gt;win-unpacked&lt;/code&gt; folder to the users' machine and the app can then be used. Therefore, alternatively, you may also compress this folder and distribute it to the users, which still delivers the same outcome.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;A complete repository you can find at: &lt;a href="https://github.com/khang-nd/electron-app-svelte" rel="noopener noreferrer"&gt;https://github.com/khang-nd/electron-app-svelte&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And that is all in this sharing article, thank you for reading and see you in the next one.&lt;/p&gt;

</description>
      <category>electron</category>
      <category>svelte</category>
      <category>javascript</category>
    </item>
    <item>
      <title>A simple RESTful service to display DEV.to stats</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Thu, 11 Mar 2021 23:41:58 +0000</pubDate>
      <link>https://dev.to/khangnd/dev-stats-a-restful-service-to-display-dev-to-stats-58ln</link>
      <guid>https://dev.to/khangnd/dev-stats-a-restful-service-to-display-dev-to-stats-58ln</guid>
      <description>&lt;p&gt;So, I'm back again with another pet project I have just finished and would like to share with everyone in this article:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-stats.vercel.app%2F%3Fbackground%3Defefef" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-stats.vercel.app%2F%3Fbackground%3Defefef" alt="Khang's DEV stats" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👆 This is it, an image generated dynamically from a RESTful service that allows me to easily display my statistics from DEV.to anywhere. Interesting? Read on to see some background and what I learned from making this, or if you want yours, head right to my repo for instructions on how to deploy one for your own:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/khang-nd" rel="noopener noreferrer"&gt;
        khang-nd
      &lt;/a&gt; / &lt;a href="https://github.com/khang-nd/DEV-stats" rel="noopener noreferrer"&gt;
        DEV-stats
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Display DEV.to stat card anywhere
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DEV Stats&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://dev.to/khangnd" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/fdc9aff38bff832756efba84c3cdd88c4510f60a017eb73488155b8005b57217/68747470733a2f2f6465762d73746174732d6b68616e676e642e6865726f6b756170702e636f6d3f6261636b67726f756e643d6639663966392631" alt="DEV-stats"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;👆 That's mine, want yours? It's easy! Follow these steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Star this repo (optional, but it makes me 🙂)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select one below to deploy this repo to your platform of choice&lt;/p&gt;
&lt;p&gt;&lt;a href="https://vercel.com/new/git/third-party?s=https://github.com/khang-nd/DEV-stats" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/20bea215d35a4e28f2c92ea5b657d006b087687486858a40de2922a4636301ab/68747470733a2f2f76657263656c2e636f6d2f627574746f6e" alt="Deploy with Vercel"&gt;&lt;/a&gt;
&lt;a href="https://www.heroku.com/deploy" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dc2056acd0e6ff421bfc2b129417f4f832d626c61d1c083221211d8503a429f7/68747470733a2f2f7777772e6865726f6b7563646e2e636f6d2f6465706c6f792f627574746f6e2e737667" alt="Deploy with Heroku"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate your &lt;a href="https://docs.forem.com/api/#section/Authentication/api_key" rel="nofollow noopener noreferrer"&gt;DEV API key&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add it as an environment variable named &lt;code&gt;API_KEY&lt;/code&gt; (for Heroku you need to configure this variable in the settings after deployed)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy and enjoy the result!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Options&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The service accepts these query parameters as inputs to customize the stat card:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;lang=en&lt;/code&gt; - localize the card. Add your language in &lt;a href="https://github.com/khang-nd/DEV-stats./src/i18n.json" rel="noopener noreferrer"&gt;i18n.json&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;background=fff&lt;/code&gt; - set the card's background color&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;text=000&lt;/code&gt; - set the card's text color&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chartColors=dc67ab,dc67ce,a367dc,6771dc,67b7dc,fff&lt;/code&gt; - set the chart colors, the last one is the labels' color&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Dark theme:&lt;/p&gt;
&lt;div class="highlight highlight-text-md notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-s"&gt;![&lt;/span&gt;&lt;span class="pl-s"&gt;]&lt;/span&gt;&lt;span class="pl-s"&gt;(&lt;/span&gt;&lt;span class="pl-corl"&gt;https://dev-stats-khangnd.herokuapp.com?background=19252f&amp;amp;text=fff&lt;/span&gt;&lt;span class="pl-s"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/66fcd0c1aef0b97259c922c264afe9b62c00f723a6e55a6c050b3583d3ea0f04/68747470733a2f2f6465762d73746174732d6b68616e676e642e6865726f6b756170702e636f6d3f6261636b67726f756e643d31393235326626746578743d6666662631"&gt;&lt;img src="https://camo.githubusercontent.com/66fcd0c1aef0b97259c922c264afe9b62c00f723a6e55a6c050b3583d3ea0f04/68747470733a2f2f6465762d73746174732d6b68616e676e642e6865726f6b756170702e636f6d3f6261636b67726f756e643d31393235326626746578743d6666662631" alt="DEV stats dark theme"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Customized chart colors:&lt;/p&gt;
&lt;div class="highlight highlight-text-md notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-s"&gt;![&lt;/span&gt;&lt;span class="pl-s"&gt;]&lt;/span&gt;&lt;span class="pl-s"&gt;(&lt;/span&gt;&lt;span class="pl-corl"&gt;https://dev-stats-khangnd.herokuapp.com?chartColors=3bf5c6,28d8ab,23bf97,1ca280,23886e,333&lt;/span&gt;&lt;span class="pl-s"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/fe851a2442805c6a64ae523a29c7e41b557b26cfecdc9a56d10881eb71769612/68747470733a2f2f6465762d73746174732d6b68616e676e642e6865726f6b756170702e636f6d3f30266368617274436f6c6f72733d3362663563362c3238643861622c3233626639372c3163613238302c3233383836652c3333332631"&gt;&lt;img src="https://camo.githubusercontent.com/fe851a2442805c6a64ae523a29c7e41b557b26cfecdc9a56d10881eb71769612/68747470733a2f2f6465762d73746174732d6b68616e676e642e6865726f6b756170702e636f6d3f30266368617274436f6c6f72733d3362663563362c3238643861622c3233626639372c3163613238302c3233383836652c3333332631" alt="DEV stats customized chart"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Contributing&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;I would appreciate it, feel free to open pull requests to contribute if you like it and…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/khang-nd/DEV-stats" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  The inspiration
&lt;/h1&gt;

&lt;p&gt;Yes, I believe some people should have realized it, this was inspired by the &lt;a href="https://github.com/anuraghazra/github-readme-stats/" rel="noopener noreferrer"&gt;amazing idea&lt;/a&gt; from &lt;a href="https://dev.to/anuraghazra"&gt;anuraghazra&lt;/a&gt; which allows us to dynamically generate our Github stats and display it easily anywhere as an SVG image. I find it interesting how he could manage it, so I went and checked out his source code, and attempted the same method for my DEV stats.&lt;/p&gt;

&lt;h1&gt;
  
  
  The techs
&lt;/h1&gt;

&lt;p&gt;As a developer with little experience in backend, I'm just simply amazed by the idea of using the RESTful API as such, to generate an SVG image that is capable of dynamically display your data from other sources.&lt;/p&gt;

&lt;p&gt;This is also a great start for me to get into the world of server-side JS, powered by &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt; and &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt;. So thanks to the love for JS, I was familiar with most of the things already, and after taking some hours to learn the basics about Node from a &lt;a href="https://youtu.be/TlB_eWDSMt4" rel="noopener noreferrer"&gt;1-hour course by Mosh&lt;/a&gt; (which I really recommend), and read through some docs and articles, I got things up and running without so much trouble.&lt;/p&gt;

&lt;p&gt;The data for my DEV stats are provided thanks to the &lt;a href="https://docs.forem.com/api/" rel="noopener noreferrer"&gt;DEV API&lt;/a&gt;. Though still in a beta stage, the API is already capable of providing a handful of information that, after some simple processing, can be displayed as statistics.&lt;/p&gt;

&lt;p&gt;The key factor for the success of this idea is how to represent the data dynamically, in the simplest way where it may be used anywhere, and that factor is by using SVG. I also went through some guides and articles about SVG to proceed and in the end, from making this, I got to learn the basic structure of an SVG document and some common elements. The pie chart, which shows the most commonly used tags in the articles, is a little tough for my current capability, so I went and picked a simpler workaround by using the awesome &lt;a href="https://quickchart.io/" rel="noopener noreferrer"&gt;QuickChart&lt;/a&gt; service offered by &lt;a href="https://dev.to/iwebst"&gt;Ian Webster&lt;/a&gt;. QuickChart is really convenient, be sure to check it out.&lt;/p&gt;

&lt;p&gt;Deploying to Vercel/Heroku was also not so bad of an experience for a beginner. I also created 2 buttons for convenient instant deployment in the repository. So in summary, check out the repo and I would welcome any contribution to improve or extend it. Thank you for reading, and see you in the next post.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>github</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Build an Android app with web techs</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Sat, 27 Feb 2021 09:20:40 +0000</pubDate>
      <link>https://dev.to/khangnd/build-an-android-app-with-web-techs-gji</link>
      <guid>https://dev.to/khangnd/build-an-android-app-with-web-techs-gji</guid>
      <description>&lt;p&gt;In this article, I'm going to share with you how I built an &lt;strong&gt;Android app with web techs using &lt;a href="https://developer.android.com/reference/android/webkit/WebView" rel="noopener noreferrer"&gt;WebView&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Yes, there are other alternative approaches, like &lt;a href="https://web.dev/progressive-web-apps/" rel="noopener noreferrer"&gt;PWA&lt;/a&gt; or &lt;a href="https://reactnative.dev/" rel="noopener noreferrer"&gt;React Native&lt;/a&gt; where web techs or the likes are involved to possibly achieve the same outcome, but due to the fact that a solution or approach may have the upperhand over the other depending on the context, it's always good to know more than just one solution. In this case, WebView provides us more interaction with our Android through the &lt;a href="https://developer.android.com/reference/android/webkit/JavascriptInterface" rel="noopener noreferrer"&gt;Javascript Interface&lt;/a&gt; and the learning path for this solution might be flatter if you already have some basic knowledge in Java/Kotlin and proficient in web development. Now let's get started:&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Basic setup
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1.1. The Android app
&lt;/h2&gt;

&lt;p&gt;Download and install &lt;a href="https://developer.android.com/studio" rel="noopener noreferrer"&gt;Android Studio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Start Android Studio and create a new project with an empty activity:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fns94v0kq2yeukvmhoocj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fns94v0kq2yeukvmhoocj.png" alt="android project template" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select &lt;em&gt;Java&lt;/em&gt; as the development language (or Kotlin if you are familiar with it)&lt;/p&gt;

&lt;p&gt;Once done, the main structure of our app is as follows:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1eamu00q7v8ygwposvus.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1eamu00q7v8ygwposvus.png" alt="android project structure" width="316" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lot of things, but let's just put our focus on the &lt;strong&gt;&lt;code&gt;MainActivity&lt;/code&gt;&lt;/strong&gt; class, where we write our code and the &lt;strong&gt;&lt;code&gt;activity_main.xml&lt;/code&gt;&lt;/strong&gt;, where we construct the app's layout.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;&lt;code&gt;activity_main.xml&lt;/code&gt;&lt;/strong&gt;, remove everything under the root and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;WebView&lt;/span&gt;
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/webapp"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a &lt;code&gt;WebView&lt;/code&gt; container which will display a web page in our app. The width and height are set to &lt;code&gt;match_parent&lt;/code&gt; which fills up the whole screen.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;&lt;code&gt;MainActivity&lt;/code&gt;&lt;/strong&gt; class, add the following lines to &lt;code&gt;onCreate&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;WebView&lt;/span&gt; &lt;span class="n"&gt;webView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WebView&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;findViewById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;R&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;webapp&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSettings&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;setJavaScriptEnabled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This searches for the WebView with the id &lt;code&gt;webapp&lt;/code&gt; from our layout that we defined and enables its JavaScript.&lt;/p&gt;

&lt;p&gt;Now create an &lt;code&gt;assets&lt;/code&gt; folder under the root &lt;code&gt;app&lt;/code&gt; as shown in the screenshots below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbt0zsfmqp6b05aa42pk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdbt0zsfmqp6b05aa42pk.png" alt="create assets" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;assets&lt;/code&gt; folder will contain the web resources we use in our app.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the web resources are composed of plain HTML, CSS and JS, you can add them directly here, if they have a more complex composition such as some frameworks and bundlers, you might need to put the &lt;strong&gt;built version&lt;/strong&gt; here instead, so the app will be of an optimal size.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1.2. The web page
&lt;/h2&gt;

&lt;p&gt;Now that we had our Android app ready to display a web page, we need a web page. I keep this guide simple and easy by just adding an HTML file directly in the &lt;code&gt;assets&lt;/code&gt; folder with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"IE=edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Good day!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;You are viewing this web page from Android!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the following line to your &lt;strong&gt;&lt;code&gt;MainActivity&lt;/code&gt;&lt;/strong&gt; class to load this page locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file:///android_asset/index.html"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are going to serve the web page on a host, you may then replace the URL to point to the target host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://mydomain.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now try running your app on a simulator or connected device, you should be able to see the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F802h6fwe701okeg4seac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F802h6fwe701okeg4seac.png" alt="Alt Text" width="405" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it, we have just finished creating our Android app which is mainly constructed with web contents.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Interacting with Android
&lt;/h1&gt;

&lt;p&gt;I did mention that using this WebView approach, our web page has the possibility to interact with our Android through the JavaScript Interface, correct? Let's see how it works:&lt;/p&gt;

&lt;p&gt;Under the same package as the &lt;code&gt;MainActivity&lt;/code&gt;, create a new class called &lt;code&gt;WebAppInterface&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.androidwebapp&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.os.Build&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.webkit.JavascriptInterface&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebAppInterface&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@JavascriptInterface&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getAndroidVersion&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RELEASE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our function to get the Android version is marked with the &lt;code&gt;@JavaScriptInterface&lt;/code&gt; annotation and will be available to our web page in a few more steps.&lt;/p&gt;

&lt;p&gt;In our &lt;code&gt;MainActivity&lt;/code&gt; class, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addJavascriptInterface&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebAppInterface&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Android"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exposes any function we defined in the &lt;code&gt;WebAppInterface&lt;/code&gt; class to the web page's JavaScript under the "Android" alias.&lt;/p&gt;

&lt;p&gt;And finally, in our HTML page, add the following script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your device is using Android &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;Android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAndroidVersion&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try running again and you should be able to see the Android version of your simulator or device.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A thing to note about this technique is that, due to the differences between Java/Kotlin and JavaScript, only &lt;strong&gt;primitive&lt;/strong&gt; data types may be shared through the interface. For instance, exposing the function that returns a Java array as follows will resolve to &lt;code&gt;undefined&lt;/code&gt; in JavaScript:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@JavascriptInterface&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;getJavaArray&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A complete repository you can find at: &lt;a href="https://github.com/khang-nd/android-web" rel="noopener noreferrer"&gt;https://github.com/khang-nd/android-web&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this concludes my sharing article, thank you for reading, see you in the next one.&lt;/p&gt;

</description>
      <category>android</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>java</category>
    </item>
    <item>
      <title>Build a browser extension with Svelte</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Sun, 07 Feb 2021 12:11:52 +0000</pubDate>
      <link>https://dev.to/khangnd/build-a-browser-extension-with-svelte-3135</link>
      <guid>https://dev.to/khangnd/build-a-browser-extension-with-svelte-3135</guid>
      <description>&lt;p&gt;I have been learning &lt;em&gt;Svelte&lt;/em&gt;. I find it extremely easy to work with. It is lightweight and fast, a suitable option for building small-scaled apps and websites. I've also been learning about how a &lt;em&gt;browser extension&lt;/em&gt; is made. Then I find it a perfect playmate for Svelte, and the learning paths crossed. So today I would like to share my process of &lt;strong&gt;building a complete cross-browser extension with Svelte&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before reading on, make sure that you're familiar with a browser extension and how to construct one with pure HTML/CSS/JS, and how to work with a front-end library/framework in a NodeJS environment. Otherwise, here are some resources to get you started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/docs/extensions/mv2/getstarted/" rel="noopener noreferrer"&gt;Chrome Extension - Getting started&lt;/a&gt; (Manifest v2)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://svelte.dev/blog/the-easiest-way-to-get-started" rel="noopener noreferrer"&gt;Svelte - Getting started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Build_a_cross_browser_extension" rel="noopener noreferrer"&gt;Build a cross-browser extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://extensionizr.com/" rel="noopener noreferrer"&gt;Extensionizr&lt;/a&gt; - Chrome extension structure generator&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  1. Setup
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1.1. Initiate a Svelte project
&lt;/h2&gt;

&lt;p&gt;From the CLI, run &lt;code&gt;npx degit sveltejs/template my-extension&lt;/code&gt;. This will make a copy of the &lt;a href="https://github.com/sveltejs/template" rel="noopener noreferrer"&gt;Svelte template&lt;/a&gt; to your machine with the name &lt;code&gt;my-extension&lt;/code&gt;, and a basic structure as seen in the repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0qk48rw1f4at61vo91mb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0qk48rw1f4at61vo91mb.png" alt="Alt Text" width="241" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1.2. Install dependencies
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;npm install&lt;/code&gt; to install all necessary dependencies in the template's &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To build a cross-browser extension, the &lt;a href="https://github.com/mozilla/webextension-polyfill/" rel="noopener noreferrer"&gt;webextension-polyfill&lt;/a&gt; is required. Therefore, run &lt;code&gt;npm install --save-dev webextension-polyfill&lt;/code&gt; to install it.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Prepare the Manifest
&lt;/h1&gt;

&lt;p&gt;Now that we have things ready. Let's create the heart of a browser extension, the &lt;strong&gt;&lt;code&gt;manifest.json&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;manifest.json&lt;/code&gt; and place it inside the &lt;code&gt;public&lt;/code&gt; folder. A bare minimum content of a manifest is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"manifest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My Extension"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And depending on the purpose and functionality of the extension, other fields may be specified. For a complete list of supported fields, refer to &lt;a href="https://developer.chrome.com/docs/extensions/mv2/manifest/" rel="noopener noreferrer"&gt;Chrome's manifest file format&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Add functionalities
&lt;/h1&gt;

&lt;p&gt;Silly things that our extension will be capable of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Say hello when somebody installs our extension (&lt;a href="https://developer.chrome.com/docs/extensions/mv2/background_pages/" rel="noopener noreferrer"&gt;background page&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;"Hack" the website's background (&lt;a href="https://developer.chrome.com/docs/extensions/mv2/content_scripts/" rel="noopener noreferrer"&gt;content script&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Configure the desired background (&lt;a href="https://developer.chrome.com/docs/extensions/reference/browserAction/#popup" rel="noopener noreferrer"&gt;popup page&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's dig through.&lt;/p&gt;

&lt;h2&gt;
  
  
  3.1. Background page
&lt;/h2&gt;

&lt;p&gt;The background page will be loaded whenever the extension is active, and react to the events we set. In our case, the extension reacts "say hello" to the event "somebody installs the extension".&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;background.js&lt;/code&gt; inside the &lt;code&gt;src&lt;/code&gt; folder and add the following script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webextension-polyfill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onInstalled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;reason&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;install&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;More about the &lt;code&gt;runtime.onInstalled&lt;/code&gt; event: &lt;a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onInstalled" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3.2. Content script
&lt;/h2&gt;

&lt;p&gt;The content script has direct access to the current web page. Therefore, it is a perfect solution to "hack the website's background".&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;injection.js&lt;/code&gt; inside the &lt;code&gt;src&lt;/code&gt; folder and add the following script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webextension-polyfill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`background: url(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;More about the &lt;code&gt;storage.local&lt;/code&gt; API: &lt;a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/local" rel="noopener noreferrer"&gt;MDN&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3.3. Popup page
&lt;/h2&gt;

&lt;p&gt;The popup page is literally the front end of the extension, where users can interact with our extension. In our case, we give users the possibility to "configure the desired background". And this is where Svelte comes into the play.&lt;/p&gt;

&lt;p&gt;Remove &lt;code&gt;props: { name: 'world' }&lt;/code&gt; from &lt;code&gt;main.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Replace content in &lt;code&gt;App.svelte&lt;/code&gt; with the following script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webextension-polyfill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://images.unsplash.com/photo-1586074299757-dc655f18518c?fit=crop&amp;amp;w=1268&amp;amp;q=80&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
  Image URL: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;bind:value=&lt;/span&gt;&lt;span class="s"&gt;{image}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{change}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Change&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3.4. Add to the Manifest
&lt;/h2&gt;

&lt;p&gt;Now modify the &lt;code&gt;manifest.json&lt;/code&gt; we created earlier to include these functionalities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"storage"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"build/background.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"persistent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"browser_action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_popup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.html"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content_scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"https://*/*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"js"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"build/injection.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  4. Config Rollup and build
&lt;/h1&gt;

&lt;p&gt;The final step involves some configuration for Rollup to generate the &lt;code&gt;background.js&lt;/code&gt; and &lt;code&gt;injection.js&lt;/code&gt; to the &lt;code&gt;build&lt;/code&gt; folder, so that the Manifest could recognize.&lt;/p&gt;

&lt;p&gt;By default, the &lt;code&gt;rollup.config.js&lt;/code&gt; file only outputs the &lt;code&gt;main.js&lt;/code&gt; entry to the &lt;code&gt;build&lt;/code&gt; folder under the alias &lt;code&gt;bundle.js&lt;/code&gt;. To include the other scripts, modify the config as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/main.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/background.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;iife&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public/build/background.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;commonjs&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;clearScreen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/injection.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;iife&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public/build/injection.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;commonjs&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;clearScreen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will output multiple entries, including the &lt;code&gt;background.js&lt;/code&gt; and &lt;code&gt;injection.js&lt;/code&gt; to the &lt;code&gt;build&lt;/code&gt; folder, and resolve any dependencies in our scripts.&lt;/p&gt;

&lt;p&gt;And finally, run &lt;code&gt;npm run build&lt;/code&gt; to compile our project and everything will be available in the &lt;code&gt;public&lt;/code&gt; folder. We may then load our extension in Chrome and see the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Funardrhpmbqcq78zoevm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Funardrhpmbqcq78zoevm.png" alt="Alt Text" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A complete repo you can find at: &lt;a href="https://github.com/khang-nd/browser-extension-svelte" rel="noopener noreferrer"&gt;https://github.com/khang-nd/browser-extension-svelte&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading, and see you in the next post.&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>browserextension</category>
      <category>chromeextension</category>
    </item>
    <item>
      <title>Make a website with a single HTML file</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Sun, 31 Jan 2021 16:46:20 +0000</pubDate>
      <link>https://dev.to/khangnd/make-a-website-with-a-single-html-file-5geg</link>
      <guid>https://dev.to/khangnd/make-a-website-with-a-single-html-file-5geg</guid>
      <description>&lt;p&gt;There is a clever way to create a whole website with just &lt;em&gt;a single&lt;/em&gt; HTML, some CSS, and &lt;em&gt;no&lt;/em&gt; JS. Did you know?&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1
&lt;/h1&gt;

&lt;p&gt;Create an empty HTML5 website:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Document&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 2
&lt;/h1&gt;

&lt;p&gt;Add some &lt;code&gt;anchors&lt;/code&gt; and &lt;code&gt;sections&lt;/code&gt; with &lt;code&gt;ids&lt;/code&gt; for the pages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;...
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#home"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#blog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Blog&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#about"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"home"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This is the homepage!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"blog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;My Blog&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"about"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;About Me&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 3
&lt;/h1&gt;

&lt;p&gt;Add some CSS to toggle the pages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
...
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="nd"&gt;:target&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 4
&lt;/h1&gt;

&lt;p&gt;There is no step 4. All that left is to customize it.&lt;/p&gt;




&lt;p&gt;And that's it. You have a website ready in just a few steps, no JS used, no complex framework, just an HTML file, and a text editor. The magic behind this is by utilizing the anchor links and the &lt;code&gt;:target&lt;/code&gt; pseudo selector to switch between the pages without the help of any JS.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;:target&lt;/code&gt; pseudo selector matches when the hash in the URL and the id of an element are the same.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Reference: &lt;a href="https://css-tricks.com/a-whole-website-in-a-single-html-file/" rel="noopener noreferrer"&gt;CSS-Tricks&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>css</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>10 Retro CSS frameworks to relive your childhood</title>
      <dc:creator>Khang</dc:creator>
      <pubDate>Sun, 24 Jan 2021 16:44:07 +0000</pubDate>
      <link>https://dev.to/khangnd/10-retro-css-frameworks-to-relive-your-childhood-nph</link>
      <guid>https://dev.to/khangnd/10-retro-css-frameworks-to-relive-your-childhood-nph</guid>
      <description>&lt;p&gt;Prank your friends or colleagues, build a retro-looking portfolio for yourself, entertain visitors to your websites with old-school themes, or most importantly, let your creativity run wild, have fun with coding and relive your childhood with these amazing Retro CSS frameworks.&lt;/p&gt;

&lt;h1&gt;
  
  
  NES.css (&lt;a href="https://nostalgic-css.github.io/NES.css/" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;)
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nostalgic-css" rel="noopener noreferrer"&gt;
        nostalgic-css
      &lt;/a&gt; / &lt;a href="https://github.com/nostalgic-css/NES.css" rel="noopener noreferrer"&gt;
        NES.css
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      NES-style CSS Framework | ファミコン風CSSフレームワーク
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
  &lt;a href="https://nostalgic-css.github.io/NES.css/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F5305599%2F49061716-da649680-f254-11e8-9a89-d95a7407ec6a.png" alt="NES.css: NES-style  CSS framework" width="600" height="315"&gt;&lt;/a&gt;
&lt;p&gt;&lt;a href="https://github.com/nostalgic-css/NES.css.github/README-jp.md" rel="noopener noreferrer"&gt;日本語&lt;/a&gt; / &lt;a href="https://github.com/nostalgic-css/NES.css.github/README-zh-CN.md" rel="noopener noreferrer"&gt;简体中文&lt;/a&gt; / &lt;a href="https://github.com/nostalgic-css/NES.css.github/README-es.md" rel="noopener noreferrer"&gt;Español&lt;/a&gt; / &lt;a href="https://github.com/nostalgic-css/NES.css.github/README-pt-BR.md" rel="noopener noreferrer"&gt;Português&lt;/a&gt; / &lt;a href="https://github.com/nostalgic-css/NES.css.github/README-ru.md" rel="noopener noreferrer"&gt;Русский&lt;/a&gt; / &lt;a href="https://github.com/nostalgic-css/NES.css.github/README-fr.md" rel="noopener noreferrer"&gt;Français&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;NES.css is a &lt;strong&gt;NES-style(8bit-like)&lt;/strong&gt; CSS Framework.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gitter.im/nostalgic-css/Lobby" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/98471f63ffa684ad63c29388f353d436aa65cd4ed0c6502757c725e2f0afe312/68747470733a2f2f696d672e736869656c64732e696f2f6769747465722f726f6f6d2f6e6f7374616c6769632d6373732f4c6f6262792e737667" alt="Gitter"&gt;&lt;/a&gt; &lt;a href="http://commitizen.github.io/cz-cli/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1d01d79de532fa2a8b9d3e1c29e2b5d6f700b6d36f108c8416faca472cb35b6f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f6d6d6974697a656e2d667269656e646c792d627269676874677265656e2e737667" alt="Commitizen friendly"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Styles&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;NES.css is available via either npm (preferred), Yarn, or a CDN.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;via package manager&lt;/h4&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install nes.css
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; or&lt;/span&gt;
yarn add nes.css&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Our &lt;code&gt;package.json&lt;/code&gt; contains some additional metadata under the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sass&lt;/code&gt; - path to our main Sass source file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;style&lt;/code&gt; - path to our non-minified CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h5 class="heading-element"&gt;AltCSS(sass, scss...)&lt;/h5&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-css-scss notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;//&lt;/span&gt; style.scss&lt;/span&gt;
&lt;span class="pl-k"&gt;&lt;a class="mentioned-user" href="https://dev.to/import"&gt;@import&lt;/a&gt;&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;./node_modules/nes.css/css/nes.css&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h5 class="heading-element"&gt;JavaScript&lt;/h5&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;// script.js&lt;/span&gt;
&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s"&gt;"nes.css/css/nes.min.css"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;You need to install css-loader.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h5 class="heading-element"&gt;HTML&lt;/h5&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;html&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;rel&lt;/span&gt;="&lt;span class="pl-s"&gt;stylesheet&lt;/span&gt;" &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;./node_modules/nes.css/css/nes.min.css&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;body&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;body&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;html&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;via CDN&lt;/h4&gt;

&lt;/div&gt;
&lt;p&gt;Import the CSS via a &lt;code&gt;&amp;lt;link /&amp;gt;&lt;/code&gt; element:&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&amp;lt;!-- minify --&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;https://unpkg.com/nes.css@2.3.0/css/nes.min.css&lt;/span&gt;" &lt;span class="pl-c1"&gt;rel&lt;/span&gt;="&lt;span class="pl-s"&gt;stylesheet&lt;/span&gt;" &lt;span class="pl-kos"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="pl-c"&gt;&amp;lt;!-- latest --&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nostalgic-css/NES.css" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  98.css (&lt;a href="https://jdan.github.io/98.css/" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;)
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jdan" rel="noopener noreferrer"&gt;
        jdan
      &lt;/a&gt; / &lt;a href="https://github.com/jdan/98.css" rel="noopener noreferrer"&gt;
        98.css
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A design system for building faithful recreations of old UIs
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;98.css&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="http://npm.im/98.css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0dcf1dc5f2e67d00459f2f5e4fbfe73c2406f62bdb8f290f8e5fe429ebb97ecc/68747470733a2f2f39386261646765732e6e6f772e73682f6170692f76657273696f6e" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://unpkg.com/98.css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a46bcb8ab3fab121ac4c94e02529dc80ca870910b1fb27ed2f9d056dd165367a/68747470733a2f2f39386261646765732e6e6f772e73682f6170692f73697a65" alt="gzip size"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A design system for building faithful recreations of old UIs.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/jdan/98.css/blob/main/docs/window.png?raw=true"&gt;&lt;img alt="a screenshot of a window with the title 'My First VB4 Program' and two buttons OK and Cancel, styled like a Windows 98 dialog" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fjdan%2F98.css%2Fraw%2Fmain%2Fdocs%2Fwindow.png%3Fraw%3Dtrue" height="133"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer" href="https://github.com/jdan/98.css/blob/main/docs/zoom.png?raw=true?raw=true"&gt;&lt;img alt="a magnified view showing pixel-perfect borders on a scrollbar and button element" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fjdan%2F98.css%2Fraw%2Fmain%2Fdocs%2Fzoom.png%3Fraw%3Dtrue%3Fraw%3Dtrue" height="133"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;98.css is a CSS file that takes semantic HTML and makes it look pretty. It does not ship with any JavaScript, so it is compatible with your frontend framework of choice.&lt;/p&gt;
&lt;p&gt;Be sure to check out &lt;a href="https://botoxparty.github.io/XP.css/" rel="nofollow noopener noreferrer"&gt;XP.css&lt;/a&gt; and &lt;a href="https://khang-nd.github.io/7.css/" rel="nofollow noopener noreferrer"&gt;7.css&lt;/a&gt; as well.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation / Usage&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The easiest way to use 98.css is to import it from &lt;a href="https://unpkg.com/" rel="nofollow noopener noreferrer"&gt;unpkg&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;&amp;lt;!DOCTYPE html&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;html&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;title&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;98.css example&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;title&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;meta&lt;/span&gt; &lt;span class="pl-c1"&gt;charset&lt;/span&gt;="&lt;span class="pl-s"&gt;UTF-8&lt;/span&gt;" &lt;span class="pl-kos"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;rel&lt;/span&gt;="&lt;span class="pl-s"&gt;stylesheet&lt;/span&gt;" &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;https://unpkg.com/98.css&lt;/span&gt;" &lt;span class="pl-kos"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;body&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;window&lt;/span&gt;" &lt;span class="pl-c1"&gt;style&lt;/span&gt;="&lt;span class="pl-s"&gt;margin: 32px; width: 250px&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;title-bar&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;title-bar-text&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
        My First VB4 Program
      &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jdan/98.css" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  BOOTSTRA.386 (&lt;a href="https://kristopolous.github.io/BOOTSTRA.386/" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;)
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kristopolous" rel="noopener noreferrer"&gt;
        kristopolous
      &lt;/a&gt; / &lt;a href="https://github.com/kristopolous/BOOTSTRA.386" rel="noopener noreferrer"&gt;
        BOOTSTRA.386
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A vintage 1980s DOS inspired Twitter Bootstrap theme
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;Bootstrap/386 is a Twitter bootstrap v2/3/4/5(in progress) theme to make webpages look like they are from the gentler, less distracting time of the 1980s.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;&lt;a href="http://kristopolous.github.io/BOOTSTRA.386/v2.3.1/" rel="nofollow noopener noreferrer"&gt;See A Demo By Clicking Here&lt;/a&gt;&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Download for your favorite bootstrap version with all the necessary JS and CSS to get started right away:&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;BOOTSTRA/386 ][ (2013) &lt;a href="http://kristopolous.github.io/BOOTSTRA.386/" rel="nofollow noopener noreferrer"&gt;demo&lt;/a&gt; &lt;a href="https://github.com/kristopolous/BOOTSTRA.386/blob/master/bootstra.386-latest-v2.zip?raw=true" rel="noopener noreferrer"&gt;144KB&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;BOOTSTRA/386 &lt;i&gt;iii&lt;/i&gt; (2015) &lt;a href="https://github.com/kristopolous/BOOTSTRA.386/blob/master/bootstra.386-latest-v3.zip?raw=true" rel="noopener noreferrer"&gt;423KB&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;BOOTSTRA/386 4 (2020) - &lt;a href="http://kristopolous.github.io/BOOTSTRA.386/v4.4.1/" rel="nofollow noopener noreferrer"&gt;demo&lt;/a&gt; &lt;a href="https://github.com/kristopolous/BOOTSTRA.386/issues/85" rel="noopener noreferrer"&gt;remaining issues&lt;/a&gt; - &lt;a href="https://github.com/kristopolous/BOOTSTRA.386/blob/master/bootstra.386-latest-v4.zip?raw=true" rel="noopener noreferrer"&gt;current build&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ブートストラップ/386 5.0 (2023) - In progress&lt;/li&gt;
&lt;/ul&gt;

  
    

    &lt;span class="m-1"&gt;bootstrap.mp4&lt;/span&gt;
    
  

  

  


&lt;p&gt;&lt;a href="http://i.imgur.com/chWpJfb.jpg" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/818c4d7a40872bf9dde639cb7bce36c514015f50fb224d7088f2744a1d5bf82c/687474703a2f2f692e696d6775722e636f6d2f636857704a66626c2e6a7067"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;     ____  ____  ____  _____________________  ___    ____        __   _____ ____  _____
    / __ )/ __ \/ __ \/_  __/ ___/_  __/ __ \/   |  / __ \     _/_/  |__  /( __ )/ ___/
   / __  / / / / / / / / /  \__ \ / / / /_/ / /| | / /_/ /   _/_/     /_ &amp;lt;/ __  / __ \ 
  / /_/ / /_/ / /_/ / / /  ___/ // / / _,&lt;/pre&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kristopolous/BOOTSTRA.386" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Geo (&lt;a href="http://divshot.github.com/geo-bootstrap/" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;)
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/divshot" rel="noopener noreferrer"&gt;
        divshot
      &lt;/a&gt; / &lt;a href="https://github.com/divshot/geo-bootstrap" rel="noopener noreferrer"&gt;
        geo-bootstrap
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A timeless Twitter Bootstrap theme built for the modern web.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Geo&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Geo&lt;/strong&gt; is a timeless &lt;a href="http://twitter.github.com/bootstrap" rel="noopener noreferrer"&gt;Twitter Bootstrap&lt;/a&gt; theme built for the modern web.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Download &lt;code&gt;bootstrap.css&lt;/code&gt; or &lt;code&gt;bootstrap.min.css&lt;/code&gt; from &lt;code&gt;/swatch&lt;/code&gt;. Replace the default Bootstrap stylesheet with one of these files.&lt;/p&gt;
&lt;p&gt;To use the image backgrounds download the graphics inside &lt;code&gt;/img&lt;/code&gt;. Graphics used on our test page can be found inside &lt;code&gt;/img/test&lt;/code&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Customization&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Geo was built with &lt;a href="https://github.com/thomaspark/bootswatch/tree/gh-pages/swatchmaker" rel="noopener noreferrer"&gt;Bootswatch Swatchmaker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To customize Geo edit &lt;code&gt;/swatch/variables.less&lt;/code&gt; and &lt;code&gt;/swatch/bootswatch.less&lt;/code&gt;. Refer to the Swatchmaker &lt;a href="https://github.com/thomaspark/bootswatch/tree/gh-pages/swatchmaker" rel="noopener noreferrer"&gt;README&lt;/a&gt; for instructions to regenerate the Bootstrap stylesheet.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;License&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Copyright (c) 2013 Divshot&lt;/p&gt;
&lt;p&gt;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/divshot/geo-bootstrap" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  XP.css (&lt;a href="https://botoxparty.github.io/XP.css/" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;)
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/botoxparty" rel="noopener noreferrer"&gt;
        botoxparty
      &lt;/a&gt; / &lt;a href="https://github.com/botoxparty/XP.css" rel="noopener noreferrer"&gt;
        XP.css
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A CSS framework for building faithful recreations of operating system GUIs.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;XP.css&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="http://npm.im/xp.css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1d3df98a20b46d0150f7b494c573545e55f67abaad03a8491e94dc867074f87d/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f78702e637373" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://unpkg.com/xp.css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f68439fff846d62e9a45b3eb0afed3a322cc0ad9806edd33fad41f037a78eb75/68747470733a2f2f696d672e736869656c64732e696f2f62756e646c6570686f6269612f6d696e7a69702f78702e637373" alt="gzip size"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A design system for building faithful recreations of old UIs.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/botoxparty/XP.css/blob/main/docs/window.png?raw=true"&gt;&lt;img alt="a screenshot of a window with the title 'My First Program' and two buttons OK and Cancel, styled like a Windows XP dialog" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fbotoxparty%2FXP.css%2Fraw%2Fmain%2Fdocs%2Fwindow.png%3Fraw%3Dtrue" height="133"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/jdan/98.css/blob/main/docs/window.png?raw=true"&gt;&lt;img alt="a screenshot of a window with the title 'My First Program' and two buttons OK and Cancel, styled like a Windows 98 dialog" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fjdan%2F98.css%2Fraw%2Fmain%2Fdocs%2Fwindow.png%3Fraw%3Dtrue" height="133"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;XP.css is an extension of 98.css. A CSS file that takes semantic HTML and makes it look pretty. It does not ship with any JavaScript, so it is compatible with your frontend framework of choice.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation / Usage&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The easiest way to use XP.css is to import it from &lt;a href="https://unpkg.com/" rel="nofollow noopener noreferrer"&gt;unpkg&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;&amp;lt;!DOCTYPE html&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;html&lt;/span&gt; &lt;span class="pl-c1"&gt;lang&lt;/span&gt;="&lt;span class="pl-s"&gt;en&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;title&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;XP.css example&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;title&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;meta&lt;/span&gt; &lt;span class="pl-c1"&gt;charset&lt;/span&gt;="&lt;span class="pl-s"&gt;UTF-8&lt;/span&gt;" &lt;span class="pl-kos"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="pl-c"&gt;&amp;lt;!-- Windows XP Theme (include only one theme at a time) --&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;rel&lt;/span&gt;="&lt;span class="pl-s"&gt;stylesheet&lt;/span&gt;" &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;https://unpkg.com/xp.css&lt;/span&gt;" &lt;span class="pl-kos"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="pl-c"&gt;&amp;lt;!-- Windows 98 Theme (include only one theme at a time) --&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;rel&lt;/span&gt;="&lt;span class="pl-s"&gt;stylesheet&lt;/span&gt;" &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;https://unpkg.com/xp.css@0.2.3/dist/98.css&lt;/span&gt;" &lt;span class="pl-kos"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;body&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;window&lt;/span&gt;" &lt;span class="pl-c1"&gt;style&lt;/span&gt;="&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/botoxparty/XP.css" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  PSone.css (&lt;a href="https://micah5.github.io/PSone.css/" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;)
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/micah5" rel="noopener noreferrer"&gt;
        micah5
      &lt;/a&gt; / &lt;a href="https://github.com/micah5/PSone.css" rel="noopener noreferrer"&gt;
        PSone.css
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🎮 PS1 style CSS Framework, inspired by NES.css
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;PSone.css&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/539f7cf16f6cd5b7028be6497e285a43eec2084f0eb6e420e209fcf5d7e43f8c/68747470733a2f2f692e696d6775722e636f6d2f496374583944322e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/539f7cf16f6cd5b7028be6497e285a43eec2084f0eb6e420e209fcf5d7e43f8c/68747470733a2f2f692e696d6775722e636f6d2f496374583944322e706e67" alt="description" title="description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Please feel free to submit a pull request, no matter how small. I love getting them.&lt;/p&gt;
&lt;p&gt;At the moment there's just a CSS file that you can link to:&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;rel&lt;/span&gt;="&lt;span class="pl-s"&gt;stylesheet&lt;/span&gt;" &lt;span class="pl-c1"&gt;type&lt;/span&gt;="&lt;span class="pl-s"&gt;text/css&lt;/span&gt;" &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;https://cdn.jsdelivr.net/gh/98mprice/PSone.css@master/PSone.min.css&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;I hope to add some JS eventually to help with progressbars etc.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Reference&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Container&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;From FF7&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;container&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;title&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;Default&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;label&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;p&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;Kick! Punch! It's all in the mind.&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;p&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;container dark&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;title&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;dark&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;label&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;p&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;You see, the island is the site of a secret nuclear
   weapons disposal facility.&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;p&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;container light&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;title&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/micah5/PSone.css" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  RPGUI (&lt;a href="https://RonenNess.github.io/RPGUI/" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;)
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/RonenNess" rel="noopener noreferrer"&gt;
        RonenNess
      &lt;/a&gt; / &lt;a href="https://github.com/RonenNess/RPGUI" rel="noopener noreferrer"&gt;
        RPGUI
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Lightweight framework for old-school RPG GUI in web!
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/RonenNess/RPGUIWe_stand_with_Israel.jpg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FRonenNess%2FRPGUIWe_stand_with_Israel.jpg" alt="Israel" title="Israel"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Israel is under a brutal attack from Gaza on multiple fronts
Hundreds of innocent civilians were murdered and kidnapped from their own homes. Hundreds are still missing.&lt;/p&gt;
&lt;p&gt;I won't show any gore and horrific photos here. But here's &lt;a href="https://www.youtube.com/watch?v=NCUsb621ELE" rel="nofollow noopener noreferrer"&gt;some more information&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Please support Israel in these dark times.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;RPGUI&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Lightweight framework for old-school RPG GUI in web!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ronenness.github.io/RPGUI/" rel="nofollow noopener noreferrer"&gt;Live examples here&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of Contents&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/RonenNess/RPGUI#what-is-it" rel="noopener noreferrer"&gt;What is it?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RonenNess/RPGUI#key-features" rel="noopener noreferrer"&gt;Key Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RonenNess/RPGUI#how-to-use" rel="noopener noreferrer"&gt;How to use&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RonenNess/RPGUI#angular-users" rel="noopener noreferrer"&gt;Angular users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RonenNess/RPGUI#how-to-tweak" rel="noopener noreferrer"&gt;How to tweak&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RonenNess/RPGUI#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RonenNess/RPGUI#contact-me" rel="noopener noreferrer"&gt;Contact Me&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is it?&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;This framework provide out-of-the-box GUI for web games with old-school RPG style.
Once including this lib all you need to do is start adding regular html elements with RPGUI classes, and RPGUI will do all the rest!&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/RonenNess/RPGUI/master/screenshot.jpg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FRonenNess%2FRPGUI%2Fmaster%2Fscreenshot.jpg" alt="alt tag"&gt;&lt;/a&gt;
(Image is slightly outdated.)&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Key Features&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;The following are the key features of RPGUI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using RPGUI don't require coding at all! Just using css classes.&lt;/li&gt;
&lt;li&gt;A complete and whole CSS…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/RonenNess/RPGUI" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Win95.css (&lt;a href="https://alexbsoft.github.io/win95.css/" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;)
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/AlexBSoft" rel="noopener noreferrer"&gt;
        AlexBSoft
      &lt;/a&gt; / &lt;a href="https://github.com/AlexBSoft/win95.css" rel="noopener noreferrer"&gt;
        win95.css
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Responsive Bootstrap 4 windows 95/98 theme &amp;amp; landing page template
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
    &lt;a href="https://alexbsoft.github.io/win95.css/" rel="nofollow noopener noreferrer"&gt;
        &lt;img src="https://camo.githubusercontent.com/fc206492ff06e97e3bfd806383d3dd4ab49725379c8d3e98fd5a8984d6123abc/68747470733a2f2f692e696d6775722e636f6d2f6b6258416354412e706e67"&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Win95.CSS&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Make your bootstrap look like Windows 95/98.&lt;/p&gt;

&lt;p&gt;
    &lt;a href="https://alexbsoft.github.io/win95.css/personal_page.html" rel="nofollow noopener noreferrer"&gt;
        &lt;img src="https://camo.githubusercontent.com/786c0d6f56fa45997733aae4dda8e3736a74e0d142105a601471888449d79ad0/68747470733a2f2f692e696d6775722e636f6d2f765039417a64472e706e67"&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://alexbsoft.github.io/win95.css/" rel="nofollow noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Documentation will be soon.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Sponsored by&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://bomjar.ga" rel="nofollow noopener noreferrer"&gt;&lt;br&gt;
&lt;img src="https://camo.githubusercontent.com/50c94b76e68444cb5571c40dbda9e7f31bac0f8dc57910731da0c1f1b4fa78bf/68747470733a2f2f626f6d6a61722e67612f6173736574732f6c6f676f2e706e67"&gt;Bomjar.ga&lt;/a&gt;- $1 unlimited PHP hosting&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Windows 95 button styles&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Windows 98 cards&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Windows 98 icons (256-color)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fully Responsive&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bootstrap 4&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Some screenshots&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f77d796857fe10fd0a274cdfbc6d0014b5b27ef64446aa8d468c2871805fc3d2/68747470733a2f2f692e696d6775722e636f6d2f4167516f6e6a622e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/f77d796857fe10fd0a274cdfbc6d0014b5b27ef64446aa8d468c2871805fc3d2/68747470733a2f2f692e696d6775722e636f6d2f4167516f6e6a622e706e67" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;How your sites can be:&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/a3d4a2e38aa3c271f6262c7de6fe47773eaa848389204b1b0a544612337fed1a/68747470733a2f2f692e696d6775722e636f6d2f72544458594f452e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/a3d4a2e38aa3c271f6262c7de6fe47773eaa848389204b1b0a544612337fed1a/68747470733a2f2f692e696d6775722e636f6d2f72544458594f452e706e67" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/3a28a9db443a67b2247c20c8f0acb41886d25130f83759aa36ef3dd8403c9251/68747470733a2f2f692e696d6775722e636f6d2f6d6561394c6d4b2e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/3a28a9db443a67b2247c20c8f0acb41886d25130f83759aa36ef3dd8403c9251/68747470733a2f2f692e696d6775722e636f6d2f6d6561394c6d4b2e706e67" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Sources:&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Webamp &lt;a href="https://github.com/captbaritone/webamp" rel="noopener noreferrer"&gt;https://github.com/captbaritone/webamp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Clippy.js &lt;a href="https://www.smore.com/clippy-js" rel="nofollow noopener noreferrer"&gt;https://www.smore.com/clippy-js&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/AlexBSoft/win95.css" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h1&gt;
  
  
  7.css (&lt;a href="https://khang-nd.github.io/7.css/" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;)
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/khang-nd" rel="noopener noreferrer"&gt;
        khang-nd
      &lt;/a&gt; / &lt;a href="https://github.com/khang-nd/7.css" rel="noopener noreferrer"&gt;
        7.css
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A JS-independent, tree-shakeable CSS framework for building faithful recreations of the Windows 7 UI.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;7.css&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="http://npm.im/7.css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6fae7dcb04d2e4ef0d912f634a185856a72c2d608d6f01fad43553a766c1c303/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f372e637373" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://unpkg.com/7.css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2651bacc82c01874593c9f6ebb15de44a91bbfc04422500201a823b0716d0f7b/68747470733a2f2f696d672e736869656c64732e696f2f62756e646c6570686f6269612f6d696e7a69702f372e637373" alt="gzip size"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/khang-nd/7.css/docs/window.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fkhang-nd%2F7.css%2Fdocs%2Fwindow.png" alt="A screenshot of a window with the title 'My First Program' and two buttons OK and Cancel, styled like a Windows 7 dialog"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7.css&lt;/strong&gt; is a CSS framework that takes semantic HTML and styles them to the Windows 7 design
It is built on top of &lt;a href="https://github.com/botoxparty/XP.css" rel="noopener noreferrer"&gt;XP.css&lt;/a&gt;, which is an extension of &lt;a href="https://github.com/jdan/98.css" rel="noopener noreferrer"&gt;98.CSS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It does not ship with any JavaScript, so it is compatible with your frontend framework of choice.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📦 Installation / Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Directly via &lt;a href="https://unpkg.com/" rel="nofollow noopener noreferrer"&gt;unpkg&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;&amp;lt;!DOCTYPE html&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;html&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;title&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;7.css example&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;title&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;meta&lt;/span&gt; &lt;span class="pl-c1"&gt;charset&lt;/span&gt;="&lt;span class="pl-s"&gt;UTF-8&lt;/span&gt;" &lt;span class="pl-kos"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;rel&lt;/span&gt;="&lt;span class="pl-s"&gt;stylesheet&lt;/span&gt;" &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;https://unpkg.com/7.css&lt;/span&gt;" &lt;span class="pl-kos"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;head&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;body&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;window&lt;/span&gt;" &lt;span class="pl-c1"&gt;style&lt;/span&gt;="&lt;span class="pl-s"&gt;margin: 32px; width: 250px&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;title-bar&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;title-bar-text&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;My First Program&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-c1"&gt;class&lt;/span&gt;="&lt;span class="pl-s"&gt;window-body&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;p&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;Hello, world!&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;p&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/khang-nd/7.css" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Pokémon GameBoy CSS (&lt;a href="https://timothywalter.github.io/css-pokemon-gameboy/" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;)
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/luttje" rel="noopener noreferrer"&gt;
        luttje
      &lt;/a&gt; / &lt;a href="https://github.com/luttje/css-pokemon-gameboy" rel="noopener noreferrer"&gt;
        css-pokemon-gameboy
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A CSS-framework based on the gameboy color version of the original Pokémon games.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Pokémon GameBoy CSS&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Inspired by: &lt;a href="https://github.com/nostalgic-css/NES.css" rel="noopener noreferrer"&gt;https://github.com/nostalgic-css/NES.css&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is a joke CSS-framework and it is not intended for use in production. You can &lt;a href="https://luttje.github.io/css-pokemon-gameboy/" rel="nofollow noopener noreferrer"&gt;see a demo here&lt;/a&gt;. The demo performs poorly on mobile devices or small resolutions.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Using the distribution&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Download &lt;a href="https://github.com/luttje/css-pokemon-gameboy/releases" rel="noopener noreferrer"&gt;the latest release&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The css is in the &lt;code&gt;styles&lt;/code&gt; directory. All other assets are inlined into the css.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The release contains a &lt;code&gt;template.html&lt;/code&gt; to get your started.&lt;/p&gt;
&lt;p&gt;-OR-&lt;/p&gt;
&lt;p&gt;Append the following include on the page where you want this style:&lt;/p&gt;
&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;link&lt;/span&gt; &lt;span class="pl-c1"&gt;rel&lt;/span&gt;="&lt;span class="pl-s"&gt;stylesheet&lt;/span&gt;" &lt;span class="pl-c1"&gt;href&lt;/span&gt;="&lt;span class="pl-s"&gt;./styles/css-pokemon-gameboy.css&lt;/span&gt;"&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;See the &lt;a href="https://luttje.github.io/css-pokemon-gameboy/" rel="nofollow noopener noreferrer"&gt;demo&lt;/a&gt;, &lt;a href="https://github.com/luttje/css-pokemon-gameboy./index.html" rel="noopener noreferrer"&gt;index.html&lt;/a&gt; or &lt;a href="https://github.com/luttje/css-pokemon-gameboy./src/scss/" rel="noopener noreferrer"&gt;.scss-files&lt;/a&gt; for all possible classes and effects.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Compile it yourself&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Compiling&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Start a terminal/command prompt in the root directory of this repository&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;code&gt;npm install&lt;/code&gt; to install the dependencies&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To build the demo run &lt;code&gt;npm run build&lt;/code&gt; to build the distribution files to the &lt;code&gt;dist&lt;/code&gt; directory (preview the demo with &lt;code&gt;npm run&lt;/code&gt;…&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/luttje/css-pokemon-gameboy" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>css</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
