<?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: hudy9x</title>
    <description>The latest articles on DEV Community by hudy9x (@hudy9x).</description>
    <link>https://dev.to/hudy9x</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%2F906293%2Fa0e0ed55-a32e-40e8-a367-c155c02f37a1.jpeg</url>
      <title>DEV Community: hudy9x</title>
      <link>https://dev.to/hudy9x</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hudy9x"/>
    <language>en</language>
    <item>
      <title>Why I built my own PlantUML Generator (and why you might need it too)</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Sun, 08 Mar 2026 15:43:44 +0000</pubDate>
      <link>https://dev.to/hudy9x/why-i-built-my-own-plantuml-generator-and-why-you-might-need-it-too-536m</link>
      <guid>https://dev.to/hudy9x/why-i-built-my-own-plantuml-generator-and-why-you-might-need-it-too-536m</guid>
      <description>&lt;p&gt;If you're a developer, chances are you've used &lt;strong&gt;PlantUML&lt;/strong&gt; or &lt;strong&gt;Mermaid&lt;/strong&gt; to visualize logic. While Mermaid is great for quick charts, many enterprise projects still require PlantUML.&lt;/p&gt;

&lt;p&gt;However, the developer experience (DX) with PlantUML isn't always smooth. After struggling with slow rendering and clunky previews, I decided to build a web-based, offline-capable PlantUML generator.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/khmJpVSfkqo"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h3&gt;
  
  
  The Motivation
&lt;/h3&gt;

&lt;p&gt;The biggest "pain point" for me was the setup. Most solutions require a portable PlantUML server or a heavy VS Code extension. I wanted something fast, lightweight, and accessible directly in the browser—even without an internet connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solving the "Pain Points"
&lt;/h3&gt;

&lt;p&gt;I built &lt;strong&gt;Beautiful PlantUML&lt;/strong&gt; to solve 5 specific issues I faced daily:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Sticky Participants:&lt;/strong&gt; In large diagrams, scrolling down means losing track of which line belongs to which participant. I made them "sticky" so you always have context.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Flexible Zooming:&lt;/strong&gt; Instead of fighting with VS Code’s scroll-zoom, I implemented a more fluid navigation system.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Direct Message Editing:&lt;/strong&gt; You can now edit messages directly on the diagram without hunting through lines of code.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Performance:&lt;/strong&gt; I optimized the rendering engine to be significantly faster than traditional server-side generation.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Code Mapping (Experimental):&lt;/strong&gt; Clicking a message on the diagram should jump you straight to that line in the editor. &lt;em&gt;Note: Still in the lab, but getting there!&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Check it out
&lt;/h3&gt;

&lt;p&gt;The tool is live and free for everyone to use:&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://beautiful-plantuml.vercel.app/" rel="noopener noreferrer"&gt;https://beautiful-plantuml.vercel.app/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’d love to hear your feedback or any features you'd like to see added. Let’s make documentation a little less painful!&lt;/p&gt;

</description>
      <category>plantuml</category>
      <category>react</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Built 3 Work-Saving Desktop Apps in 3 Days Using Google Antigravity – Here’s How</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Wed, 25 Feb 2026 15:24:12 +0000</pubDate>
      <link>https://dev.to/hudy9x/i-built-3-work-saving-desktop-apps-in-3-days-using-google-antigravity-heres-how-2364</link>
      <guid>https://dev.to/hudy9x/i-built-3-work-saving-desktop-apps-in-3-days-using-google-antigravity-heres-how-2364</guid>
      <description>&lt;p&gt;Hey dev community 👋&lt;/p&gt;

&lt;p&gt;I'm hudy9x, a web app developer in Hanoi, and for the past few years I've been grinding on enterprise projects — the kind where budgets are tight, licenses are forbidden, and "just use VS Code preview" is the default answer to everything.&lt;/p&gt;

&lt;p&gt;But in February 2026, I decided to stop complaining and start building. Using &lt;strong&gt;Google Antigravity&lt;/strong&gt; (the new agentic AI IDE powered by Gemini 3), I shipped &lt;strong&gt;three custom desktop tools in just three days&lt;/strong&gt; that actually make my daily work better.&lt;/p&gt;

&lt;p&gt;No massive codebases. No weeks of setup. Just prompts, a bit of polish, and publish.&lt;/p&gt;

&lt;p&gt;Here's exactly what I built — and why this changes everything for solo devs and teams on a budget.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick context: My day job pain points
&lt;/h3&gt;

&lt;p&gt;I work on a big web app project. Every sprint includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing PlantUML and Mermaid diagrams for basic + detailed design docs&lt;/li&gt;
&lt;li&gt;Managing Docker containers (but company banned licensed Docker Desktop)&lt;/li&gt;
&lt;li&gt;Letting testers browse S3 buckets without giving them full AWS console access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Paid tools? Nope. VS Code extensions? They suck for real-time preview/editing. So I took matters into my own hands.&lt;/p&gt;

&lt;h3&gt;
  
  
  App 1: PlantUML + Mermaid Viewer/Editor (Day 1)
&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkw8dz73muorbbyri2df.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%2Fdkw8dz73muorbbyri2df.png" alt="PlantUML + Mermaid Viewer/Editor" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why I needed it:&lt;br&gt;&lt;br&gt;
Our team draws sequence/component diagrams daily. VS Code's PlantUML preview is laggy, no drag/drop, no easy zoom, and editing feels clunky. No budget for paid diagramming software like Lucidchart or Draw.io desktop.&lt;/p&gt;

&lt;p&gt;What I did:&lt;br&gt;&lt;br&gt;
I opened Antigravity, described the app in one prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Build a lightweight desktop app using Tauri + React that renders PlantUML and Mermaid diagrams from local .puml / .md files. Support live preview, drag-and-drop to rearrange elements, zoom in/out, pan, and inline editing of diagram text with instant re-render. Offline-first, no cloud."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent planned the stack, generated boilerplate, wired up rendering libs (like @mermaid-js/mermaid + plantuml-encoder), and even added nice-to-haves like theme toggle and export to PNG.&lt;/p&gt;

&lt;p&gt;Because I already have solid experience with Monaco Editor (for the inline editing), implementing search, and integrating those main packages, the initial running version came together surprisingly fast.  &lt;/p&gt;

&lt;p&gt;It took me &lt;strong&gt;12 hours&lt;/strong&gt; to complete a functional first version on Day 1 — but that version only included:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monaco Editor for text editing
&lt;/li&gt;
&lt;li&gt;Basic tab manager
&lt;/li&gt;
&lt;li&gt;Simple PlantUML preview
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fancy stuff (Mermaid support, drag-and-drop rearranging, zoom/pan, inline editing with instant re-render, export, etc.) came later — I kept iterating and adding features over the next 30+ days.&lt;/p&gt;

&lt;p&gt;Still, having that usable core in just 12 hours felt like magic. My PM now asks me to share the evolving version with the team 😂. Here it is &lt;a href="https://depdok.com" rel="noopener noreferrer"&gt;https://depdok.com&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  App 2: Custom Docker UI (Day 2)
&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm1mm27uvxnbwp20jk70.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%2Fqm1mm27uvxnbwp20jk70.png" alt="Custom Docker UI" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem:&lt;br&gt;&lt;br&gt;
Company policy bans any licensed software — including Docker Desktop. We all use Docker in WSL2 on Windows, but no nice GUI = constant terminal pain.&lt;/p&gt;

&lt;p&gt;Prompt to Antigravity:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Create a desktop Docker management UI that connects to a local Docker daemon (via exposed socket or TCP). Show running containers, images, volumes. Buttons to start/stop/restart, view logs, exec into shell. Handle WSL2 setup where daemon is inside WSL."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It built a Tauri frontend + Rust backend to talk to Docker API. Generated nice tables, real-time stats, dark mode...&lt;/p&gt;

