/ src / content / projects / prawf.mdx
prawf.mdx
 1  ---
 2  title: Prawf
 3  date: 2022-02-19
 4  description: A Pauli Test Simulation app made with Web Component and RxJS
 5  source: https://github.com/elianiva/prawf
 6  type: personal
 7  featured: true
 8  stack:
 9      - ["Web Component", "https://developer.mozilla.org/en-US/docs/Web/Web_Components"]
10      - ["RxJS", "https://rxjs.dev/"]
11      - ["Typescript", "https://www.typescriptlang.org/"]
12  ---
13  
14  **Prawf** is a Pauli Test simulation app made with Web Component and RxJS. You can find the reason why I made this in [the project repo](https://github.com/elianiva/prawf)
15  
16  ## Web Component
17  
18  I chose Web Component because I want to try to experiment with it. I used it briefly in the past and I have no idea what I'm doing so I want to try to use it again.
19  
20  ## Styling
21  
22  I was going to use [Tailwind](https://tailwindcss.com/) but then I realised I use Web Component and I have no idea how to set it up. The second option is [Open Props](https://open-props.style/) but then I thought it's a bit overkill for what I'm doing.
23  
24  Since I don't use Web Component that much, there are probably some questionable things that I've done, and one of them is importing CSS as a string and then including it in the template.
25  
26  I imported the css string using `?inline` directive from Vite to import a file as a string. The result is... there are quite a lot of unnecessary whitespaces which makes the final HTML bigger. I'm sure I could _probably_ minify it, but it's fine for now.
27  
28  One of the things that I like from Web Component is component isolation; meaning that other component won't touch each other, they're isolated. This is good and bad, the good is I don't need to worry about accidentally touching other components, the bad is I duplicated a bunch of CSS because I couldn't use utility classes.
29  
30  Oh, I also added a darkmode with an animated toggle button because why not ツ It isn't persisted, though.
31  
32  ## Reactivity
33  
34  Making something Reactive is very easy thanks to RxJS. I don't think I struggle that much in this section. Again, I don't use RxJS that much so there is definitely room for improvement.
35  
36  For example, I re-render the entire component instead of modifying the node that I changed because I feel re-rendering the entire thing is a lot simpler and I don't think it slows my app.
37  
38  ## State Management
39  
40  I use Svelte quite a bit, so I tried to make `svelte/store`-style state management using RxJS Subject. Here's an example.
41  
42  ```typescript
43  export let currentTheme: Theme = "light";
44  export const currentTheme$ = new Subject<ThemeState>();
45  currentTheme$.subscribe(({ current }) => {
46  	currentTheme = current;
47  });
48  ```
49  
50  I use a variable to persist the last state because I couldn't find a way to "get" the last value from RxJS Subject.
51  
52  ## Routing
53  
54  I made a Subject to change the route. The way it works is actually pretty simple. Whenever I want to navigate to another page, I just need to emit a path as a string to the Subject and it will change the route using `history.pushState`.
55  
56  ## Chart
57  
58  I decided to build the chart myself instead of using a library since I only need two; which are lines and bars. I decided to make a smooth curved line. Thanks to [this post](https://francoisromain.medium.com/smooth-a-svg-path-with-cubic-bezier-curves-e37b49d46c74) that I found, I was able to make the chart.
59  
60  ## History and Countdown
61  
62  I used RxJS `interval` and `timer` for the countdown timer and just re-render every second. I used css transition for the top bar instead of re-rendering every time because I want it to animate smoothly when it gets shorter.
63  
64  For the game history, I just pushed an object to a Subject. I also have a `currentRound` Subject that keeps getting updated by an `interval` Observable which tracks the current round.
65  
66  ## Result Calculation
67  
68  The result is calculated from the correct answers, incorrect answers, the percentage of the correct answer, answers per round in average, and the standard deviation.
69  
70  I didn't know how to decide a smoother chart (consistent) is better than a jagged chart (inconsistent). Fortunately, people at [Teknologi Umum](https://t.me/teknologi_umum) pointed me in the right direction, which was to find the standard deviation. It's just simple math, apparently. I was expecting something more involved but no, it's just a quick formula that could be done in less than a minute.