&lt;p&gt;But... it was buggy on Windows at first (connection refused because WSL port wasn't exposed). After a few hours of debugging and prompting fixes ("add port forwarding from WSL to host via netsh interface portproxy"), it worked perfectly.&lt;/p&gt;

&lt;p&gt;Now I have my own "Docker Desktop" that's 100% allowed and super lightweight.&lt;/p&gt;

&lt;h3&gt;
  
  
  App 3: Simple AWS S3 Viewer (Day 3)
&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8jdm30q2ix6r3qpkj4wx.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%2F8jdm30q2ix6r3qpkj4wx.png" alt="Simple AWS S3 Viewer" width="800" height="754"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Super simple need:&lt;br&gt;&lt;br&gt;
Testers need to check uploaded files in S3 without logging into AWS console (security reasons + they don't have creds).&lt;/p&gt;

&lt;p&gt;I just cloned a sleek file-browser UI I saw on Instagram, took a screenshot + quick description, and told Antigravity to start building the app for me with that exact look and feel.&lt;/p&gt;

&lt;p&gt;One prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Build a desktop app that lets users input AWS credentials (access key + secret) and browse S3 buckets/files. List objects, preview images/text, download files. Securely store creds in OS keychain. No upload/delete for safety."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Antigravity handled AWS SDK integration, file listing, presigned URLs for preview/download, and even added a clean file tree view.&lt;/p&gt;

&lt;p&gt;Polished in under an hour. Shared with QA team — instant productivity boost.&lt;/p&gt;

&lt;h3&gt;
  
  
  The real magic: Prompt → Polish → Publish
&lt;/h3&gt;

&lt;p&gt;This whole process feels like cheating in 2026:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prompt&lt;/strong&gt; — Describe what you want in natural language (be specific about stack, features, constraints)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polish&lt;/strong&gt; — Review code, fix bugs, tweak UI/UX (agents help here too)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish&lt;/strong&gt; — Build binaries with Tauri, share via GitHub / itch.io / your site&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No more "I don't have time to build a tool." If it takes 3 days max for a working version, why not build exactly what your workflow needs?&lt;/p&gt;

&lt;h3&gt;
  
  
  How the last 2 years flipped my career thinking
&lt;/h3&gt;

&lt;p&gt;I used to think indie/dev tools were for "full-time makers" with endless time.&lt;br&gt;&lt;br&gt;
Then AI coding tools exploded: Cursor, Windsurf, now Antigravity...  &lt;/p&gt;

&lt;p&gt;Suddenly, a solo dev in Vietnam can prototype production-grade desktop apps faster than waiting for company approval or budget.  &lt;/p&gt;

&lt;p&gt;It shifted my mindset from "I'm just a web dev" to "I can build whatever tool solves my pain — and maybe others' too."  &lt;/p&gt;

&lt;p&gt;(This same energy helped me ship &lt;a href="https://depdok.com" rel="noopener noreferrer"&gt;DepDok&lt;/a&gt;, my offline-first Markdown editor with Mermaid/Kanban support. If you're into lightweight notes tools, check it out!)&lt;/p&gt;

&lt;h3&gt;
  
  
  What about you?
&lt;/h3&gt;

&lt;p&gt;What small (or big) desktop/web/tool have you been wishing for at work?&lt;br&gt;&lt;br&gt;
If it only took 3 days with Antigravity, would you build it?&lt;/p&gt;

&lt;p&gt;Drop a comment — I'd love to hear your ideas. Maybe I'll prompt one next weekend 😄&lt;/p&gt;

&lt;p&gt;Follow me on X &lt;a href="https://x.com/hudy09" rel="noopener noreferrer"&gt;@hudy09&lt;/a&gt; for more build-in-public chaos.&lt;/p&gt;

&lt;p&gt;Happy building!&lt;br&gt;&lt;br&gt;
hudy9x 🚀&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>desktopapps</category>
      <category>indiedev</category>
    </item>
    <item>
      <title>My 1-Day Prototype, 2-Week Launch: Building a Cross-Platform UML Editor with Tauri and Cursor</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Sat, 12 Jul 2025 08:06:07 +0000</pubDate>
      <link>https://dev.to/hudy9x/my-1-day-prototype-2-week-launch-building-a-cross-platform-uml-editor-with-tauri-and-cursor-3np9</link>
      <guid>https://dev.to/hudy9x/my-1-day-prototype-2-week-launch-building-a-cross-platform-uml-editor-with-tauri-and-cursor-3np9</guid>
      <description>&lt;p&gt;Hi, I'm Hudy - a half Indie maker based in Hanoi, Vietnam. Today, I'm thrilled to share the story of how I spent one day building a functional cross-platform desktop UML editor prototype. And then the next 10+ days refining it based on valuable feedback from my colleagues. &lt;/p&gt;

&lt;p&gt;Here is &lt;a href="https://github.com/hudy9x/uml.git" rel="noopener noreferrer"&gt;the Github repo&lt;/a&gt; and a quick look about the app:&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%2Fx6rhhhrx5n3l6crqu4dd.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%2Fx6rhhhrx5n3l6crqu4dd.png" alt="UML editor preview" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It includes some features such as: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uml text editor with syntax highlighted and suggestions&lt;/li&gt;
&lt;li&gt;Preview panel with zoom in/out and dragging around features&lt;/li&gt;
&lt;li&gt;Enable export uml as file .pu and .png&lt;/li&gt;
&lt;li&gt;Copy as an image and paste to chatbox&lt;/li&gt;
&lt;li&gt;Create multiple and update uml's title&lt;/li&gt;
&lt;li&gt;Realtime diagram preview&lt;/li&gt;
&lt;li&gt;Soft and permanent delete feature&lt;/li&gt;
&lt;li&gt;Restore deleted uml diagram&lt;/li&gt;
&lt;li&gt;Pop out the preview window&lt;/li&gt;
&lt;li&gt;Autoupdate using Github action pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See other open-sources that I built: &lt;a href="https://hudy9x.com" rel="noopener noreferrer"&gt;hudy9x.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why build my own UML tool ?
&lt;/h2&gt;

&lt;p&gt;Three weeks ago, my boss tell me that we've started the next phase of the project. And this phase requires us to implement the detailed design which include some detailed sequence diagram in UML format. &lt;/p&gt;

&lt;p&gt;So I've just googling a few days to find the best match for us. Found a lot of tools but with locked essential features behind a paywall. (Actually, I'm not familiar with DD and hate to draw, so I refused to learn how to use the tool LOL)&lt;/p&gt;

&lt;p&gt;I just need a simple tool which allows me to visualize and edit the diagram quickly without dragging, aligning, but just type and see the result. &lt;/p&gt;

&lt;p&gt;At that moment, an idea flashed in my mind: "Why don't I built my own UML tool" &lt;/p&gt;

&lt;h2&gt;
  
  
  Found the uml syntax but how to preview it
&lt;/h2&gt;

&lt;p&gt;Next 2 hours, I've kept googling "how to preview uml syntax in javascript, npm". And "wa lah" I figured out a package that called  &lt;code&gt;plantuml-encoder&lt;/code&gt; which accept an encoded uml syntax and calling the uml link to response an image/svg/text format. &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%2Fvfzs66rr46qskjgsmbt7.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%2Fvfzs66rr46qskjgsmbt7.png" alt="plantuml-encoder" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Boom, let's build it right away. &lt;/p&gt;

&lt;h2&gt;
  
  
  Choose Tauri for building cross-platform desktop app
&lt;/h2&gt;

&lt;p&gt;Immediately, I opened &lt;a href="https://v2.tauri.app/" rel="noopener noreferrer"&gt;tauri.app&lt;/a&gt; and install required dependencies and start building the project. Here is what I chosen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tauri&lt;/li&gt;
&lt;li&gt;Pnpm&lt;/li&gt;
&lt;li&gt;Reactjs - frontend&lt;/li&gt;
&lt;li&gt;Sqlite - database&lt;/li&gt;
&lt;li&gt;Zustand - state management&lt;/li&gt;
&lt;li&gt;Shadcn UI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Crafting the UML editor prototype
&lt;/h2&gt;

&lt;p&gt;Now that is the important part, I had to isolate the scope of development, otherwise the app would never been released LOL. In order to increase the development process I just need to simplify features. So after 15 minutes of brainstorming with my ego, here are the features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The app only have 2 part: the left and the right.&lt;/li&gt;
&lt;li&gt;Left is a text editor&lt;/li&gt;
&lt;li&gt;Right is the preview panel&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's breaking down these two features. Regarding the left side, what requirements it should cover: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text editor must have syntax highlighted&lt;/li&gt;
&lt;li&gt;It must have embed theme and allow to customize the theme&lt;/li&gt;
&lt;li&gt;It must have completions and search or replace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these requirements, I found &lt;a href="https://www.npmjs.com/package/@uiw/react-codemirror" rel="noopener noreferrer"&gt;@uiw/react-codemirror&lt;/a&gt; - a wrapper of code-mirror for React.js&lt;/p&gt;

&lt;p&gt;Regarding the right side - the preview panel. It's more simpler, cause we just need to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Preview the uml syntax&lt;/li&gt;
&lt;li&gt;It must allow to dragging around&lt;/li&gt;
&lt;li&gt;It must allow to zoom in/out&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For dragging and zooming, I found &lt;a href="https://www.npmjs.com/package/react-zoom-pan-pinch" rel="noopener noreferrer"&gt;react-zoom-pan-pinch&lt;/a&gt; package. However, the preview got an issue was that the image became too blurry when zoomed in. Therefore, I used svg instead of image as follow&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// just change the /img to /svg in the url
var url = 'http://www.plantuml.com/plantuml/svg/' + encoded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Now I just need to open cursor and tell it to start building. After 30 minutes doing questions and answers with it, the output is something like 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%2F1rh0kwwltdvvm4gah9ir.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%2F1rh0kwwltdvvm4gah9ir.png" alt="The first prototype" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply the build pipeline automatically for Windows and Macos
&lt;/h2&gt;

&lt;p&gt;Since I built this app on Mac, I had to create a Github pipeline to generate the Windows version. &lt;/p&gt;

&lt;p&gt;While this step might seem daunting, it's surprisingly simple. Tauri provides a comprehensive solution for this process that you can just copy and paste: &lt;a href="https://v2.tauri.app/distribute/pipelines/github/#example-workflow" rel="noopener noreferrer"&gt;Tauri Github Pipeline&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Release a beta version and get feedbacks in next 10+ days
&lt;/h2&gt;

&lt;p&gt;Next days, I just sent the app to my colleagues and eager for their feedbacks. And to my pleasant surprise, the suggestions poured in! This "collect comments and review" phase lasted over 10+ days and was invaluable. Here's a snapshot of suggestions that helped  shape the app: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"I think you should create a tab on the left or the top, something like notepad++ to show what files you're editting and help me easy to switch between them"&lt;/li&gt;
&lt;li&gt;"The preview panel should able to pop out the main window. Cuz the window's size kinda too small, I'd like to split it out to the other screen to edit"&lt;/li&gt;
&lt;li&gt;"Can I copy it as an image and paste it to Teams chatbox ?"&lt;/li&gt;
&lt;li&gt;"What if I delete the app, where is my diagram? Could you allow to save it or something"&lt;/li&gt;
&lt;li&gt;"The theme is too light, could you provide the dark mode"&lt;/li&gt;
&lt;li&gt;"Well, the diagram list is too long and hard to find. Can you allow to delete it and provide a search box ? "&lt;/li&gt;
&lt;li&gt;"For now, I have 3 running projects, each of them have 4-5 diagram. Can you provide something like folder, project or category to manage them easier?"&lt;/li&gt;
&lt;li&gt;"Do you have sort feature, it's kinda drag the diagram to sort them"&lt;/li&gt;
&lt;li&gt;....&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lession learned and road ahead
&lt;/h2&gt;

&lt;p&gt;That's the story! The app officially launched within two weeks: one intense day of prototyping, and over 10 days dedicated to iterating and improving based on real user feedback. It was an incredible learning experience. I gained a deeper understanding of efficient development, the power of rapid prototyping, and the immense value of user-centric design.&lt;/p&gt;

&lt;p&gt;Building this app with Cursor by my side, which streamlined many coding tasks, combined with my prior Tauri knowledge, made this rapid development cycle possible. It truly shows what you can achieve when you focus on user needs and leverage powerful tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;P/s: I've been learning to write English. So the post is mixed with Gemeni and me :D &lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>3 FOSS Project Manager that JS devs want to contribute</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Tue, 30 Jul 2024 14:18:57 +0000</pubDate>
      <link>https://dev.to/hudy9x/3-foss-project-manager-that-js-devs-want-to-contribute-47df</link>
      <guid>https://dev.to/hudy9x/3-foss-project-manager-that-js-devs-want-to-contribute-47df</guid>
      <description>&lt;p&gt;Hi everyone, It's Hudy again&lt;/p&gt;

&lt;p&gt;In this post, I'm gonna share with you 3 open source project management application you may not know about them. &lt;/p&gt;

&lt;h2&gt;
  
  
  Plane.so
&lt;/h2&gt;

&lt;p&gt;🔥 🔥 🔥 Open Source JIRA, Linear and Asana Alternative. Plane helps you track your issues, epics, and product roadmaps in the simplest way possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/a3b6788ab8ed064ef435eb49704b37ed31e0fbce524024f3eb3cf7f86a5afe33/68747470733a2f2f706c616e652d6d61726b6574696e672e73332e61702d736f7574682d312e616d617a6f6e6177732e636f6d2f706c616e652d726561646d652f706c616e655f73637265656e735f6461726b5f6d6f64652e77656270" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/a3b6788ab8ed064ef435eb49704b37ed31e0fbce524024f3eb3cf7f86a5afe33/68747470733a2f2f706c616e652d6d61726b6574696e672e73332e61702d736f7574682d312e616d617a6f6e6177732e636f6d2f706c616e652d726561646d652f706c616e655f73637265656e735f6461726b5f6d6f64652e77656270" alt="image 1" width="3840" height="2160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://plane.so" rel="noopener noreferrer"&gt;https://plane.so&lt;/a&gt;&lt;br&gt;
Github: &lt;a href="https://github.com/makeplane/plane" rel="noopener noreferrer"&gt;https://github.com/makeplane/plane&lt;/a&gt;&lt;br&gt;
Star: +26k&lt;/p&gt;

&lt;h2&gt;
  
  
  Huly.io
&lt;/h2&gt;

&lt;p&gt;Huly, an open-source platform, serves as an all-in-one replacement of Linear, Jira, Slack, and Notion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HVqYNEpX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://huly.io/_next/image%3Furl%3D%252F_next%252Fstatic%252Fmedia%252Fhero-illustration.7100a376.jpg%26w%3D750%26q%3D75" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HVqYNEpX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://huly.io/_next/image%3Furl%3D%252F_next%252Fstatic%252Fmedia%252Fhero-illustration.7100a376.jpg%26w%3D750%26q%3D75" alt="image-2" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://huly.io/" rel="noopener noreferrer"&gt;https://huly.io/&lt;/a&gt;&lt;br&gt;
Github: &lt;a href="https://github.com/hcengineering/platform" rel="noopener noreferrer"&gt;https://github.com/hcengineering/platform&lt;/a&gt;&lt;br&gt;
Star: +5.4k&lt;/p&gt;

&lt;h2&gt;
  
  
  Namviek.com
&lt;/h2&gt;

&lt;p&gt;Namviek is an open-source project manager for small teams with low budget. It includes essential features for running your team.&lt;/p&gt;

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

&lt;p&gt;Website: &lt;a href="https://namviek.com" rel="noopener noreferrer"&gt;https://namviek.com&lt;/a&gt;&lt;br&gt;
Github: &lt;a href="https://github.com/hudy9x/namviek" rel="noopener noreferrer"&gt;https://github.com/hudy9x/namviek&lt;/a&gt;&lt;br&gt;
Star: +1.8k&lt;/p&gt;

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

&lt;p&gt;So, if you've been running a small team with a low budget, they would be the best choice. Additionally, it could be a good project to contribute to, which would help you improve your skills or even your reputation.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Deploy your own project management app on Vercel and Render without coding skills and especially, it's free.</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Sat, 06 Jul 2024 14:49:26 +0000</pubDate>
      <link>https://dev.to/hudy9x/deploy-your-own-project-management-app-on-vercel-and-render-without-coding-skills-and-especially-its-free-1hea</link>
      <guid>https://dev.to/hudy9x/deploy-your-own-project-management-app-on-vercel-and-render-without-coding-skills-and-especially-its-free-1hea</guid>
      <description>&lt;p&gt;Hi everyone, It's Hudy again&lt;/p&gt;

&lt;p&gt;Today, I just released the deployment guide for Namviek on youtube. So, if someone who need to deploy my app to run their team please check out the link below&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Pql94kF--4s"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;For those who would like to scroll for fast, use this post intead. &lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation
&lt;/h2&gt;

&lt;p&gt;In order to deploy &lt;code&gt;namviek&lt;/code&gt; to Vercel and Render we need to prepare accounts on the following services&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt; - for caching&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://account.mongodb.com/account/login?nds=true" rel="noopener noreferrer"&gt;Mongodb Atlas&lt;/a&gt; - for database&lt;/li&gt;
&lt;li&gt;Github Account - store the codebase&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firestore&lt;/a&gt; - for Gmail authentication&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; - for frontend&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://render.com" rel="noopener noreferrer"&gt;Render&lt;/a&gt; - for backend&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deployment process
&lt;/h2&gt;

&lt;p&gt;The deployment progress will implemented in 5 steps. That's a lot of steps for a deployment tasks I know. However, you need no coding skills for these step. Just copy and paste some configurations and follows exactly what I do.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create Redis database
&lt;/h3&gt;

&lt;p&gt;So, the first thing we need to do is that create Redis database. Please go to &lt;a href="https://docs.namviek.com/doc/use-redis-cloud" rel="noopener noreferrer"&gt;use Redis cloud&lt;/a&gt; section and follow my instruction. The result of this step is you must to get the redis connection string as follow&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REDIS_HOST=redis://default:ck7VLUkNQ*************GWeD@redis-18732.a293.ap-southeast-1-1.ec2.redns.redis-cloud.com:11077
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Create database on Mongodb Atlas
&lt;/h3&gt;

&lt;p&gt;Next, navigate to &lt;a href="https://account.mongodb.com/account/login" rel="noopener noreferrer"&gt;Mongodb Atlas&lt;/a&gt; and create your own database as the following &lt;a href="https://docs.namviek.com/doc/installation#create-mongodb-atlas-database" rel="noopener noreferrer"&gt;instruction&lt;/a&gt;. After completing this process you will obtain the mongodb connection string in the following format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MONGODB_URL=mongodb+srv://{user}:{pwd}@cluster0.weszq.mongodb.net/{dbName}?retryWrites=true&amp;amp;w=majority
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to secure your connection by restricting a specified Ip address, please visit &lt;a href="https://docs.namviek.com/doc/mongodb-network-access" rel="noopener noreferrer"&gt;MongoDb Network Access&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Deploy backend to Render
&lt;/h3&gt;

&lt;p&gt;Now, it's time to deploy backend to Render. Open a new tab and visit &lt;a href="https://render.com" rel="noopener noreferrer"&gt;Render.com&lt;/a&gt;. Sign up a new account and just leave it. Go to my &lt;a href="https://github.com/hudy9x/namviek?tab=readme-ov-file#deploy" rel="noopener noreferrer"&gt;repo&lt;/a&gt; and click on the &lt;strong&gt;Deploy to Render&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;You will be redirect to the deployment page as following. Fill your &lt;code&gt;Blueprint Name&lt;/code&gt; and environment variables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwvovpmb8p84bziu2ykho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwvovpmb8p84bziu2ykho.png" alt="render-deploy-1" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The env values should be like the below example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JWT_REFRESH_KEY=287kjshkjshdf
JWT_SECRET_KEY=12981KJ1H23KJH

JWT_REFRESH_EXPIRED=4h
JWT_TOKEN_EXPIRED=30m
JWT_VERIFY_USER_LINK_TOKEN_EXPIRED=1h

NEXT_PUBLIC_FE_GATEWAY=https://test/v2/234234/clusters

MONGODB_URL=mongodb+srv://&amp;lt;user&amp;gt;:&amp;lt;pass&amp;gt;@cluster0.bswhjt.mongodb.net/demodb?retryWrites=true&amp;amp;w=majority
REDIS_HOST=redis://&amp;lt;user&amp;gt;:&amp;lt;pass&amp;gt;@redis-48362.c345.ap-southeast-1-1.ec2.redns.redis-cloud.com:19729
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;MONGODB_URL&lt;/code&gt; and &lt;code&gt;REDIS_HOST&lt;/code&gt; are important variables. So please input them exactly. The others are up to you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Click on the &lt;code&gt;Apply&lt;/code&gt; button to start deploying. &lt;br&gt;
Wait for Render deploy the app. If nothing wrong the output should look like below. Don't worry about the red line through&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffg6tf3rg1noq77dxwhcb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffg6tf3rg1noq77dxwhcb.png" alt="render-deploy-5" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Verify Render deployment process
&lt;/h4&gt;

&lt;p&gt;Right after Render finishs the deployment process we have to verify it whether success or not. Head to &lt;strong&gt;Mongodb Atlas&lt;/strong&gt; &amp;gt; &lt;strong&gt;Database&lt;/strong&gt; &amp;gt; &lt;strong&gt;Cluster&lt;/strong&gt; &amp;gt; &lt;strong&gt;Collections&lt;/strong&gt;. And find your database that you've created earlier. If you see a list of collections as the image below then congrats you succeeded.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxlj5sfv9w87niqfmqvn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxlj5sfv9w87niqfmqvn.png" alt="render-deploy-5" width="270" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Deploy frontend to Vercel
&lt;/h3&gt;

&lt;p&gt;Well, the last thing to run &lt;code&gt;namviek&lt;/code&gt; is to deploy the frontend to Vercel. This will be quick i promise :D. &lt;/p&gt;

&lt;p&gt;Open your browser and go to my &lt;a href="https://github.com/hudy9x/namviek?tab=readme-ov-file#deploy" rel="noopener noreferrer"&gt;repo&lt;/a&gt; and click on the &lt;code&gt;Vercel deploy&lt;/code&gt; button. It will navigate you to the deploy page. Give it a name and press &lt;code&gt;Create&lt;/code&gt; button. Then fill environment variables and press &lt;code&gt;Deploy&lt;/code&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1rx21m7g33rc7x9gwyiy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1rx21m7g33rc7x9gwyiy.png" alt="vercel-deploy-1" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don't find the &lt;code&gt;NEXT_PUBLIC_BE_GATEWAY&lt;/code&gt; please go to &lt;strong&gt;Render.com&lt;/strong&gt; and navigate to service's setting. You'll see the domain&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpw5ejxsg2oedgluasulm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpw5ejxsg2oedgluasulm.png" alt="vercel-deploy-1" width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At last, if you're lucky the below screen will be displayed that means the deployment is success. LOL&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbf083gdupbl44f3bo67.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbf083gdupbl44f3bo67.png" alt="vercel-deploy-1" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Integrate Gmail authentication
&lt;/h3&gt;

&lt;p&gt;Follow my instruction &lt;a href="https://docs.namviek.com/doc/gmail-auth" rel="noopener noreferrer"&gt;here&lt;/a&gt; to integrate Gmail authentication&lt;/p&gt;

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

&lt;p&gt;Hope you found something helpful in this post. If you got any issues, please create an PR or go to my Discord server for help. Thank for reading. &lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>node</category>
      <category>opensource</category>
      <category>vercel</category>
    </item>
    <item>
      <title>Deploy your own project management app on Vercel and Render for free</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Sat, 06 Jul 2024 09:14:00 +0000</pubDate>
      <link>https://dev.to/hudy9x/how-to-deploy-namviek-to-vercel-and-render-for-free-2fe7</link>
      <guid>https://dev.to/hudy9x/how-to-deploy-namviek-to-vercel-and-render-for-free-2fe7</guid>
      <description>&lt;p&gt;Hi everyone, It's Hudy again&lt;/p&gt;

&lt;p&gt;Today, I just released the deployment guide for Namviek on youtube. So, if someone who need to deploy my app to run their team please check out the link below&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Pql94kF--4s"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;For those who would like to scroll for fast, use this post intead. &lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation
&lt;/h2&gt;

&lt;p&gt;In order to deploy &lt;code&gt;namviek&lt;/code&gt; to Vercel and Render we need to prepare accounts on the following services&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt; - for caching&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://account.mongodb.com/account/login?nds=true" rel="noopener noreferrer"&gt;Mongodb Atlas&lt;/a&gt; - for database&lt;/li&gt;
&lt;li&gt;Github Account - store the codebase&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firestore&lt;/a&gt; - for Gmail authentication&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; - for frontend&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://render.com" rel="noopener noreferrer"&gt;Render&lt;/a&gt; - for backend&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deployment process
&lt;/h2&gt;

&lt;p&gt;The deployment progress will implemented in 5 steps. That's a lot of steps for a deployment tasks I know. However, you need no coding skills for these step. Just copy and paste some configurations and follows exactly what I do.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create Redis database
&lt;/h3&gt;

&lt;p&gt;So, the first thing we need to do is that create Redis database. Please go to &lt;a href="https://docs.namviek.com/doc/use-redis-cloud" rel="noopener noreferrer"&gt;use Redis cloud&lt;/a&gt; section and follow my instruction. The result of this step is you must to get the redis connection string as follow&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

REDIS_HOST=redis://default:ck7VLUkNQ*************GWeD@redis-18732.a293.ap-southeast-1-1.ec2.redns.redis-cloud.com:11077


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  2. Create database on Mongodb Atlas
&lt;/h3&gt;

&lt;p&gt;Next, navigate to &lt;a href="https://account.mongodb.com/account/login" rel="noopener noreferrer"&gt;Mongodb Atlas&lt;/a&gt; and create your own database as the following &lt;a href="https://docs.namviek.com/doc/installation#create-mongodb-atlas-database" rel="noopener noreferrer"&gt;instruction&lt;/a&gt;. After completing this process you will obtain the mongodb connection string in the following format.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

MONGODB_URL=mongodb+srv://{user}:{pwd}@cluster0.weszq.mongodb.net/{dbName}?retryWrites=true&amp;amp;w=majority


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you want to secure your connection by restricting a specified Ip address, please visit &lt;a href="https://docs.namviek.com/doc/mongodb-network-access" rel="noopener noreferrer"&gt;MongoDb Network Access&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Deploy backend to Render
&lt;/h3&gt;

&lt;p&gt;Now, it's time to deploy backend to Render. Open a new tab and visit &lt;a href="https://render.com" rel="noopener noreferrer"&gt;Render.com&lt;/a&gt;. Sign up a new account and just leave it. Go to my &lt;a href="https://github.com/hudy9x/namviek?tab=readme-ov-file#deploy" rel="noopener noreferrer"&gt;repo&lt;/a&gt; and click on the &lt;strong&gt;Deploy to Render&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;You will be redirect to the deployment page as following. Fill your &lt;code&gt;Blueprint Name&lt;/code&gt; and environment variables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fwvovpmb8p84bziu2ykho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fwvovpmb8p84bziu2ykho.png" alt="render-deploy-1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The env values should be like the below example.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

JWT_REFRESH_KEY=287kjshkjshdf
JWT_SECRET_KEY=12981KJ1H23KJH

JWT_REFRESH_EXPIRED=4h
JWT_TOKEN_EXPIRED=30m
JWT_VERIFY_USER_LINK_TOKEN_EXPIRED=1h

NEXT_PUBLIC_FE_GATEWAY=https://test/v2/234234/clusters

MONGODB_URL=mongodb+srv://&amp;lt;user&amp;gt;:&amp;lt;pass&amp;gt;@cluster0.bswhjt.mongodb.net/demodb?retryWrites=true&amp;amp;w=majority
REDIS_HOST=redis://&amp;lt;user&amp;gt;:&amp;lt;pass&amp;gt;@redis-48362.c345.ap-southeast-1-1.ec2.redns.redis-cloud.com:19729


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;MONGODB_URL&lt;/code&gt; and &lt;code&gt;REDIS_HOST&lt;/code&gt; are important variables. So please input them exactly. The others are up to you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Click on the &lt;code&gt;Apply&lt;/code&gt; button to start deploying. &lt;br&gt;
Wait for Render deploy the app. If nothing wrong the output should look like below. Don't worry about the red line through&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ffg6tf3rg1noq77dxwhcb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ffg6tf3rg1noq77dxwhcb.png" alt="render-deploy-5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Verify Render deployment process
&lt;/h4&gt;

&lt;p&gt;Right after Render finishs the deployment process we have to verify it whether success or not. Head to &lt;strong&gt;Mongodb Atlas&lt;/strong&gt; &amp;gt; &lt;strong&gt;Database&lt;/strong&gt; &amp;gt; &lt;strong&gt;Cluster&lt;/strong&gt; &amp;gt; &lt;strong&gt;Collections&lt;/strong&gt;. And find your database that you've created earlier. If you see a list of collections as the image below then congrats you succeeded.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fgxlj5sfv9w87niqfmqvn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fgxlj5sfv9w87niqfmqvn.png" alt="render-deploy-5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Deploy frontend to Vercel
&lt;/h3&gt;

&lt;p&gt;Well, the last thing to run &lt;code&gt;namviek&lt;/code&gt; is to deploy the frontend to Vercel. This will be quick i promise :D. &lt;/p&gt;

&lt;p&gt;Open your browser and go to my &lt;a href="https://github.com/hudy9x/namviek?tab=readme-ov-file#deploy" rel="noopener noreferrer"&gt;repo&lt;/a&gt; and click on the &lt;code&gt;Vercel deploy&lt;/code&gt; button. It will navigate you to the deploy page. Give it a name and press &lt;code&gt;Create&lt;/code&gt; button. Then fill environment variables and press &lt;code&gt;Deploy&lt;/code&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F1rx21m7g33rc7x9gwyiy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F1rx21m7g33rc7x9gwyiy.png" alt="vercel-deploy-1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don't find the &lt;code&gt;NEXT_PUBLIC_BE_GATEWAY&lt;/code&gt; please go to &lt;strong&gt;Render.com&lt;/strong&gt; and navigate to service's setting. You'll see the domain&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fpw5ejxsg2oedgluasulm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fpw5ejxsg2oedgluasulm.png" alt="vercel-deploy-1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At last, if you're lucky the below screen will be displayed that means the deployment is success. LOL&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Flbf083gdupbl44f3bo67.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Flbf083gdupbl44f3bo67.png" alt="vercel-deploy-1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Integrate Gmail authentication
&lt;/h3&gt;

&lt;p&gt;Follow my instruction &lt;a href="https://docs.namviek.com/doc/gmail-auth" rel="noopener noreferrer"&gt;here&lt;/a&gt; to integrate Gmail authentication&lt;/p&gt;

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

&lt;p&gt;Hope you found something helpful in this post. If you got any issues, please create an PR or go to my Discord server for help. Thank for reading. &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>nextjs</category>
      <category>node</category>
    </item>
    <item>
      <title>8 Date Functions You Can Absolutely Write Without a Library</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Mon, 24 Jun 2024 03:04:16 +0000</pubDate>
      <link>https://dev.to/hudy9x/8-date-functions-you-can-absolutely-write-without-a-library-372f</link>
      <guid>https://dev.to/hudy9x/8-date-functions-you-can-absolutely-write-without-a-library-372f</guid>
      <description>&lt;p&gt;Hi everyone, It's Hudy again&lt;/p&gt;

&lt;p&gt;Date is one of the most popular object in Javascript that you're supposed to work with in at least one of your projects. And I'm sure that you also implement these function using the &lt;code&gt;Date&lt;/code&gt; object for some cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compare two dates&lt;/li&gt;
&lt;li&gt;get the last date of month&lt;/li&gt;
&lt;li&gt;convert date to readable version&lt;/li&gt;
&lt;li&gt;... many more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So in this post, I'd like to share with you 8 date utilities function that I often use to manipulate the Date object in javascript.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Convert date to a readable version
&lt;/h2&gt;

&lt;p&gt;If you have a list of activities and you'd like to display a readable version of date (ex: 2 min ago, 10 hours ago, 2 days ago) for straightforward and understandable when an activity happens. &lt;/p&gt;

&lt;p&gt;Then you could try this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;toReadableDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AMIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ADAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AMIN&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculateMinuteFromNow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;isFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;absMinutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;addAffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;minStr&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="n"&gt;isFuture&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;minStr&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="err"&gt;`$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;minStr&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;ago&lt;/span&gt;&lt;span class="err"&gt;`&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="n"&gt;absMinutes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;AMIN&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="n"&gt;addAffix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;`$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="err"&gt;`&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="n"&gt;absMinutes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ADAY&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;addAffix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;`$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;absMinutes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;AMIN&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="err"&gt;`&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="n"&gt;absMinutes&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;ADAY&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isFuture&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="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;yesterday&lt;/span&gt;&lt;span class="err"&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="n"&gt;absMinutes&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;ADAY&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;isFuture&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="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;tomorrow&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;addAffix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;`$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;absMinutes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ADAY&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateMinuteFromNow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// minutes&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Test&lt;/span&gt;
&lt;span class="n"&gt;toReadableDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&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;// '11 days ago'&lt;/span&gt;
&lt;span class="n"&gt;toReadableDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// 'in 5 days'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Get the first/last date of month
&lt;/h2&gt;

&lt;p&gt;The second function that I often used for getting first/last date in month. You can write it easily as follow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFirstDateOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setDate&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getLastDateOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()&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="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setDate&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="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setHours&lt;/span&gt;&lt;span class="p"&gt;(&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Test&lt;/span&gt;
&lt;span class="n"&gt;getFirstDateOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;getLastDateOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Compare two dates
&lt;/h2&gt;

&lt;p&gt;There are two case occur in this function. First, you'd like to compare date and the second is you'd like to compare exact date and time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;compareDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dateRight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateLeft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateRight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d1Str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;`$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d2Str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;`$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;d1Str&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;d2Str&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above version compares dates only by year, month and day. It doesn't consider hours, minutes and seconds. The following will handle comparisions based on the exact date and time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;compareExactDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dateRight&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateLeft&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateRight&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;getTime&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;h2&gt;
  
  
  4. Calculate the duration between two dates
&lt;/h2&gt;

&lt;p&gt;The fourth function will helps you calculate the number of days/hours/minutes between two dates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;
&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dateRight&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;HOUR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateLeft&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateRight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;d1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;MIN&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;HOUR&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;DAY&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Test&lt;/span&gt;
&lt;span class="n"&gt;getDuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The earlier function only returns the number of days. You can custom the formula to return value in hour, minute as you wish.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Get list of month/day in alphabet or number
&lt;/h2&gt;

&lt;p&gt;Sometimes, you want to get the list of month or day in alphabet for displaying on a select box or calendar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getMonthList&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;months&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;January&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;February&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;March&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;April&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;May&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;June&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;July&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;August&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;September&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;October&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;November&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;December&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;months&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDayList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;Sunday&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;Monday&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;Tuesday&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;Wednesday&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;Thursday&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;Friday&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;Saturday&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCompactDayList&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="n"&gt;getDayList&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&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="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="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCompactMonthList&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="n"&gt;getMonthList&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&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="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="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getMonthOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compact&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;getCompactMonthList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;getMonthList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDayOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compact&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;getCompactDayList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;getDayList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&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="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;i&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;h2&gt;
  
  
  6. Get the first (monday) and last day (saturday) of week
&lt;/h2&gt;

&lt;p&gt;For those unfamiliar with the &lt;code&gt;Date&lt;/code&gt; object, keep in mind that &lt;code&gt;Sunday&lt;/code&gt; is assigned &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;Saturday&lt;/code&gt; is assigned &lt;code&gt;6&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFirstDayOfWeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;currentDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentDate&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;day&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Test&lt;/span&gt;
&lt;span class="n"&gt;getFirstDayOfWeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&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 c"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getLastDayOfWeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;currentDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentDate&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Test&lt;/span&gt;
&lt;span class="n"&gt;getLastDayOfWeek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Get the list of week by a specified date
&lt;/h2&gt;

&lt;p&gt;I often use this function to generate labels for a week's worth of data, which I then use on the x-axis of my visualizations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getListOfWeekByDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;week&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;weekLen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;

  &lt;span class="n"&gt;let&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;weekLen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;

    &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;week&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;week&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Test&lt;/span&gt;
&lt;span class="n"&gt;getListOfWeekByDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Get all week of month
&lt;/h2&gt;

&lt;p&gt;The last function will return all weeks of month. I ultilize &lt;code&gt;getLastDateOfMonth&lt;/code&gt;, &lt;code&gt;getFirstDateOfMonth&lt;/code&gt; and &lt;code&gt;getListOfWeekByDate&lt;/code&gt; from the above functions to create this function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. we generate the first week of month &lt;/span&gt;
&lt;span class="c1"&gt;// by using `getFirstDateOfMonth` and `getListOfWeekByDate`&lt;/span&gt;
&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFirstWeekOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;firstDateOfMonth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getFirstDateOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;getListOfWeekByDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstDateOfMonth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFullWeekOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;weeks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;lastDateInThisMonth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getLastDateOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. get the first week&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;firstWeek&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getFirstWeekOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;weeks&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="n"&gt;firstWeek&lt;/span&gt;

  &lt;span class="n"&gt;let&lt;/span&gt; &lt;span class="n"&gt;going&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;

  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;going&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;lastWeek&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weeks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;weeks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&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="c1"&gt;// 5.1 until no week found&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;lastWeek&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;going&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. get the last date of the last week&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;lastDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lastWeek&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lastWeek&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&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="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ldate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lastDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;lmonth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lastDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// 5.2 or that last date belongs to next month&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lmonth&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;ldate&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="n"&gt;lastDateInThisMonth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;going&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. increase the last date to 1&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;nextDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;nextDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDate&lt;/span&gt;&lt;span class="p"&gt;()&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="c1"&gt;// 4. generate the week by a new date&lt;/span&gt;
    &lt;span class="c1"&gt;// then keep going&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;week&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getListOfWeekByDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nextDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;weeks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;week&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="n"&gt;weeks&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;So, I hope this post provided you some useful things. If you have a better version of the above functions or want to share yours, go ahead, I'd love to learn from you guys. &lt;/p&gt;

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

</description>
    </item>
    <item>
      <title>2 re-rendering pitfalls I learned about while building my React app</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Sat, 15 Jun 2024 14:45:31 +0000</pubDate>
      <link>https://dev.to/hudy9x/two-simple-re-rendering-pitfalls-i-learned-about-while-building-my-react-app-2n7</link>
      <guid>https://dev.to/hudy9x/two-simple-re-rendering-pitfalls-i-learned-about-while-building-my-react-app-2n7</guid>
      <description>&lt;p&gt;Hi It's Hudy here.&lt;/p&gt;

&lt;p&gt;In this blog post, I'd like to share two re-rendering pitfalls I encountered while developing &lt;a href="https://namviek.com"&gt;Namviek&lt;/a&gt;, my open-source project management app, and how I addressed them.&lt;/p&gt;

&lt;p&gt;These pitfalls highlight common mistakes that can lead to performance issues in React applications. By understanding and avoiding these issues, you can ensure that your React apps run smoothly and efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Put states, Context.Provider and child component within the same place.
&lt;/h2&gt;

&lt;p&gt;I usually use React Context for building my own components (Ex: Calendar, ProjectMemberSelect) and containers. However, by habit, I tend to put states, Context.Provider and all child components within the same place.&lt;/p&gt;

&lt;p&gt;Look at the below example: I put the &lt;code&gt;counter&lt;/code&gt; state and &lt;code&gt;&amp;lt;Report.Provider/&amp;gt;&lt;/code&gt; inside &lt;code&gt;&amp;lt;Report/&amp;gt;&lt;/code&gt;. No problems, I thought initially.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; export default function Report() {

   const [counter, setCounter] = useState(1)  // state
   return (
     &amp;lt;Report.Provider value={{
       counter,
       setCounter
     }}&amp;gt;
        &amp;lt;ReportContent /&amp;gt; // child
        &amp;lt;ReportSidebar /&amp;gt; // child
     &amp;lt;/Report.Provider&amp;gt;
   )
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue just appeared when I increased &lt;code&gt;counter&lt;/code&gt; value. Both &lt;code&gt;&amp;lt;ReportContent /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;ReportSidebar/&amp;gt;&lt;/code&gt; re-rendered, even though they didn't rely on the &lt;code&gt;counter&lt;/code&gt; state. &lt;/p&gt;

&lt;p&gt;This might seem like a minor oversight, but it's a common pitfalls for developers who frequently use React Context like me, I guess.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Fixed version

export default function Report() {
  // moved state to another place
  return (
    &amp;lt;ReportProvider&amp;gt;
      &amp;lt;ReportContent /&amp;gt;
      &amp;lt;ReportSidebar /&amp;gt;
    &amp;lt;/ReportProvider&amp;gt;
  )
}

function ReportProvider({children}) {
  const [counter, setCounter] = useState(1) 
  return &amp;lt;Report.Provider value={{
     counter,
     setCounter
   }}&amp;gt;{children}&amp;lt;/Report.Provider&amp;gt;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the solution is straightforward: move the &lt;code&gt;counter&lt;/code&gt; state logic into the &lt;code&gt;&amp;lt;ReportProvider/&amp;gt;&lt;/code&gt; component. By doing this, only the components that truly depend on the context will re-render when the state changes.&lt;/p&gt;

&lt;p&gt;This fix works because the &lt;code&gt;counter&lt;/code&gt; state becomes encapsulated within the &lt;code&gt;&amp;lt;ReportProvider/&amp;gt;&lt;/code&gt; component. Since child components only receive the context value at the time of render, changes to the state within the provider won't trigger re-renders in &lt;code&gt;&amp;lt;ReportContent/&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;ReportSidebar/&amp;gt;&lt;/code&gt; unless they explicitly rely on the context.&lt;/p&gt;

&lt;p&gt;Crucially, the &lt;code&gt;children&lt;/code&gt; prop, which passes down the component tree, only updates when the &lt;code&gt;&amp;lt;Report /&amp;gt;&lt;/code&gt; component itself re-renders.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Misconception: Custom hooks do not cause component re-renders.
&lt;/h2&gt;

&lt;p&gt;Look the following example. I created a custom hook called &lt;code&gt;useUpdate&lt;/code&gt; to encapsulate the fetch logic with the goal of minimizing unnecessary re-renders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// custom hook
function useUpdate() {
  const [counter, setCounter] = useState(0)

  useEffect(() =&amp;gt; {
    // assume that this is a fetch call
    setTimeout(() =&amp;gt; {
      setCounter(c =&amp;gt; c + 1)
    }, 1000)
  }, [])
}

// component
export default function Report() {
  useUpdate()

  console.log('render Report'). // run twice

  return (
    &amp;lt;ReportProvider&amp;gt;
      &amp;lt;ReportContent /&amp;gt;
      &amp;lt;ReportSidebar /&amp;gt;
    &amp;lt;/ReportProvider&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I realized the &lt;code&gt;&amp;lt;Report/&amp;gt;&lt;/code&gt; component was still re-rendering as expected. While I thought custom hooks might prevent re-renders.&lt;/p&gt;

&lt;p&gt;After a few hours of researching I found that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A custom can be treated as a function simply which is executed from within the functional component and effectively the hooks that are present in the custom hook are transferred on to the component. So any change that would normally cause the component to re-render if the code within the custom hook was directly written within functional component will cause a re-render even if the hook is a custom hook. &lt;a href="https://stackoverflow.com/a/56346042/17752111"&gt;Refer&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So to fix this, I moved the &lt;code&gt;useUpdate&lt;/code&gt; hook to a separate component like &lt;code&gt;&amp;lt;PrefetchData/&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// fixed version

function PrefetchData() {
  useUpdate()
  return null
}

// component
export default function Report() {

  console.log('render Report'). // run once

  return (
    &amp;lt;ReportProvider&amp;gt;
      &amp;lt;PrefetchData /&amp;gt;
      &amp;lt;ReportContent /&amp;gt;
      &amp;lt;ReportSidebar /&amp;gt;
    &amp;lt;/ReportProvider&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the &lt;code&gt;&amp;lt;PrefetchData/&amp;gt;&lt;/code&gt; component will be responsible for retrieving the data and managing it's state. As a result, the re-render process will be isolated to the &lt;code&gt;&amp;lt;PrefetchData/&amp;gt;&lt;/code&gt; component, preventing unintended re-renders in unrelated components outside its scope.&lt;/p&gt;

&lt;p&gt;This approach ensures that updates to the report's state only trigger re-renders in components that rely on the fetched data, promoting a more efficient rendering cycle.&lt;/p&gt;

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

&lt;p&gt;I hope my experience can help others prevent performance issues caused by unintentional misuse of React.Context. If you have any insights into better solutions or have spotted any mistakes in my explanation, I'd be eager to learn from them.&lt;/p&gt;

</description>
      <category>react</category>
    </item>
    <item>
      <title>I built an open-source multi-platforms Note-taking app using Reactjs and Tauri</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Mon, 03 Jun 2024 17:40:55 +0000</pubDate>
      <link>https://dev.to/hudy9x/i-built-a-note-taking-app-for-2-years-ago-and-released-it-open-source-2m0j</link>
      <guid>https://dev.to/hudy9x/i-built-a-note-taking-app-for-2-years-ago-and-released-it-open-source-2m0j</guid>
      <description>&lt;p&gt;Hi everyone, It's Hudy again.&lt;/p&gt;

&lt;p&gt;Almost a month ago, I shared &lt;a href="https://dev.to/hudy9x/i-built-a-free-open-source-project-manager-that-helps-teams-keep-costs-under-15month-3pmk"&gt;my open-source project manager&lt;/a&gt; with you guys. And it got a lot of attention from community. Besides, I received valuable comments from you all which helped me improve the app significantly.&lt;/p&gt;

&lt;p&gt;So, today I'd love to share another open-source project with you: my Note-taking app that I built 2 years ago. &lt;/p&gt;

&lt;p&gt;It's a simple note-taking app designed for personal use. You can find it's features here &lt;a href="https://kompad.vercel.app/" rel="noopener noreferrer"&gt;kompad.vercel.app&lt;/a&gt;. And here's the Github &lt;a href="https://github.com/hudy9x/kompad" rel="noopener noreferrer"&gt;repository&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This app is open-source and free to use. However, it hasn't received updates in the past few months.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://kompad.vercel.app/" rel="noopener noreferrer"&gt;&lt;img src="https://media.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%2Flfkjbxs61weh3vk3juza.png" alt="Preview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What frameworks did i use
&lt;/h2&gt;

&lt;p&gt;Reactjs was still my favorite frontend framework that time. Additionally I discovered Tauri - an app construction toolkit that lets you build software for all major desktop operating system. This combination was fantastic for building multi-platform applications using Web technologies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tauri.app/v1/guides/getting-started/setup/" rel="noopener noreferrer"&gt;Tauri&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Reactjs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tiptap.dev/docs/editor/installation" rel="noopener noreferrer"&gt;Tiptap&lt;/a&gt; - a toolkit for building rich text WYSIWYG editors&lt;/li&gt;
&lt;li&gt;Firebase (Authentication + Firestore + Storage)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.algolia.com/" rel="noopener noreferrer"&gt;Algolia&lt;/a&gt; - Full text search&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Tauri, but Electronjs ?
&lt;/h2&gt;

&lt;p&gt;Before I discovered Tauri, I tried Electron.js, which was incredibly easy to use and develop with. However, the resulting app file size was massive, exceeding 500mb. This significant size prompted me to explore alternatives, ultimately leading me to Tauri.&lt;/p&gt;

&lt;p&gt;Tauri not only produces significantly smaller applications files compared to Electron.js (which relies on Node.js)but, it also leverages Rust for it's core functionality. After testing out, I was convinced it was the perfect choice for building this app.&lt;/p&gt;

&lt;h2&gt;
  
  
  What features did it have
&lt;/h2&gt;

&lt;p&gt;I initially thought I only needed a few basic features, but that turned out I was wrong. As development progressed, I kept coming up with new features I wanted to add. Let's take a look at what I ended up building.&lt;/p&gt;

&lt;h3&gt;
  
  
  Markdown support and Search
&lt;/h3&gt;

&lt;p&gt;As a developer, markdown was a must-have feature for the app. Next is the search function. Since Firestore doesn't support full-text search, I utilized Algolia for this functionality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fccp4nz0ix0hahuxb1g8u.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fccp4nz0ix0hahuxb1g8u.gif" alt="Markdown support"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Code highlight
&lt;/h3&gt;

&lt;p&gt;The second must-have feature was code highlighting. Because I take a lot of notes on code snippets, tutorials, and tech articles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Frbd4if02xwiyuhaxsi5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Frbd4if02xwiyuhaxsi5k.png" alt="code highlight"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Shortcuts
&lt;/h3&gt;

&lt;p&gt;Being a Neovim user, I dislike using the mouse while writing or coding. Therefore, shortcuts were the third essential feature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F018q453l6vdrzbgc0me7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F018q453l6vdrzbgc0me7.png" alt="shortcuts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Folder, Tags and Favorites
&lt;/h3&gt;

&lt;p&gt;This feature allows users to create folders, tags, and add notes to favorites for easy organization by category.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fwtmd4bte46jcb050v6fi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fwtmd4bte46jcb050v6fi.png" alt="Folder tag and favorites"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Word counting
&lt;/h3&gt;

&lt;p&gt;Sometimes I want to know how many words I've written and how long it would take to read the note. &lt;br&gt;
&lt;a href="https://media.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%2Faihuc5oxdudvzbjitfcp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Faihuc5oxdudvzbjitfcp.png" alt="Word counting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Theme collection
&lt;/h3&gt;

&lt;p&gt;A beautiful app motivates me to write. So, dark/light mode wasn't enough. It needed the ability to create and customize new themes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fzp5ra9hmmyefoy6xz2zp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fzp5ra9hmmyefoy6xz2zp.gif" alt="Theme customization"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Synced to Other devices
&lt;/h3&gt;

&lt;p&gt;Of course, it also syncs updates to other devices. Updating a note on the Windows app will immediately sync it to the Web app, thanks to Firebase Firestore. &lt;/p&gt;

&lt;p&gt;If it didn't sync, that would be a bug, not a feature! LOL &lt;/p&gt;

&lt;h3&gt;
  
  
  Support Windows, Linux, Macos, Web, PWA
&lt;/h3&gt;

&lt;p&gt;I use Windows and macOS at the office and Linux at home. So, the app had to be multi-platform. It might sound strange, but in the office, I use macOS for coding and Windows for a local server. Sometimes I use it for coding, sometimes not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto updates
&lt;/h3&gt;

&lt;p&gt;Whenever the app has new updates, a small circle icon appears on the bottom left sidebar. You can then choose to update or not.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F5rcogynk7zs1ts1kp0fb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5rcogynk7zs1ts1kp0fb.png" alt="Auto updates"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Content Encryption
&lt;/h3&gt;

&lt;p&gt;This feature encrypts your notes before saving them to the database. This makes your content difficult to read without your decryption code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fnm89juljt3omam6bmsnk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fnm89juljt3omam6bmsnk.png" alt="Cipher content"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to install
&lt;/h2&gt;

&lt;p&gt;To run the app on your specific operating system, you'll need to install Tauri and build the app yourself. My friend has written a detailed installation guide &lt;a href="https://github.com/hudy9x/kompad/tree/main/docs" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Please let me know if you encounter any issues with the guide or if it seems outdated.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Important Note: Configuring authentication and rules for Firebase requires some prior experience with the platform.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Building open-source projects hones my coding and writing. I'm excited to share this app! Feedback on the app or installation guide is highly appreciated. Stay tuned for more projects coming soon!&lt;/p&gt;

</description>
      <category>react</category>
      <category>tauri</category>
    </item>
    <item>
      <title>I built a free, open-source project manager that helps teams keep costs under $15/month.</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Sun, 19 May 2024 13:04:41 +0000</pubDate>
      <link>https://dev.to/hudy9x/i-built-a-free-open-source-project-manager-that-helps-teams-keep-costs-under-15month-3pmk</link>
      <guid>https://dev.to/hudy9x/i-built-a-free-open-source-project-manager-that-helps-teams-keep-costs-under-15month-3pmk</guid>
      <description>&lt;p&gt;Hi everyone, Hudy here! &lt;/p&gt;

&lt;p&gt;Today, I'm excited to share my open-source project manager with you all. I built this from the ground up with the goal of keeping operational costs under $15 per month.&lt;/p&gt;

&lt;p&gt;Before I deciding to build it, I tried Trello, Jira and Clickup. All of them are fantastic tools, but the cost was a major barrier for us. As a small team of 7 - 10 members at a Vietnamese startup, we simply didn't have the budget for these paid platforms.&lt;/p&gt;

&lt;p&gt;You might be wondering why we didn't just use the free tier. Here's the thing: I believed I could build a project manager that offered the specified features we needed, like Reports, Exporting capabilities, Boards, Calendars and more. &lt;/p&gt;

&lt;p&gt;Additionally, I had a significant amount of free time at that point, which made it a good opportunity to take on this project.&lt;/p&gt;

&lt;p&gt;I open-source this app on github: &lt;a href="https://github.com/hudy9x/namviek" rel="noopener noreferrer"&gt;https://github.com/hudy9x/namviek&lt;/a&gt; or you can check out the website &lt;a href="https://namviek.com" rel="noopener noreferrer"&gt;namviek.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is this for ?
&lt;/h2&gt;

&lt;p&gt;This project is a great fit for people with developer skills who are running a small team on a limited budget, similar to me. &lt;/p&gt;

&lt;p&gt;It might seen daunting at first, but see the cost report below. I was able to significantly reduce the operational cost from $49 per month ($7 x 7 member) to less than $10 per month.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F30fjxmx0fmmsuzc22cs7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F30fjxmx0fmmsuzc22cs7.png" alt="Amazon Cost"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How did I keep the cost low ?
&lt;/h2&gt;

&lt;p&gt;I leveraged a variety of free platforms to minimize operational costs. Here's a breakdown: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vercel: for the frontend  (Free)&lt;/li&gt;
&lt;li&gt;Aws Lightsail: for the backend (Paid)&lt;/li&gt;
&lt;li&gt;Aws S3: for file storage (Paid)&lt;/li&gt;
&lt;li&gt;Resend: sending email (Free)&lt;/li&gt;
&lt;li&gt;Cloudflare: to manage my domain (Free)&lt;/li&gt;
&lt;li&gt;Github Action: CD automation (Free)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Tech Stack
&lt;/h2&gt;

&lt;p&gt;To ensure fast building and deployment, I opted for Next.js on the frontend as it seamlessly integrates with Vercel. For the backend, I currently use Node.js, but I have plans to migrate some funtionalities to Golang in the comming future.  &lt;/p&gt;

&lt;h2&gt;
  
  
  What features are packed in ?
&lt;/h2&gt;

&lt;p&gt;As mentioned before, this app includes some essential features for a small team such as:&lt;/p&gt;

&lt;h3&gt;
  
  
  List view
&lt;/h3&gt;

&lt;p&gt;See it all at once. Prioritize and manage your tasks in a simple list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Faj75jb3vu9gl3nsppdy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Faj75jb3vu9gl3nsppdy0.png" alt="List view"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Board view
&lt;/h3&gt;

&lt;p&gt;Visualize your workflow. Move tasks between stages for clear progress tracking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F8p40vkwmxhmvtsq8bj2y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F8p40vkwmxhmvtsq8bj2y.png" alt="Board view"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Goal view
&lt;/h3&gt;

&lt;p&gt;Stay on target. See your progress at a glance and celebrate milestones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fn0uohpxfrshi5xwnhb1t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fn0uohpxfrshi5xwnhb1t.png" alt="Goal view"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Calendar view
&lt;/h3&gt;

&lt;p&gt;Plan your days. Never miss a deadline with tasks scheduled on your calendar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Frsndq9r27qszq3mvwo03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Frsndq9r27qszq3mvwo03.png" alt="Calendar view"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom view
&lt;/h3&gt;

&lt;p&gt;Work your way. Design the perfect view to fit your specific needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fzk24iwg5dzf43dgvg5t0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fzk24iwg5dzf43dgvg5t0.png" alt="View customization"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use it.
&lt;/h2&gt;

&lt;p&gt;Check out &lt;a href="https://www.namviek.com/#download" rel="noopener noreferrer"&gt;the setup guide&lt;/a&gt;. If you encounter any errors during the setup process, you can refer to the full guide &lt;a href="https://docs.namviek.com/doc/installation" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Maybe you prefer a step by step video guide? Check out this video below:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/3CS0DB4_2FU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Contribute your features or bug fixes
&lt;/h2&gt;

&lt;p&gt;This app is still under development, and I welcome your contributions to improve it! Feel free to submit feature requests and bug fixes. &lt;/p&gt;

&lt;p&gt;Want to suggest a better solution or a code base refactoring? Just create a pull request and I'd be happy to discuss it.&lt;/p&gt;

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

&lt;p&gt;Finally, I hope this open-source helps you and your team reduce operational costs while offering the opportunity to learn new skills by fixing bugs and building features. It will always be free to use. &lt;/p&gt;

&lt;p&gt;See you in the next open-source app :D&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>I built a simple keystroke application for Windows</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Sun, 30 Apr 2023 01:50:55 +0000</pubDate>
      <link>https://dev.to/hudy9x/i-built-a-simple-keystroke-application-for-windows-4nah</link>
      <guid>https://dev.to/hudy9x/i-built-a-simple-keystroke-application-for-windows-4nah</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hi friends, it's hudy here. In this tutorial, I'm so excited to show you how I built a keystroke application for Windows that inspired by KeyCastr. You guys maybe wondering why do I have to build a keystroke when there are numerous similar applications for Windows ? That's simply because I personally find their UI/UX to be too unappealing&lt;/p&gt;

&lt;p&gt;In this tutorial I just made a simplest version of it. So if you want to get full source code and guide, please visit the homepage below to download and access to my repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;p&gt;Here is the homepage and github repo: &lt;a href="https://hudy9x.github.io/keyreader/" rel="noopener noreferrer"&gt;https://hudy9x.github.io/keyreader/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to download, fork or contribute it&lt;/p&gt;

&lt;h2&gt;
  
  
  Video version
&lt;/h2&gt;

&lt;p&gt;I made a video version as well, you guys can watch it here&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=hhwjGIICLuA&amp;amp;t=10s" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=hhwjGIICLuA&amp;amp;t=10s&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;Well, I've used some tech for building this app&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Yarn&lt;/code&gt; or &lt;code&gt;Npm&lt;/code&gt; - I use yarn &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tauri.app/v1/guides/getting-started/prerequisites" rel="noopener noreferrer"&gt;Tauri&lt;/a&gt; - a toolkit for building desktop application&lt;/li&gt;
&lt;li&gt;Reactjs&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwindcss&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://crates.io/crates/rdev" rel="noopener noreferrer"&gt;rdev&lt;/a&gt; - a rust crate for listening keystroke event&lt;/li&gt;
&lt;li&gt;Typescript basic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure that you have &lt;code&gt;yarn&lt;/code&gt; and &lt;code&gt;tauri&lt;/code&gt; installed. Now, let's get started&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Open your terminal and create new Tauri project called &lt;code&gt;keyreader&lt;/code&gt;. The project use &lt;code&gt;react-ts&lt;/code&gt; - means Reactjs with typescript and yarn as a package manager&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;yarn create tauri-app keyreader &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts &lt;span class="nt"&gt;--manager&lt;/span&gt; yarn
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;keyreader
&lt;span class="nv"&gt;$ &lt;/span&gt;yarn
&lt;span class="nv"&gt;$ &lt;/span&gt;yarn tauri dev


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After running above commands (It'll take a few minutes). The following UI shown means we created Tauri app successfully&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fbis1w8g4b3pmdistjgey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fbis1w8g4b3pmdistjgey.png" alt="Tauri app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove redundant files in source base
&lt;/h3&gt;

&lt;p&gt;Just keep main files and remove redundant files. I just removed files inside &lt;code&gt;public&lt;/code&gt; and &lt;code&gt;src&lt;/code&gt; folder&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fsnpwdtojvdggnwirs5mm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fsnpwdtojvdggnwirs5mm.png" alt="Folder structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install tailwindcss (optional)
&lt;/h3&gt;

&lt;p&gt;I'd love to use tailwindcss for styling cuz it's so useful. But you guys don't need to. Please take a look at the installation instruction &lt;a href="https://tailwindcss.com/docs/guides/vite" rel="noopener noreferrer"&gt;here&lt;/a&gt; or follow the guide below&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; tailwindcss postcss autoprefixer
&lt;span class="nv"&gt;$ &lt;/span&gt;yarn tailwindcss init &lt;span class="nt"&gt;-p&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Add the paths to all of your template files in your &lt;code&gt;tailwind.config.js&lt;/code&gt; file.&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;/** @type {import('tailwindcss').Config} */&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="na"&gt;content&lt;/span&gt;&lt;span class="p"&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;./src/**/*.{js,ts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&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;plugins&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;Now, add the &lt;code&gt;@tailwind&lt;/code&gt; directives for each of Tailwind’s layers to your ./src/styles.css file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Open &lt;code&gt;src/App.tsx&lt;/code&gt; and add some class&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;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-red-400&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;world&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&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="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then run the app again, if text turn to red that means it works&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ yarn tauri dev


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.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%2F1eitkjwudhc95tjaik0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F1eitkjwudhc95tjaik0n.png" alt="Install tailwindcss"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Keystroke listener
&lt;/h3&gt;

&lt;p&gt;This is the core of our app. I'll create a &lt;code&gt;keyboard_listener.rs&lt;/code&gt; file for watching keystrokes that users typed. To do that, we use &lt;code&gt;rdev&lt;/code&gt; crate. &lt;/p&gt;

&lt;p&gt;Install crate by opening &lt;code&gt;src-tauri/Cargo.toml&lt;/code&gt; and add &lt;code&gt;rdev&lt;/code&gt; to &lt;code&gt;[dependencies]&lt;/code&gt; section&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;

&lt;span class="nn"&gt;[build-dependencies]&lt;/span&gt;
&lt;span class="py"&gt;tauri-build&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&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="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;span class="py"&gt;rdev&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.5.2"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Time to create the listener&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// ./src-tauri/src/keyboard_listener.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rdev&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;run_listener&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt;
    &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;'static&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="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&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="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&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="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="py"&gt;.name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Some: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Some"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="py"&gt;.event_type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nn"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;KeyPress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"KeyPress: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;key_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"KeyPress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;key_str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nn"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;KeyRelease&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;key_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"KeyRelease"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;key_str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nn"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MouseMove&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Ignore MouseMove event type&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// println!("None: {:?}", event.event_type);&lt;/span&gt;
                    &lt;span class="c1"&gt;// let event_type_str = format!("{:?}", event.event_type);&lt;/span&gt;
                    &lt;span class="c1"&gt;// emit(&amp;amp;event_type_str);&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="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The above script's simply using &lt;code&gt;listen&lt;/code&gt; method from &lt;code&gt;rdev&lt;/code&gt; to watch keystrokes. All aphabet characteres return in &lt;code&gt;Some&lt;/code&gt; event and the others like Ctrl, Alt, Caplocks, ... return in &lt;code&gt;None&lt;/code&gt;. So we've to read it by comparing &lt;code&gt;event.event_type&lt;/code&gt; with &lt;code&gt;EventType&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;One more thing, open &lt;code&gt;src-tauri/src/main.rs&lt;/code&gt; and use the listener&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// ./src-tauri/src/main.rs&lt;/span&gt;

&lt;span class="c1"&gt;// Prevents additional console window on Windows in release, DO NOT REMOVE!!&lt;/span&gt;
&lt;span class="nd"&gt;#![cfg_attr(not(debug_assertions),&lt;/span&gt; &lt;span class="nd"&gt;windows_subsystem&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"windows"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;

&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;keyboard_listener&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tauri&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Manager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;serde::Serialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Payload&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command&lt;/span&gt;
&lt;span class="nd"&gt;#[tauri::command]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, {}! You've been greeted from Rust!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tauri&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.invoke_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;tauri&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;generate_handler!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="nf"&gt;.setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;wv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="nf"&gt;.get_window&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nn"&gt;keyboard_listener&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;run_listener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&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="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wv&lt;/span&gt;&lt;span class="nf"&gt;.emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="s"&gt;"keypress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;Payload&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s1&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="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error while emitting event: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="nf"&gt;.run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;tauri&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;generate_context!&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error while running tauri application"&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;Run the app again and try to type something. If you got logs shown in terminal that means &lt;code&gt;rdev&lt;/code&gt; works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F8em6t5f2s1i4rfrbdtbh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F8em6t5f2s1i4rfrbdtbh.png" alt="Testing rdev"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Display keystroke on Reactjs
&lt;/h3&gt;

&lt;p&gt;For now, register a event listener on the view. Open &lt;code&gt;src/App.tsx&lt;/code&gt; and register a &lt;code&gt;keypress&lt;/code&gt; event as follow&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&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;listen&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;@tauri-apps/api/event&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;App&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;alphabeticKeys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAlphabeticKeys&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;NONE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&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="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keypress&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="nx"&gt;payload&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;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some&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;setAlphabeticKeys&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prevTickers&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;let&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&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;newTickers&lt;/span&gt; &lt;span class="o"&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;charCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&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="mi"&gt;0&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;charCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;␣&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="nx"&gt;newTickers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prevTickers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...[&lt;/span&gt;&lt;span class="nx"&gt;message&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;currLen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newTickers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nx"&gt;newTickers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currLen&lt;/span&gt; &lt;span class="o"&gt;&amp;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;newTickers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newTickers&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;newTickers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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="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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;tauri&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;drag&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-black&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; px-4 py-3 text-3xl text-white flex items-center gap-1 pointer-events-none&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;alphabeticKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&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;index&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;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;        &lt;span class="p"&gt;})}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;I use Inter font for fixing UX bug that make Esc character shorter than the others&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="c"&gt;/*.........*/&lt;/span&gt;

&lt;span class="k"&gt;@font-face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"Inter"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("/fonts/Inter-Regular.ttf")&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"truetype"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@font-face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"Inter"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("/fonts/Inter-Bold.ttf")&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"truetype"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Avenir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0f0f0f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nl"&gt;font-synthesis&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="nl"&gt;text-rendering&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;optimizeLegibility&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;-webkit-font-smoothing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;antialiased&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;-moz-osx-font-smoothing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grayscale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;-webkit-text-size-adjust&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;flex&lt;/span&gt; &lt;span class="err"&gt;items-center&lt;/span&gt; &lt;span class="err"&gt;justify-center&lt;/span&gt; &lt;span class="err"&gt;h-screen&lt;/span&gt; &lt;span class="err"&gt;overflow-hidden;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Re-run the app one more time. It's testing time guys&lt;/p&gt;

&lt;h3&gt;
  
  
  Make background transparent and hide titlebar
&lt;/h3&gt;

&lt;p&gt;Last thing to do for better UI is hiding titlebar and make the background transparent. It's so simple, just open &lt;code&gt;src-tauri/tauri.conf.json&lt;/code&gt; and add some config fields&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tauri"&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;"allowlist"&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="err"&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="err"&gt;For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;titlebar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;drag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;close&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="err"&gt;window&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"window"&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;"all"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"close"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hide"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"show"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"maximize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"minimize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"unmaximize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"unminimize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"startDragging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;"bundle"&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="err"&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="err"&gt;Rename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;app&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"identifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"com.keyreader.app"&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="err"&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;"windows"&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;"fullscreen"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"resizable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"KeyReader"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"width"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"height"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"decorations"&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="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="err"&gt;turn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;titlebar&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"transparent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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="err"&gt;make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;background&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;transparency&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;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;Wait for a few minutes to rebuild the app. And here is our result&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fkn1wbae1r6j0fxop6fow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fkn1wbae1r6j0fxop6fow.png" alt="result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Modifier keys
&lt;/h2&gt;

&lt;p&gt;Just now, I show you how to display alphabet keys. So what if modifier keys like Ctrl, Enter, Space, Alt, etc... ?&lt;/p&gt;

&lt;p&gt;You guys just use &lt;code&gt;mode&lt;/code&gt; variable for checking these keys. For examples.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keypress&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="nx"&gt;payload&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;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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;charCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&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="mi"&gt;0&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;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some&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="cm"&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;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;KeyPress&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ControlRight&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="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;⌃&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// update state&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;Still don't get it? Scroll to top and refer to my video or repo&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclution
&lt;/h2&gt;

&lt;p&gt;So far, I just show you how to listen keystrokes event from keyboard using &lt;code&gt;rdev&lt;/code&gt;. And send it to Tauri view by registering an event. Hope you guys learn something news about building desktop application using Reacjts and Tauri. &lt;/p&gt;

</description>
      <category>tauri</category>
      <category>react</category>
      <category>rust</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>How i setup my development env on Windows 11 for Web deverloper in 2023</title>
      <dc:creator>hudy9x</dc:creator>
      <pubDate>Sat, 31 Dec 2022 10:52:13 +0000</pubDate>
      <link>https://dev.to/hudy9x/how-to-setup-development-env-on-windows-11-for-web-deverloper-2if2</link>
      <guid>https://dev.to/hudy9x/how-to-setup-development-env-on-windows-11-for-web-deverloper-2if2</guid>
      <description>&lt;h2&gt;
  
  
  ⚒ Install 📺 Windows Terminal and Powershell from Microsoft Store
&lt;/h2&gt;

&lt;p&gt;Go to Microsoft Store, find “Windows Terminal“ and install it. Keep searching “Powershell“ in Microsoft Store and install it as well. Now, open the Windows Terminal and select default shell as Powershell that just installed.&lt;/p&gt;

&lt;p&gt;If Powershell not displayed in Window Terminal, please add new Profile and reload the terminal&lt;/p&gt;

&lt;h2&gt;
  
  
  🧩 Install choco
&lt;/h2&gt;

&lt;p&gt;Go to &lt;a href="https://chocolatey.org/install" rel="noopener noreferrer"&gt;https://chocolatey.org/install&lt;/a&gt; and find the following installation command. Run it in Powershell&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;Set-ExecutionPolicy Bypass &lt;span class="nt"&gt;-Scope&lt;/span&gt; Process &lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;System.Net.ServicePointManager]::SecurityProtocol &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;System.Net.ServicePointManager]::SecurityProtocol &lt;span class="nt"&gt;-bor&lt;/span&gt; 3072&lt;span class="p"&gt;;&lt;/span&gt; iex &lt;span class="o"&gt;((&lt;/span&gt;New-Object System.Net.WebClient&lt;span class="o"&gt;)&lt;/span&gt;.DownloadString&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://community.chocolatey.org/install.ps1'&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  🏀 Install Oh-my-posh, a prompt theme engine
&lt;/h2&gt;

&lt;p&gt;Open terminal and run the following command to install oh-my-posh&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;winget &lt;span class="nb"&gt;install &lt;/span&gt;JanDeDobbeleer.OhMyPosh &lt;span class="nt"&gt;-s&lt;/span&gt; winget


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After installation success, open Powershell profile by typing notepad $profile and paste below config inside it&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

clear
oh-my-posh init pwsh &lt;span class="nt"&gt;--config&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$env&lt;/span&gt;&lt;span class="s2"&gt;:POSH_THEMES_PATH/takuya.omp.json"&lt;/span&gt; | Invoke-Expression


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However, it’s not the end, in order to display oh-my-posh themes, we’ve got to install at least a Nerd Font. Go to &lt;a href="https://www.nerdfonts.com/font-downloads" rel="noopener noreferrer"&gt;https://www.nerdfonts.com/font-downloads&lt;/a&gt; and download one. For me, i chosen Caskaydia Cove Nerd Font.&lt;/p&gt;

&lt;p&gt;Extract font .zip file and select &lt;strong&gt;Caskaydia Cove Nerd Font Complete Mono Regular&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, restart powershell and enjoy the new terminal interface 😁&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚽ Install neovim
&lt;/h2&gt;

&lt;p&gt;For now, we only install it for editting purpose. I'll install packages at the last&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;winget &lt;span class="nb"&gt;install &lt;/span&gt;Neovim.Neovim


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Configure alias for starting neovim quickly&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;nvim &lt;span class="nv"&gt;$profile&lt;/span&gt;

// now, input the following &lt;span class="nb"&gt;command
&lt;/span&gt;Set-Alias &lt;span class="nt"&gt;-Name&lt;/span&gt; vim &lt;span class="nt"&gt;-Value&lt;/span&gt; nvim


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  🥎 Install scoop - package management for Windows
&lt;/h1&gt;

&lt;p&gt;I use &lt;code&gt;scoop&lt;/code&gt; for package management on windows. Because packages that installed by it does not require any system permission. So just type your package, and install it.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;irm get.scoop.sh | iex


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  🎲 Install git
&lt;/h1&gt;

&lt;p&gt;It's important tool for a developer 😁&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;scoop &lt;span class="nb"&gt;install &lt;/span&gt;git


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, we need to configure git alias for better performance&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.co checkout
&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.br branch
&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.ci commit
&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; alias.st status


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Adding an alias for git command. This step is optional&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;nvim &lt;span class="nv"&gt;$profile&lt;/span&gt;

// now, input the following &lt;span class="nb"&gt;command
&lt;/span&gt;Set-Alias &lt;span class="nt"&gt;-Name&lt;/span&gt; g &lt;span class="nt"&gt;-Value&lt;/span&gt; git


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Configure git ssh - go to another document&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"your@email.here"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Testing with git clone command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;git clone git@github.com:hudy9x/kompad-homepage.git


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  🎯 Install nvm vs nodejs
&lt;/h1&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;scoop &lt;span class="nb"&gt;install &lt;/span&gt;nvm
&lt;span class="nv"&gt;$ &lt;/span&gt;nvm &lt;span class="nb"&gt;install &lt;/span&gt;lts
&lt;span class="nv"&gt;$ &lt;/span&gt;nvm use lts


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  💊 Install yarn and python
&lt;/h1&gt;

&lt;p&gt;I personally love to use &lt;code&gt;yarn&lt;/code&gt; for nodejs package management&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;scoop &lt;span class="nb"&gt;install &lt;/span&gt;yarn
&lt;span class="nv"&gt;$ &lt;/span&gt;scoop &lt;span class="nb"&gt;install &lt;/span&gt;python // optional


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  🎹 Install ripgrep for searching tool
&lt;/h1&gt;

&lt;p&gt;This package only used for searching text, file. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;scoop &lt;span class="nb"&gt;install &lt;/span&gt;ripgrep


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Install Neovim plugins
&lt;/h1&gt;

&lt;p&gt;One thing to keep in mind that, this step does not walk you throught from the beginning of setting up a neovim workspace. I just install my Neovim plugins. So if you looking for a fully setup guide, maybe it's not for you.&lt;/p&gt;

&lt;p&gt;First, install &lt;code&gt;llvm&lt;/code&gt; that requires for nvim-treesitter on Windows&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;choco &lt;span class="nb"&gt;install &lt;/span&gt;llvm // run this &lt;span class="k"&gt;in &lt;/span&gt;Admin mode


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I user Packer for package management, install it&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://github.com/wbthomason/packer.nvim &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$env&lt;/span&gt;&lt;span class="s2"&gt;:LOCALAPPDATA&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;vim-data&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;ite&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="s2"&gt;ack&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="s2"&gt;acker&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;tart&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="s2"&gt;acker.nvim"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Alright, now clone my dotfiles that contains all my setup: &lt;a href="https://github.com/hudy9x/dotfiles" rel="noopener noreferrer"&gt;https://github.com/hudy9x/dotfiles&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://github.com/hudy9x/dotfiles.git


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And then, copy all files and folders inside &lt;code&gt;.config/nvim&lt;/code&gt; to your neovim's config folder. If you don't know where it is, open neovim and type the command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;nvim
// Neovim opened, &lt;span class="k"&gt;then &lt;/span&gt;pressing ESC and &lt;span class="nb"&gt;type&lt;/span&gt;
:echo stdpath&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'config'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The path outputed below is your neovim's config folder. Now, copy all config to there.&lt;br&gt;
&lt;a href="https://media.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%2Fih2g0j71t0zqq5t77z3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fih2g0j71t0zqq5t77z3k.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, open neovim and run the command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

:PackerInstall


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Wait for minutes, after the installation finished then we done&lt;/p&gt;

&lt;p&gt;However, if you got some errors about &lt;code&gt;:TSUpdate&lt;/code&gt; in the installation process. Just don't worry, close neovim and reopen it again. Neovim will re-run &lt;code&gt;:TSUpdate&lt;/code&gt; automatically, wait to this process done and check again. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Notice that, you should run &lt;code&gt;:TSUpdate&lt;/code&gt; with no file opened. Otherwise it might be cause some error as below&lt;br&gt;
&lt;a href="https://media.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%2F5v9ajdl2il7g53s0uykf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5v9ajdl2il7g53s0uykf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you still got another error, like me, it's about &lt;code&gt;tree-sitter/highlighter&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fpnujhhjieloeui0877ly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fpnujhhjieloeui0877ly.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then close neovim, reopen it and run the command &lt;code&gt;:TSUpdate vim&lt;/code&gt;. It might be fix that issue.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Hope this guide helps you to setup the workspace quickly. Thanks guys for taking your time to read this. See you in another post&lt;/p&gt;

</description>
      <category>neovim</category>
      <category>git</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
