# Montalesi.dev > Alberto Montalesi — software developer, author of The Complete Guide to Modern JavaScript, and builder of web and mobile apps. Alberto Montalesi is a software developer and author of *The Complete Guide to Modern JavaScript*. He writes about web development, JavaScript, and TypeScript, and builds web and mobile apps as well as browser games. # How to convert a string to camelCase in JavaScript Published: 2026-09-19T00:00:00.000Z Modified: 2026-09-19T00:00:00.000Z Category: article Tags: js, article Keywords: javascript camelcase, camelcase javascript, convert string to camel case javascript, js to camelcase, string to camelcase, tocamelcase javascript, camel case in javascript, javascript string to camelcase, reverse camel case, typescript camelcase type URL: https://montalesi.dev/blog/article/convert-string-to-camelcase-javascript Converting a string to camelCase sounds like a one-liner, and for the easy cases it is. The trouble starts when the input is not what you expected: `USER_NAME`, `XMLHttpRequest`, a stray leading dash, two delimiters in a row. This article covers both: the short version for when you control the input, and a version that holds up when you don't.   ## What camelCase actually is Four naming conventions turn up constantly, and it helps to name them precisely before writing code to convert between them: | Convention | Example | | --- | --- | | camelCase (lower camel case) | `theStealthWarrior` | | PascalCase (upper camel case) | `TheStealthWarrior` | | snake_case | `the_stealth_warrior` | | kebab-case | `the-stealth-warrior` | camelCase means: first word entirely lowercase, every following word capitalised, no separators. PascalCase is identical except the first word is capitalised too — which is why a lot of "camelCase" utilities actually produce one from the other with a single `Capitalize` step.   ## The one-line version If your input is reliably delimited by dashes, underscores or spaces, one `String.prototype.replace` call is enough: ```javascript function toCamelCase(str) { return str.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : '' ) } toCamelCase('the-stealth-warrior') // 'theStealthWarrior' toCamelCase('The_Stealth_Warrior') // 'TheStealthWarrior' ``` The regex does three things: - `[-_\s]+` matches a **run** of one or more dashes, underscores or whitespace characters. The `+` is what makes `foo--bar` work — without it the second dash would survive into the output. - `(.)?` optionally captures the character immediately after that run. It is optional so that a **trailing** delimiter (`'foo-'`) still matches and gets removed rather than being left behind. - The replacer uppercases the captured character, or returns an empty string when there was nothing after the delimiter. Note what this version does *not* do: it leaves the first character exactly as it found it. `'The_Stealth_Warrior'` comes back as `'TheStealthWarrior'`, PascalCase, not camelCase. That is the behaviour the [CodeWars kata](https://www.codewars.com/kata/517abf86da9663f1d2000003) asks for — I solved that one in [JS Challenge 6](/blog/challenge/challenge-6-string-to-camelcase) — but it is usually **not** what you want in application code. Force it: ```javascript function toCamelCase(str) { return str .replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : '')) .replace(/^./, (char) => char.toLowerCase()) } toCamelCase('The_Stealth_Warrior') // 'theStealthWarrior' ```   ## Where the one-liner breaks Feed it real-world input and the cracks show: ```javascript toCamelCase('USER_NAME') // 'uSERNAME' — wanted 'userName' toCamelCase('XMLHttpRequest') // 'xMLHttpRequest' — wanted 'xmlHttpRequest' ``` The problem is structural, not a bug in the regex. The one-liner only knows about **delimiters**. It has no concept of a *word*, so it cannot see that `USER_NAME` is two words, and it cannot see any word boundary at all in `XMLHttpRequest` because there are no delimiters to find.   ## The robust version: split into words first The fix is to stop thinking in terms of "replace the delimiters" and start thinking in terms of "find the words, then join them". This is the approach Lodash takes, and it is worth understanding rather than reaching straight for a dependency. ```javascript const WORD_PATTERN = /[A-Z]{2,}(?=[A-Z][a-z]+|\b)|[A-Z]?[a-z]+|[A-Z]+|\d+/g function toWords(input) { return String(input).match(WORD_PATTERN) ?? [] } function toCamelCase(input) { return toWords(input) .map((word, index) => index === 0 ? word.toLowerCase() : word[0].toUpperCase() + word.slice(1).toLowerCase() ) .join('') } ``` `WORD_PATTERN` is four alternatives, tried in order: - `[A-Z]{2,}(?=[A-Z][a-z]+|\b)` — an acronym. The lookahead is the clever part: it stops the match either at a proper capitalised word (so `XMLHttpRequest` splits as `XML` + `Http`, not `XMLH` + `ttp`) or at a word boundary (so `USER_NAME` splits as `USER` + `NAME`). - `[A-Z]?[a-z]+` — an ordinary word, with or without a leading capital. - `[A-Z]+` — a run of capitals nothing else claimed. - `\d+` — a run of digits, kept as its own word. Because it *matches* words rather than *replacing* separators, every delimiter, repeated or leading or trailing, is simply never matched and therefore never appears in the output. You get that for free. It handles the cases the one-liner could not: ```javascript toCamelCase('the-stealth-warrior') // 'theStealthWarrior' toCamelCase('The_Stealth_Warrior') // 'theStealthWarrior' toCamelCase('USER_NAME') // 'userName' toCamelCase('XMLHttpRequest') // 'xmlHttpRequest' toCamelCase('--leading--dashes--') // 'leadingDashes' toCamelCase(' spaced out ') // 'spacedOut' toCamelCase('hello world') // 'helloWorld' toCamelCase('user2Name') // 'user2Name' toCamelCase('foo_barBaz-QUX') // 'fooBarBazQux' toCamelCase('alreadyCamelCase') // 'alreadyCamelCase' toCamelCase('') // '' ``` That last pair matters in practice: running the function twice on the same string gives the same answer as running it once, so it is safe to apply to input that may already be camelCase.   ## Two limitations, stated honestly **Acronyms lose their capitalisation.** `getHTTPResponseCode` becomes `getHttpResponseCode`, not `getHTTPResponseCode`. This is deliberate — it is also what Lodash does — because preserving acronym casing makes the conversion non-reversible. If you need the original casing preserved, drop the `.toLowerCase()` on the tail of each word, and accept that `USER_NAME` will then give you `userNAME`. **It is ASCII-only.** `[A-Z]` and `[a-z]` do not match accented or non-Latin characters, so `toCamelCase('背景 color')` returns `'color'` — the non-Latin word is silently dropped. If you need Unicode, swap the character classes for Unicode property escapes and add the `u` flag: ```javascript const WORD_PATTERN = /\p{Lu}{2,}(?=\p{Lu}\p{Ll}+|\b)|\p{Lu}?\p{Ll}+|\p{Lu}+|\p{N}+/gu ``` Silently dropping characters is the kind of bug that surfaces months later in somebody else's locale, so it is worth deciding which of the two you want rather than inheriting the ASCII default by accident.   ## The other conversions Once you have `toWords`, every other case convention is a one-line join: ```javascript function toPascalCase(input) { return toWords(input) .map((word) => word[0].toUpperCase() + word.slice(1).toLowerCase()) .join('') } function toKebabCase(input) { return toWords(input).map((word) => word.toLowerCase()).join('-') } function toSnakeCase(input) { return toWords(input).map((word) => word.toLowerCase()).join('_') } toPascalCase('the-stealth-warrior') // 'TheStealthWarrior' toKebabCase('XMLHttpRequest') // 'xml-http-request' toSnakeCase('userName') // 'user_name' ``` `toKebabCase` and `toSnakeCase` are the "reverse camelCase" people usually mean — going from `userName` back to `user-name` or `user_name`. Because they share the same word splitter, they round-trip with `toCamelCase` reliably (subject to the acronym caveat above).   ## Do you need Lodash? If Lodash is already in your bundle, use it: ```javascript import camelCase from 'lodash/camelCase' camelCase('the-stealth-warrior') // 'theStealthWarrior' camelCase('USER_NAME') // 'userName' camelCase('XMLHttpRequest') // 'xmlHttpRequest' ``` [`_.camelCase`](https://lodash.com/docs/4.17.15#camelCase) is battle-tested and Unicode-aware, so it keeps the non-Latin word the ASCII version above drops: `_.camelCase('背景 color')` gives `'背景Color'`. Be aware that it also runs [`_.deburr`](https://lodash.com/docs/4.17.15#deburr) internally, which strips diacritics — `_.camelCase('café_au_lait')` returns `'cafeAuLait'`, not `'caféAuLait'`. That is usually what you want for a slug or an identifier, and occasionally a surprise. It also always lowercases the first word, so it cannot produce the PascalCase-preserving behaviour of the CodeWars kata — use `_.upperFirst(_.camelCase(str))` if you want PascalCase. If Lodash is *not* already there, importing it for this one function is not worth it. The word-splitting version above is fifteen lines and has no dependencies.   ## Doing it in the type system If you are converting object keys in TypeScript — an API that returns `snake_case` rows into a camelCase domain model, say — you want the types to follow the runtime conversion. Template literal types can do it: ```typescript type CamelCase = S extends `${infer Head}_${infer Tail}` ? `${Head}${Capitalize>}` : S extends `${infer Head}-${infer Tail}` ? `${Head}${Capitalize>}` : S type A = CamelCase<'the-stealth-warrior'> // 'theStealthWarrior' type B = CamelCase<'user_first_name'> // 'userFirstName' ``` `infer Head` is non-greedy, so it stops at the *first* delimiter, and the recursion handles the rest of the string. Combine it with a key remapping to convert a whole object type: ```typescript type CamelCaseKeys = { [K in keyof T as K extends string ? CamelCase : K]: T[K] } type Row = { user_id: number; created_at: string } type Model = CamelCaseKeys // { userId: number; createdAt: string } ``` This is type-level only — you still need the runtime function to actually transform the values. But it means the compiler catches a mismatch between your API schema and your domain model rather than leaving it to a runtime `undefined`.   ## Which one to use - **Input you control, simple delimiters** — the one-liner. It is short enough to inline and there is nothing to maintain. - **Input you don't control** — the word-splitting version. The acronym and repeated-delimiter cases will otherwise find you eventually. - **Lodash already in the bundle** — `_.camelCase`, and move on. - **Converting object keys in TypeScript** — the word-splitting version plus the `CamelCaseKeys` type, so the compiler stays in sync with the runtime. --- # Culture Drop: Using AI to Draft a Daily Reading App Without Letting It Publish Published: 2026-09-19T00:00:00.000Z Modified: 2026-09-19T00:00:00.000Z Category: article Tags: article, mobile app Keywords: culture drop, daily culture app, ai editorial pipeline, human in the loop content, expo react native app, daily art history app, local first mobile app URL: https://montalesi.dev/blog/article/culture-drop Culture Drop is a three-minute daily ritual: four editorial cards — an artwork, a history entry, a word or concept, and a curious fact — and a fifth card where you write a private reflection. No account, no feed to scroll, no streak shouting at you. A daily content app needs 365 items a year in four categories. I am one person. AI is the obvious way to make that volume tractable, and it is also the obvious way to end up shipping confident nonsense about a painting that does not exist. The interesting part of this project is the machinery I built to get the first without the second.   ## The rule: AI drafts, a person approves, the tooling enforces it The editorial flow is deliberately boring: 1. An AI brief drafts candidate days as structured JSON, given the existing titles, terms, events and facts so it avoids repeats. 2. **Every draft is checked by a person** against a fixed list: factual claims, event date, word count, source URL, image rights, duplicates. 3. Approved days are saved into the repository as `data/feed/YYYY-MM-DD.json`. The repository is the editorial source of truth. 4. A publish step mirrors images, rewrites their URLs, and uploads the validated JSON to object storage, where a Worker serves it. 5. A verify step checks that every public feed still matches the repository and that every referenced image is served from the app's own CDN. The load-bearing sentence, which I wrote into the project's own README so future-me could not talk himself out of it, is that **the AI draft is never publish-ready by itself**. That is a policy, and policies decay. So the parts that can be mechanical are mechanical.   ## Making the pipeline fail instead of degrade The failure mode I actually worried about was not a bad fact — it was the pipeline quietly doing something slightly wrong, forever, without telling me. Two specific cases got hard rules: **No image may be uploaded unoptimized.** The publisher requires the image tooling to be present on `PATH` and fails *before* uploading anything if it is not. Paintings are published as WebP with a 2400px maximum long edge at quality 88; history and fact images at 1600px and quality 82. The optimizer derives target dimensions from the source rather than forcing a box, and rejects any output whose aspect ratio drifts by more than 1% — because silently squashing a painting is exactly the kind of bug nobody files. **No feed may reference someone else's server.** Publishing fails outright if a feed entry still points at an external image URL. This one is about rights as much as reliability: an app that hotlinks artwork is both fragile and rude. The original file is kept as a backup, and exactly one stable optimized object is published per card. Both rules share a shape worth naming: *the unsafe path is not available*, as opposed to documented as discouraged. A dry-run mode lets me confirm every source can be mirrored before anything is written.   ## Everything personal stays on the device There is no account system and no user-data backend. Notes, saved cards and reading history live in on-device SQLite. The daily editorial JSON is public static content, so the app fetches only the date you are looking at, and falls back to a cached deck — then to a small bundled deck — when the network is unavailable. This is partly a privacy position and mostly a simplicity one. A reflection journal is the last thing that should sit in someone else's database, and not having accounts removes an enormous amount of product surface I would otherwise have to build, secure and support.   ## Stack Expo and React Native with Expo Router, `expo-sqlite` for local persistence, RevenueCat for purchases, and Sentry for error tracking. The feed is static JSON on Cloudflare R2 served through a Worker. Minimum iOS 16.4. Notably absent: an application server. The only backend is a CDN serving files that a build step produced from a folder of reviewed JSON in a git repository. For a content app with no social features, that is most of the operational burden gone.   ## What I would keep The generalisable lesson is not "use AI for content" — it is that if you do, the review step has to be **structurally impossible to skip**, not merely written down. A checklist in a README is a wish. A publisher that exits non-zero when the optimizer is missing, or when a feed still points at someone else's image, is a guarantee. I got that right for images and the publishing path. The human review of facts is still a policy rather than a mechanism, and it is the part most likely to erode on a tired evening — which is worth being honest about rather than presenting the whole thing as solved. You can read more about Culture Drop at culturedrop.montalesi.dev. --- # Why Greenland Looks Bigger Than Africa on a Mercator Map Published: 2026-08-03T00:00:00.000Z Modified: 2026-08-03T00:00:00.000Z Category: article Tags: article, webdev Keywords: map2maps, why does greenland look so big on the map, mercator projection distortion explained, compare map projections, true size of countries map, mapbox app URL: https://montalesi.dev/blog/article/map2maps-v2 Greenland is not the size of Africa. It is not even close: Africa is roughly fourteen times larger. If that surprises you, blame the map on your classroom wall. The Mercator projection preserves local angles and shapes, which made it useful for navigation. Its scale increases with latitude, though, so areas near the poles look far larger than they are. Africa is not made smaller on the map; Greenland is made much larger. Map2Maps lets you select a country or draw a shape, then compare the same geometry across several map projections. Map2Maps comparing the size of several countries against different locations ## What Map2Maps does - **Compare country sizes** by viewing the same country across up to four map projections - **Draw your own shapes** and polygons to compare arbitrary areas, not just national borders - **Save and share** comparisons when you want to show how a projection changes what a shape appears to be I built the first version in 2020 after having the same argument too many times. A Mercator map gives people a very particular picture of country size. Japan can look compact, while Greenland can look continental. Seeing the same region in a different projection makes the tradeoff obvious.
Japan shown across map projections to compare its apparent size Australia shown in a Map2Maps comparison
## From Angular to a modern stack: the v2 rebuild The version online today is a ground-up rebuild, not a patch on the original. | | v1 (2020) | v2 (2023) | | --- | --- | --- | | Frontend | Angular | Next.js + TypeScript | | Map rendering | LeafletJS | Mapbox GL JS | | Data | None persisted | PostgreSQL (saved maps, accounts) | | Payments | — | Paddle | The rebuild was not cosmetic. Mapbox GL made it practical to render several views at once, and the backend made saved and shared comparisons part of the product. The area of a country does not change between views. What changes is the projection used to place its coordinates on a flat surface. Map2Maps keeps the selected geometry and redraws it in each view, which makes the projection's effect visible without pretending that one projected outline is the country's literal size. ## Not everything here is AI-built I've written elsewhere on this blog about leaning on AI tools heavily for recent projects like ARCOLOGY and Battle Tanks, so it's worth being precise here: Map2Maps isn't one of those. The core of it was designed and hand-built across several years, long before AI-assisted coding was part of my workflow. Where AI has helped more recently is around the edges of the v2 codebase: cleanup passes, refactors, smaller feature work. A hand-built project with some AI help bolted on late in its life is a different story from an app built AI-first, and worth keeping separate rather than lumping together. This site itself moved off Vercel onto Cloudflare Workers this year, a much more recent and much more AI-assisted piece of work, written up here. Map2Maps is free to start using at map2maps.com, with premium features available. Compare a country or a shape in a few projections and the limits of the standard classroom map become much easier to see. --- # How I Make App Store Screenshots Without a Design Tool Published: 2026-07-30T00:00:00.000Z Modified: 2026-07-30T00:00:00.000Z Category: article Tags: article, webdev Keywords: appframer, app store screenshot sizes, free app store screenshot generator, device mockup generator, translate app store screenshots, app store screenshot generator no subscription URL: https://montalesi.dev/blog/article/appframer The App Store wants polished, captioned screenshots at exact pixel resolutions, in a device frame, ideally translated into a dozen-plus languages. Doing that by hand in a design tool, per screen, per device size, per language, is miserable, and for me it was consistently the thing standing between "app is done" and "app is actually submitted." AppFramer is the tool I built to make that step stop being miserable: a fully client-side generator that turns raw screenshots into App Store-ready assets in the browser. The screenshots below were all produced with AppFramer, for my own apps, including Yore and Valuta:
App Store screenshot generated for Yore App Store screenshot generated for Valuta Second App Store screenshot generated for Yore
## What AppFramer does I make a lot of small apps, and I didn't want to pay a subscription for a screenshot studio or leave the browser to use one. So AppFramer does exactly the thing I wanted: drop in raw screenshots, write a caption, pick a background, and get a folder of App Store-ready images out the other side. | Feature | Detail | | --- | --- | | Device mockups | Pure CSS frames for iPhone 6.7", iPhone 6.5", iPad 12.9", iPad 11" at the correct App Store resolutions | | Captions | Title + subtitle, independent font, size, color, and alignment per caption | | Fonts and layouts | 12 Google Fonts, 5 layout styles | | Backgrounds | Solid color or gradient, angle control, 8 presets | | Translation | Translate captions into up to 18 languages through a third-party translation service | | Project management | Bulk image upload, save/load the whole project as JSON | | Export | ZIP of every screen across every language, grouped into per-language folders | AppFramer has no account system or upload backend, and source screenshots stay in your browser. If you use translation, the caption text is sent to the translation service; the screenshots are not. ## Rendering to Canvas instead of capturing the DOM The part I'm happiest with is the export pipeline. Instead of reaching for a DOM-capture library, AppFramer draws each frame onto a Canvas at the exact target App Store resolution. That means the exported PNGs are pixel-precise to what Apple expects, rather than a screenshot of a screenshot with whatever rounding error the browser's rendering introduces. AppFramer is a **React 18 + Vite 5** app styled with **Tailwind**, using **JSZip** for the export bundle and **lucide-react** for icons. I used AI tools for the device dimensions, Canvas composition math, and export plumbing. The product decisions came from shipping apps such as Baby Book Tracker and Provato. The nicest proof is that I now use AppFramer for every app I release. It solved my own problem, which is the only reason I trusted it enough to put online at appframer.montalesi.dev. If you ship small apps and dread the screenshot step as much as I did, no account is needed to try it. --- # Designing a Simple Currency Conversion Calculator Published: 2026-07-26T00:00:00.000Z Modified: 2026-07-26T00:00:00.000Z Category: article Tags: article, mobile app Keywords: valuta, currency converter with calculator, offline currency converter iphone, no subscription currency app, currency converter without ads, currency calculator app URL: https://montalesi.dev/blog/article/valuta Every currency converter I tried made me leave the app to do basic arithmetic. I'd convert a price, then reach for the calculator to split it, add tax, or multiply it by a quantity, then come back and lose my place. Valuta puts the calculator and the conversion in the same screen, which turned out to be the entire feature that mattered. Valuta conversion screen ## What's in Valuta It is a deliberately small app. There is no finance dashboard or portfolio tracker, just a fast path from "what is this in my currency" to an answer you can use in a calculation. | Feature | What it does | | --- | --- | | Exchange rates | Fetches rates when connected and keeps the most recently retrieved rates for offline reference | | Calculator keypad | Arithmetic and conversion in one flow, no app-switching | | Saved currency pairs | Your most-used conversions are one tap away | | Pricing | One-time purchase, no account, no subscription |
Valuta saved currency pairs Valuta conversion screen in dark mode
## Works offline, stays private Valuta stores the most recently retrieved exchange rates locally. With no signal, it can still show those cached rates instead of failing outright. A cached rate may be out of date, so it is useful for a quick estimate, not a quote or financial decision. There's no account and no sign-up. Your settings and saved currency pairs are stored locally on your device and never sent to a server. It's a one-time purchase rather than another subscription, which felt like the right model for a utility this narrow. I used AI tools to accelerate the rate cache, calculator logic, and React Native UI. The calculator-first flow, local storage, and one-time purchase were product decisions. The screenshots above were made with AppFramer. Valuta is available now on iPhone at valuta.montalesi.dev, with an Android version in progress. If you've ever converted a price and immediately needed a calculator, that's the entire reason this app exists. --- # I Built One Place for Movies, Books, and Games Published: 2026-07-22T00:00:00.000Z Modified: 2026-07-22T00:00:00.000Z Category: article Tags: article, mobile app Keywords: yore, track movies books games in one app, media tracker app ios, local-first media diary, app to log what you watch read and play, media backlog tracker URL: https://montalesi.dev/blog/article/yore My media life used to be scattered across half a dozen apps: movies in one, books in another, a games backlog somewhere else, and a music history I never checked. Most trackers handle one kind of media. A film app does not know about your manga, and a book app has no idea you also play board games. Yore is my answer: a local-first iPhone app that treats movies, TV, anime, books, manga, games, music, podcasts, board games, and comics as one library while keeping the details for each format. Yore home screen ## What Yore tracks, and how For each item in your library, Yore lets you: - add it manually or import metadata from public services - track status, ratings, dates, progress, notes, and category-specific fields - log progress and completions over time - keep diary entries connected to a specific item when it's worth remembering - group related things into franchises and collections
Yore library screen Yore item detail screen
## The diary is the point A rating tells you what you thought of something. A diary entry tells you what was going on when you experienced it. That distinction is the part of Yore I care about most. Yore lets you attach diary entries to a specific item, so over time your library stops being a spreadsheet of scores and starts being an actual record: the game you finished on a long flight, the book you read during a hard month, the show you watched with someone else. Yore diary entry screen ## Metadata without accounts or API keys I didn't want Yore to depend on a paid metadata provider or force anyone to manage API keys, so it pulls covers, descriptions, release years, genres, and format-specific details from public sources that work without keys: | Media type | Source | | --- | --- | | Movies and games | Wikidata | | TV shows | TVmaze | | Anime and manga | Jikan (MyAnimeList data) | | Books | Open Library | | Music | iTunes Search API | You get a search box instead of manual data entry for most items, but you can always add or edit things by hand when a source is missing something. ## Local-first, by design The local SQLite database on your device is the source of truth for Yore. There is no required Yore account. If iCloud sync is enabled, it can keep the library available on your Apple devices. That is the same local-first approach I used for Provato and Baby Book Tracker. Under the hood, Yore is an Expo Router app with a local SQLite database and the no-key metadata sources above. I used AI coding tools for the initial scaffolding, metadata adapters, and parts of the data layer. The decision to keep every format in one library, give the diary its own place, and keep local data at the center was mine. Yore is available now on iPhone at yore.montalesi.dev (the App Store screenshots were made with AppFramer). If you've ever wanted one place for your whole media life instead of ten, that's exactly what this was built for. --- # A Browser Tank Game Inspired by Battle City Published: 2026-07-18T00:00:00.000Z Modified: 2026-07-18T00:00:00.000Z Category: article Tags: article, game Keywords: battle tanks, battle city remake browser, threejs tank game, browser game no download webgpu, local co-op browser game, roguelite browser shooter URL: https://montalesi.dev/blog/article/battle-tanks Battle Tanks takes the classic Battle City formula: drive a tank, blast bricks, defend a base, and destroy the enemy. It adds a modern roguelite power-up ladder in a full 3D low-poly browser game. There is no download, install, or lobby. Open a tab and you are in a tank. Battle Tanks gameplay: low-poly 3D tanks in a brick arena ## Fight through waves, gear up, take down the boss You survive escalating waves of enemy tanks across **12 hand-built arenas**, each with its own brick maze, water hazards, tree cover, or lava lake. The enemies aren't all the same either: grunts, snipers, splitters, shielded armor, and stationary bunkers all want you dead in different ways. Every fifth wave ends with a **boss fight** against the Titan, a scaled-up tank with twin heavy barrels and a pulsing weak-point core. Survive past the final arena and the level roster loops, with enemies returning with more health and damage each time.
Laser weapon cutting through a swarm of enemy tanks A multi-kill combo around the MOLTEN CORE lava lake The Titan boss tank at the end of a boss wave
## Stack your loadout Clear a wave, pick an upgrade, and those upgrades carry across the whole run and stack with each other: | Category | Upgrades | | --- | --- | | Weapons | Laser (pierces tanks and brick), Rocket (splash damage), Spread Gun (3-way fan) | | Offense | Ricochet, Homing Shots, Overcharge, Extra Bullet, Rapid Fire, Overdrive (kills briefly boost fire rate) | | Survival | Tough Armor, Extra Life, Ghost Plating, Adrenaline, Scrap Armor (kills heal you), Second Wind (cheat death once a wave) | | Utility | Speed Boost, Power Shot (breaks steel), Mines, Juggernaut (ram enemies for free damage) | A homing-laser build plays completely differently from a mines-and-juggernaut brawler, and that's the whole point: two runs shouldn't feel the same. ## Solo, or drop in a second player Battle Tanks has local 2-player co-op on the same keyboard, with shared upgrades and twin-stick chaos, plus touch controls so it works on mobile and tablet browsers. | Action | Player 1 | Player 2 | | --- | --- | --- | | Move | WASD | Arrow keys | | Shoot | Space | Enter | | Pause | Esc / P | — | ## The tech: Three.js, WebGPU, and a fixed-step simulation Battle Tanks is built with **Three.js (r171)**, running on **WebGPU** where the browser supports it and falling back to **WebGL** automatically. It is written in strict **TypeScript** with a fixed-step simulation loop. Like ARCOLOGY, the other Three.js game on this site, it has no backend and everything runs client-side. The fixed-step simulation was the detail that mattered most. With a lot of bullets, mines, and tanks on screen at once, you want game logic to run at a stable rate independent of frame rate, so a laptop and a phone play the same even when one is rendering far fewer frames. AI tools sped up the Three.js setup, WebGPU/WebGL fallback, enemy behaviors, and power-up wiring. The pacing of waves, boss timing, upgrade interactions, and endless-mode curve came from repeatedly playing the game until runs felt fair. That was the work that decided whether the game was worth finishing. It runs entirely in the browser. Play Battle Tanks with a friend in local co-op. --- # How I Balanced a City Builder with Run Exports Published: 2026-07-14T00:00:00.000Z Modified: 2026-07-14T00:00:00.000Z Category: article Tags: article, game Keywords: arcology, browser city builder no download, threejs city building game, balancing a game economy with data, cyberpunk city builder game, idle city builder browser URL: https://montalesi.dev/blog/article/arcology You don't play a mayor in ARCOLOGY. You play a district operator. Buildings generate credits, population, and data; infrastructure coverage throttles how much they actually produce; and three rival factions slowly push their meters around whether you like it or not. The long-term goal is to grow the district all the way up to the Arcology itself, a city-within-a-city megastructure that ends the campaign and unlocks endless play. It's a browser-based cyberpunk city builder made with Three.js, no download and no install. ARCOLOGY gameplay at night, with neon buildings, traffic, and weather ## Balancing the economy with exported run telemetry The single technique I'm proudest of in ARCOLOGY has nothing to do with graphics: I balanced the game's economy by exporting every run as JSON and tuning against the data, instead of guessing. The export records credits earned, faction meters over time, pressure spikes, and the point where a run collapsed. My balancing loop was simple: play a short run, export it, find the point where a faction meter ran away or the economy stalled, change a constant, then play again. It was not a replacement for playtesting. It gave me a way to check whether a frustrating run was a genuine balance problem or just one bad decision. ## What is in the game There's more content here than "browser game" usually implies. | System | Detail | | --- | --- | | Structures | 38, across four tiers: power/network infrastructure, residential, commercial, decorative | | Infrastructure simulation | Power, workforce, and bandwidth coverage; placement actually matters | | Factions | 3 (Corpos, Citizens, Syndicate), each can win or destroy your run if their meter hits 0 or 100 | | Story cards | 35 | | Timed city events | 12 | | Disaster types | 3 (fire, earthquake, flood) | | Persistence | Autosave plus JSON import/export | Under the surface, ARCOLOGY is a small economy simulation wrapped in a card game, built around three pressures that constantly pull against each other: - **Exploit vs sustain**: a profitable city still collapses if your citizens or factions spiral. - **Spend vs earn**: land, roads, upgrades, and infrastructure all compete for the same cash. - **React vs plan**: city events, disasters, and story cards keep interrupting whatever tidy build order you had in mind.
ARCOLOGY district during the day ARCOLOGY district at dusk
Every building you place is a small procedural Three.js mesh, and the preview art in the game's manual is rendered from those same in-game models, so the catalog always matches what you actually see on the map.
Shanty building Nightclub building Mega Corp Tower building The Arcology megastructure
## The stack, and where AI actually helped The stack is deliberately lightweight: **Three.js** for rendering, procedural building meshes, lighting, traffic, and weather; **Vite + TypeScript** for the dev server, build, and strict typing; vanilla ES modules with a small event bus instead of a runtime framework; **Vitest** for logic regression tests; **Biome** for formatting and linting. There is no backend. The entire simulation runs client-side, so it starts quickly and works offline once loaded, like Battle Tanks. I used AI coding tools for Three.js scaffolding, procedural mesh builders, and parts of the simulation. The three competing pressures, faction conditions, and balance decisions came from repeated playtests and the run exports. AI made the scope manageable; it did not make the game fun by itself. No download or install is required. Play ARCOLOGY or play it on itch.io. Reaching the Arcology megastructure ends the campaign; endless mode continues after that. --- # Remembering Which Coffee Shop (and Order) Was Actually Good Published: 2026-05-27T00:00:00.000Z Modified: 2026-05-27T00:00:00.000Z Category: article Tags: article, mobile app Keywords: provato, restaurant tracker app, track places you want to try, local-first iphone app no account, coffee shop journal app, wishlist app for restaurants URL: https://montalesi.dev/blog/article/provato I kept having the same small problem: I'd try a new coffee shop, order something I liked, and forget the useful details a few weeks later. Sometimes it was the place itself, sometimes it was the specific drink. Notes apps were too messy for that, spreadsheets were too much friction, and most tracking apps I tried were built for one narrow use case and broke down the moment I wanted something more flexible. Provato is the local-first iPhone app I built instead: save the experience first, add details only when they matter, and let the history become useful over time. Provato home screen ## What Provato does I wanted one place where I could log something I tried in a few taps, keep repeat visits connected to the same place, save wishlist ideas for later, and add notes, ratings, dates, prices, photos, tags, and locations when they were actually useful. That combination turned out to be the important part: I mainly wanted this for coffee shops and repeat orders, but it needed to work for restaurants and similar places too, without forcing a rigid format. Provato is built around that log-first workflow. Instead of making you build a detailed library upfront, it starts from the thing you want to remember right now, and builds a timeline that gets more useful every time you come back to it. - `Logs`: save the real experience first - `Library`: keep all tracked items in one place - `Wishlist`: store things you want to try later - `Stats and filters`: review patterns once your history grows Provato library screen In practice that covers restaurants and coffee shops, casual places worth revisiting, and specific drinks or dishes worth ordering again.
Provato add log screen Provato stats screen
## Why the history matters more on the second visit The second or third visit to a place is often more interesting than the first, which is the useful part of keeping a history at all. If you go back to the same cafe or restaurant, Provato keeps those entries together instead of scattering them across unrelated notes, so it's easy to compare what changed, what was worth repeating, and what probably wasn't. A one-off note reminds you that something happened; a timeline shows you a pattern. ## Local-first, no accounts, no tracking Provato is local-first by design. You do not need a Provato account, there are no ads, and there are no third-party analytics SDKs in the app. Your library stays on your device and can sync through iCloud when available. Photos, camera access, and location are optional, so you only enable the context you want. It is the same local-first approach behind Yore and Baby Book Tracker: the data is personal, and it should stay on your device by default. Provato is available on iPhone: download it from the App Store. It starts free with up to five items, with a one-time upgrade for unlimited items instead of a subscription. Screenshots, a feature breakdown, and an FAQ are at provato.montalesi.dev. --- # Why I moved this blog from Vercel to Cloudflare Workers Published: 2026-04-22T00:00:00.000Z Modified: 2026-04-22T00:00:00.000Z Category: article Tags: article, nextjs, cloudflare Keywords: cloudflare workers, vercel to cloudflare workers migration, opennext cloudflare nextjs, contentlayer alternative velite, vercel pricing too expensive, vercel security incident 2026 URL: https://montalesi.dev/blog/article/vercel-to-cloudflare-workers
This article was written with AI assistance (Claude Sonnet 4.6).
I migrated this blog off Vercel this week. Here is what pushed me to do it and how the technical side went. ## The trigger: Vercel's April 2026 security incident On April 19, Vercel disclosed a security incident. According to Vercel's bulletin, the incident originated with a compromise of Context.ai, a third-party AI tool used by a Vercel employee. That access was then used to take over the employee's Vercel Google Workspace account, which enabled access to some Vercel environments and environment variables that were not marked as sensitive. Vercel said a limited subset of customers had non-sensitive environment variables compromised and recommended rotating exposed credentials immediately. None of this was catastrophic for a small personal blog. But it was enough to finally do something about a problem I had been putting off: the cost. ## The cost problem Vercel is genuinely good for developer experience. But the pricing gets uncomfortable fast for personal projects with unpredictable traffic. The Hobby plan has bandwidth and function invocation limits that are easy to hit if a post picks up any traction. The Pro tier is $20/month, and useful things like log drains and more granular analytics are either locked behind paid tiers or charged separately on top. For this site's traffic, Cloudflare Workers has been inexpensive. The free tier allows 100,000 Worker requests per day, while the paid plan has a $5 monthly minimum and includes 10 million requests per month before request overages. Check the current limits and estimate your own dynamic traffic, especially if the site uses Worker bindings or server rendering. ## Also: Contentlayer was dead The site had been using Contentlayer for MDX processing. The project has been unmaintained for a while. The main repo went quiet and the community fork (contentlayer2) was barely keeping pace with Next.js. I was already looking at replacing it. So the migration was really two things at once: swap the runtime from Vercel to Cloudflare, and replace Contentlayer with Velite. ## The new stack - **Velite** for content and MDX processing - **OpenNext Cloudflare** (`@opennextjs/cloudflare`) to adapt the Next.js build output for the Workers runtime - **Wrangler** for deployment The site is still a Next.js app. OpenNext does the work of making that compatible with Cloudflare's environment. ## Replacing Contentlayer with Velite Contentlayer used "document types" with computed fields to define your content schema. Velite has a similar concept but uses a Zod-style schema API and is actively maintained.
**Before (Contentlayer):** ```ts // contentlayer.config.ts const computedFields: ComputedFields = { readingTime: { type: 'json', resolve: (doc) => readingTime(doc.body.raw) }, slug: { type: 'string', resolve: (doc) => doc._raw.flattenedPath.replace(/^.+?(\/)/, ''), }, toc: { type: 'string', resolve: (doc) => extractTocHeadings(doc.body.raw) }, } export const Blog = defineDocumentType(() => ({ name: 'Blog', filePathPattern: 'blog/**/*.mdx', contentType: 'mdx', fields: { title: { type: 'string', required: true }, date: { type: 'date', required: true }, tags: { type: 'list', of: { type: 'string' }, default: [] }, // ... }, computedFields, })) ```
**After (Velite):** ```ts // velite.config.ts const allBlogs = defineCollection({ name: 'Blog', pattern: 'blog/**/*.mdx', schema: s .object({ title: s.string(), date: s.isodate(), tags: s.array(s.string()).default([]), rawContent: s.raw(), path: s.path(), body: s.mdx(), // ... }) .transform(async (data) => { const { rawContent, ...rest } = data; return { ...rest, body: renderCompiledMdxToHtml(rest.body), slug: rest.path.replace(/^[^/]+\//, ''), readingTime: readingTime(rawContent), toc: await extractTocHeadings(rawContent), }; }), }); ```
One difference worth noting: Velite compiles MDX to a code string rather than a React component. I had to write a small helper to turn that into static HTML at build time: ```ts // data/mdx-to-html.ts export function renderCompiledMdxToHtml(code: string) { const fn = new Function(code) as (runtime: typeof jsxRuntime) => CompiledMdxModule; const MDXContent = fn(jsxRuntime).default; return renderToStaticMarkup( createElement(MDXContent, { components: mdxComponents }) ); } ``` This runs during the build. The output is plain HTML strings, which is what gets stored and eventually served. ## Wiring Velite into the webpack build Velite needs to run before Next.js compiles. The way to do that is a small webpack plugin: ```js // next.config.js class VeliteWebpackPlugin { static started = false; apply(compiler) { compiler.hooks.beforeCompile.tapPromise('VeliteWebpackPlugin', async () => { if (VeliteWebpackPlugin.started) return; VeliteWebpackPlugin.started = true; const dev = compiler.options.mode === 'development'; const { build } = await import('velite'); await build({ watch: dev, logLevel: 'warn' }); }); } } ``` The `static started` flag prevents duplicate builds during hot reloads in dev mode. ## OpenNext config There isn't much to configure in `open-next.config.ts`: ```ts import { defineCloudflareConfig } from "@opennextjs/cloudflare"; const config = defineCloudflareConfig({ // R2 incremental cache is available but not enabled here }); export default { ...config, buildCommand: "npm run build:next", }; ``` And the Wrangler config (with domain-specific values anonymized): ```jsonc { "main": ".open-next/worker.js", "name": "my-blog-worker", "compatibility_date": "2026-04-18", "compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"], "assets": { "directory": ".open-next/assets", "binding": "ASSETS" }, "services": [ { "binding": "WORKER_SELF_REFERENCE", "service": "my-blog-worker" } ], "images": { "binding": "IMAGES" } } ``` The `WORKER_SELF_REFERENCE` service binding is used by OpenNext for caching. The `IMAGES` binding wires up Cloudflare's image optimization. ## Build scripts The build pipeline changed to put OpenNext in front: ```json { "build": "opennextjs-cloudflare build", "build:next": "cross-env INIT_CWD=$PWD next build && node ./scripts/postbuild.mjs", "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy", "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview" } ``` `opennextjs-cloudflare build` calls `build:next` internally, then wraps the output for the Workers runtime. Having `build:next` as a separate named script is what makes the `buildCommand` in `open-next.config.ts` work. ## Dev mode emulation OpenNext needs one extra line to emulate Cloudflare bindings locally during `next dev`: ```js // next.config.js if (process.env.NODE_ENV === 'development') { import('@opennextjs/cloudflare').then((m) => m.initOpenNextCloudflareForDev()); } ``` Without it, `ASSETS` and `IMAGES` bindings are not available and things break in local development. ## How long did it take? The migration took most of a weekend. The majority of that time went into Velite, specifically understanding how it handles MDX differently from Contentlayer and getting the HTML rendering helper right. Once that clicked, the Cloudflare side was straightforward. The migration itself was done entirely with AI, using Claude Sonnet 4.6 and Codex 5.4. I mostly guided the process and reviewed the output rather than writing the config files by hand. It was the same heavy-AI workflow used for recent projects such as ARCOLOGY, Battle Tanks, and Yore, applied to infrastructure rather than a product. ## Performance This migration did not include a controlled before-and-after benchmark, so I would not treat it as proof that Cloudflare is faster than Vercel. This blog is mostly static and cacheable, which makes it a good fit for the Workers deployment model. Measure your own routes, regions, cache behavior, and image pipeline before using performance as a reason to migrate. ## Cost and security At this site's current usage, the cost is close to zero. Moving providers does not remove third-party or account-compromise risk; it changes the platform and operational model. The incident was a prompt to review credentials, access controls, deployment protection, and how much I wanted to depend on a single provider. ## Should you do it? There are still rough edges in the OpenNext Cloudflare adapter. It's moving fast and some Next.js features aren't fully supported yet. For a content-heavy blog without heavy server-side logic it works well, but I'd check the compatibility matrix before going this route with something more complex. If you're running a Next.js site on Vercel and the April breach made you think harder about your platform dependencies, or you're just watching the billing go up, the OpenNext route is worth a look. The main cost is one weekend and some patience with Velite's documentation. This blog was the easy case: a mostly static site with no complex server-side logic. I'm also in the process of moving my other, larger projects off Vercel, and that migration is a different story. I'll write that up as a part two once it's done. --- # I Built Baby Book Tracker for Our Reading Routine Published: 2026-02-10T00:00:00.000Z Modified: 2026-02-10T00:00:00.000Z Category: article Tags: article, mobile app Keywords: baby book tracker, reading log app for kids, 1000 books before kindergarten tracker, shared reading tracker for caregivers, baby reading habit app, story time tracker ios URL: https://montalesi.dev/blog/article/baby-book-tracker I got into the 1000 Books Before Kindergarten project and wanted a simple app to track the books I read to my kid. None of the options I tried felt right for that specific use case: routines get messy, multiple people may read to the same child, and it is easy to lose track of what happened when. Baby Book Tracker is what I built instead. Open the app, log a reading session in a few taps, and move on with your day. Baby Book Tracker home screen ## What's in the app I wanted something calm and lightweight where you can create profiles for one or more children, manage a shared library of books, log who read what, when, and in which language, and see progress over time without spreadsheets or notes apps. The app focuses on a few core screens instead of trying to do everything: Books library screen - `Home`: quick overview of your reading activity - `Books`: add and organize your library - `History`: browse past sessions by date - `Stats`: see streaks, top books, and per-baby breakdowns
Reading history screen Statistics screen
It also supports collaborators, so parents, grandparents, or caregivers can contribute to the same reading log. The app starts free, with a limited number of books you can create, and offers a one-time unlock for full access instead of a subscription. ## Private by default One important choice was to keep things private by default: you can use the app without creating an account, and your data stays on your device or in iCloud if you enable backups. It is the same local-first, no-account approach I used for Provato and Yore. None of these apps need your data to leave your phone to be useful. Baby Book Tracker is currently available on iOS: download on the App Store. Screenshots, a feature breakdown, and the roadmap are at babybooktracker.montalesi.dev. --- # JS Challenge 7: Multiples of 3 or 5 Published: 2020-10-28T00:00:00.000Z Modified: 2020-10-28T00:00:00.000Z Category: challenge Tags: challenge Keywords: javascript, codewars, javascript challenge, coding problem, javascript multiples, javascript multiples of 3 and 5, javascript multiples codewards URL: https://montalesi.dev/blog/challenge/challenge-7-multiples-of-3-and-5   In this article we will solve together the _Multiples of 3 or 5_ challenge from CodeWars, you can find it at this [link](https://www.codewars.com/kata/514b92a657cdc65150000006). The difficulty of this challenge is easy. Let's read the task together: > If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. > > Finish the solution so that it returns the sum of all the multiples of 3 or 5 below the number passed in. > > Note: If the number is a multiple of both 3 and 5, only count it once. Also, if a number is negative, return 0(for languages that do have them) This challenge is very simple and we can achieve the expected result using the remainder operator (`%`).   ## The remainder operator What this oparator does is is return the remainder left over when one operand is divided by a second operand. Let's look at some examples: ```JS 6%3; // 0 6%2; // 0 6%4; // 2 6%5; // 1 6%7; // 6 ``` Let's go over each example: 1. 6%3 = 0 because 3 \* 2 = 6 with no remainder; 2. 6%2 = 0 because 2 \* 3 = 6 with no remainder; 3. 6%4 = 2 because 4 \* 1 = 4 with 2 remainder; 4. 6%5 = 1 because 5 \* 1 = 5 with 1 remainder; 5. 6%7 = 6 because 6 \* 0 = 0 with 6 remainder; Knowing this, we can easily determine if a number is a multiple of 3 or 5 and then perform the sum we need;   ## Working on the solution ```JS function solution(number){ let sum = 0; for (var i = 0; i < number; i++) { if (i % 3 === 0 || i % 5 === 0) { sum += i; } } return sum; } ``` 1. first we initialise our `sum` variable that will hold the total sum of numbers 2. then we iterate over all the numbers, getting only the one perfectly divisible by 3 or 5, using the `%` (remainder) operator that we saw above 3. lastly we return the sum of all the numbers that match our condition There are many other ways of solving this problem, let me know yours in the comment. If you liked this type of content, please let me know in the comments and I'll create more of these. --- # JS Challenge 6: Convert string to camel case Published: 2020-10-25T00:00:00.000Z Modified: 2020-10-25T00:00:00.000Z Category: challenge Tags: challenge Keywords: javascript, codewars, javascript challenge, coding problem, javascript string to camelcase, javascript camelcase, javascript camelcase codewards URL: https://montalesi.dev/blog/challenge/challenge-6-string-to-camelcase   In this article we will solve together the _Convert string to camel case_ challenge from CodeWars, you can find it at this [link](https://www.codewars.com/kata/517abf86da9663f1d2000003). The difficulty of this challenge is easy. Let's read the task together: > Complete the method/function so that it converts dash/underscore delimited words into camel casing. The first word within the output should be capitalized only if the original word was capitalized (known as Upper Camel Case, also often referred to as Pascal case). > > Examples > toCamelCase("the-stealth-warrior") // returns >"theStealthWarrior" > > toCamelCase("The_Stealth_Warrior") // returns "TheStealthWarrior" The easiest way to solve this challenge will be with RegEx and we don't even need a complicate one in this case:   ## Write the RegExp `/[-_]\w/ig` this is all we need. - [-_] will match all the underscore and dashes - \w will match any character right after a dash or underscore - /ig will perform a **g**lobal case **i**nsesitive search. The trick that will help us complete the challenge more easily is the `\w` which allows us to capture the letter right after a dash or underscore, meaning we can easily make it uppercase in one go. When you want to play around with RegEx, this is a great playground that also explains how they work [regexr.com](https://regexr.com/). Now that we have the most important piece of our function, let's try and build a function around it. ```JS function toCamelCase(str){ const regExp = /[-_]\w/ig; return str.replace(regExp,(match) => { console.log(match); }); } toCamelCase("the-stealth-warrior") // -s // -w ``` `String.replace()` can take not only a substring but only a RegExp as the first parameter and will pass the result in the second one. As you can see our RexExp matched each dash and the first character after. ## Completing the function Now what we are left to do with the function is to return only the uppercase letter without the dash or underscore. ```JS function toCamelCase(str){ const regExp = /[-_]\w/ig; return str.replace(regExp,(match) => { return match[1].toUpperCase() }); } toCamelCase("the-stealth-warrior") ``` That's it, the last line we added will return **S** instead of **-s** and **W** instead of **-w**. There are many other ways of solving this problem, let me know yours in the comment. The solution above deliberately matches what the kata asks for, which means it preserves the case of the first letter and only knows about dashes and underscores. If you need something that holds up against real-world input — `USER_NAME`, `XMLHttpRequest`, repeated delimiters — I wrote a fuller reference in [How to convert a string to camelCase in JavaScript](/blog/article/convert-string-to-camelcase-javascript), which also covers the reverse conversions and a TypeScript type that does it at the type level. If you liked this type of content, please let me know in the comments and I'll create more of these. --- # JS Challenge 5: Pete the baker Published: 2020-10-15T00:00:00.000Z Modified: 2020-10-15T00:00:00.000Z Category: challenge Tags: challenge Keywords: URL: https://montalesi.dev/blog/challenge/challenge-5-pete-the-baker   In this article we will solve together the _Pete the baker_ challenge from CodeWars, you can find it at this [link](https://www.codewars.com/kata/525c65e51bf619685c000059). The difficulty of this challenge is medium. Let's read the task together: > Pete likes to bake some cakes. He has some recipes and ingredients. Unfortunately, he is not good at maths. Can you help him to find out, how many cakes he could bake considering his recipes? > Write a function cakes(), which takes the recipe (object) and the available ingredients (also an object) and returns the maximum number of cakes Pete can bake (integer). For simplicity, there are no units for the amounts (e.g. 1 lb of flour or 200 g of sugar are simply 1 or 200). Ingredients that are not present in the objects, can be considered as 0. > > Examples: > // must return 2 > `cakes({flour: 500, sugar: 200, eggs: 1}, {flour: 1200, sugar: 1200, eggs: 5, milk: 200});` > // must return 0 > `cakes({apples: 3, flour: 300, sugar: 150, milk: 100, oil: 100}, {sugar: 500, flour: 2000, milk: 2000});` We can solve this problem in many ways but the logic behind it is simply to iterate over the keys in our Object, calculate for how many cakes an ingredient can be used, and then simply return the lowest number we got for any ingredient. ## First method - For In Let's try to solve it using a `for..in` loop. ```JS function cakes(recipe, available) { let maxCakes; for(var ingredient in recipe){ } } ``` This is the skeleton of our loop, as you can see I've initialized a variable `maxCakes` that will keep track of how many cakes we can make. Let's continue the loop: ```js function cakes(recipe, available) { let maxCakes for (var ingredient in recipe) { if (available[ingredient]) { const possibleCakes = Math.floor(available[ingredient] / recipe[ingredient] || 0) if (!maxCakes || possibleCakes < maxCakes) { maxCakes = possibleCakes } } else { return 0 } } return maxCakes } ``` To recap: - we iterate over each ingredient in the recipe - we first check if we have that ingredient, if we don't we return 0 as we will not be able to make any cake with a missing ingredient - if we have the ingredient we calculate how many cakes we can create and we round it down to the lowest integer with `Math.floor` - if `maxCakes` is `undefined` (meaning it's the first iteration we make) or if the amount of possible cakes that this ingredient can provide us is less than the amount we calculated for another ingredient we update the value of `maxCakes` There you have it, this is a simple solution using a `for..in` loop, let's try one more time with a `reduce` method.   ## Second method - Reduce The logic behind this solution is the same as before, just the syntax will be maybe a bit harder to read at first but more concise. ```js function cakes(recipe, available) { return Object.keys(recipe).reduce(function (val, ingredient) { console.log(val) console.log(ingredient) return Infinity }, Infinity) } cakes({ flour: 500, sugar: 200, eggs: 1 }, { flour: 1200, sugar: 1200, eggs: 5, milk: 200 }) ``` In this implementation we are calling `reduce` on the `Array` of keys of our recipe `Object`, passing `Infinity` as the first value. We do that because we don't know what's gonna be the max value in any of our ingredients so we need to play safe and use that instead. If you try running the code above you will see this output: ```javascript Infinity flour Infinity sugar Infinity eggs ``` We don't want to return `Infinity`, what we want is to return the lowest possible number of cakes possible to make, and to do that we can change our function to look like this: ```js function cakes(recipe, available) { return Object.keys(recipe).reduce(function (val, ingredient) { return Math.min(Math.floor(available[ingredient] / recipe[ingredient] || 0), val) }, Infinity) } cakes({ flour: 500, sugar: 200, eggs: 1 }, { flour: 1200, sugar: 1200, eggs: 5, milk: 200 }) ``` What we changed is this line: ```js return Math.min(Math.floor(available[ingredient] / recipe[ingredient] || 0), val) ``` What this does is get the minimum (`Math.min`) between the current number of cakes that we can make with this current ingredient (`Math.floor(available[ingredient] / recipe[ingredient] || 0`) or the value returned by the previous iteration that we are passing via the `val` variable. At the first iteration, `val` is `Infinity` so any value will override it, whether it's a positive value or just 0. There you have it, a more concise function that does the same as the first solution we adopted. There are many other ways of solving this problem, let me know yours in the comment. If you liked this type of content, please let me know in the comments and I'll create more of these. --- --- # JS Challenge 4: Who Likes it? Published: 2020-10-12T00:00:00.000Z Modified: 2020-10-12T00:00:00.000Z Category: challenge Tags: challenge Keywords: javascript, codewars, javascript challenge, coding problem, javascript who likes it, who likes it codewars URL: https://montalesi.dev/blog/challenge/challenge-4-who-likes-it   In this article we will solve together the _Who Likes It_ challenge from CodeWars, you can find it at this [link](https://www.codewars.com/kata/5266876b8f4bf2da9b000362). The difficulty of this challenge is easy. Let's read the task together: > You probably know the "like" system from Facebook and other pages. People can "like" blog posts, pictures or other items. We want to create the text that should be displayed next to such an item. > > Implement a function likes :: [String] -> String, which must take in input array, containing the names of people who like an item. It must return the display text as shown in the examples: > > ```JS > likes [] -- must be "no one likes this" > likes ["Peter"] -- must be "Peter likes this" > likes ["Jacob", "Alex"] -- must be "Jacob and Alex like this" > likes ["Max", "John", "Mark"] -- must be "Max, John and Mark like this" > likes ["Alex", "Jacob", "Mark", "Max"] -- must be "Alex, Jacob and 2 others like this" > ``` > > For 4 or more names, the number in and 2 others simply increases. This challenge is a bit easier than the previous one we looked at and it shouldn't take us much to solve. First, we'll try to solve it the conventional way, then I'll show you how we can approach it with one of the new features of ES2021. ## Complete the challenge using a Switch statement For this challenge we will use a `switch` statement an for each case we will return the requested string. Let's start like this: ```js function likes(names) { names = names || [] switch (names.length) { case 0: return 'no one likes this' break } } ``` We initialized our simple function and in the first line we ensure that `names` exist, otherwise, we transform it into an empty `Array`. We then start our `switch` statement using the length of the `names` `Array` as our cases. The first one is very straightforward, for the second one onwards we will make use of string interpolation. ```js function likes(names) { names = names || [] switch (names.length) { case 0: return 'no one likes this' case 1: return `${names[0]} likes this` case 2: return `${names[0]} and ${names[1]} like this` case 3: return `${names[0]}, ${names[1]} and ${names[2]} like this` default: return `${names[0]}, ${names[1]} and ${names.length - 2} others like this` } } ``` If you don't know what `${}` means, you can read more about string interpolation [here](https://github.com/AlbertoMontalesi/The-complete-guide-to-modern-JavaScript/blob/master/ebook/04_template_literals.md) Since the challenge didn't pose any surprise, we could easily access the `Array` values at index 0 and 1 to display their names for all cases, using `names.length -2` to display how many are left for our default case which will be used for any instance where we have 4 or more names. ## Try to solve it with ES2021 ES2021 will bring many new additions to `JavaScript` one of which we will try to use for this challenge. If you wanna learn more about everything coming to ES2021, please check out my article at this link. We will try using `Intl.ListFormat` which is a constructor that enables language-sensitive list formatting. Basically what it can do is create a formatted list from our initial `Array` based on a specific language, using either conjunctions or disjunctions. ```js const names = ['Max', 'John', 'Mark'] const formatter = new Intl.ListFormat('en', { style: 'long', type: 'conjunction', }) console.log(formatter.format(names)) // Max, John, and Mark ``` Very cool right? Let's try to apply for our function: ```js function likes(names) { names = names || [] switch (names.length) { case 0: return 'no one likes this' case 1: return ;`${new Intl.ListFormat('en', { style: 'long', type: 'conjunction', }).format(names)} likes this` case 2: case 3: return ;`${new Intl.ListFormat('en', { style: 'long', type: 'conjunction', }).format(names)} like this` default: return `${names[0]}, ${names[1]} and ${names.length - 2} others like this` } } ``` As you can see, using `Intl.ListFormat` we combine case 1 to 3 into one, I had to split case 1 to use `likes` and `like` correctly but other than that the function is the same. To see more examples, head over here. I hope you found this useful, despite the challenge itself being very easy I wanted to show you something that many of you probably don't know yet. There are many other ways of solving this problem, let me know yours in the comment. If you liked this type of content, please let me know in the comments and I'll create more of these. --- --- # JS Challenge 3: Remove Zeroes Published: 2020-10-06T00:00:00.000Z Modified: 2020-10-06T00:00:00.000Z Category: challenge Tags: challenge Keywords: javascript, codewars, javascript challenge, coding problem, javascript remove zeroes, remove zeroes codewars URL: https://montalesi.dev/blog/challenge/challenge-3-remove-zeroes   In this article we will solve together the _Remove Zeroes_ challenge from CodeWars, you can find it at this [link](https://www.codewars.com/kata/52aae14aa7fd03d57400058f). The difficulty of this challenge is medium. Let's read the task together: > Write a function that takes an array of values and moves all elements that are zero to the end of the array, otherwise preserving the order of the array. The zero elements must also maintain the order in which they occurred. > For example, the following array > [7, 2, 3, 0, 4, 6, 0, 0, 13, 0, 78, 0, 0, 19, 14] > is transformed into > [7, 2, 3, 4, 6, 13, 78, 19, 14, 0, 0, 0, 0, 0, 0] > > Zero elements are defined by either 0 or "0". Some tests may include elements that are not number literals. > You are NOT allowed to use any temporary arrays or objects. You are also not allowed to use any Array.prototype or Object.prototype methods. If it were not for the last point regarding temporary arrays this challenge would have been easier as we could have completed it like this: ```JS function removeZeros(array) { const head = [] const tail = [] for (const e of array) { if (e === 0 || e === "0") { tail[tail.length] = e } else { head[head.length] = e } } return [...head, ...tail] } ``` This solution is not mine, I took it from the challenge page. Unfortunately, it is not valid as we are not allowed to define new arrays where to store the zeroes and the non-zeroes values. In real life coding, where everything is valid, this is a perfectly fine solution so feel free to use it if you ever encounter a similar problem. The challenge also forbids Array.prototype or Object.prototype methods so no push,slice,forEach etc..! The way we are going to solve it without creating new arrays is simple, we are still going to iterate over the Array but instead of storing the values in temporary arrays, grab each zero and push it at the appropriate spot. Let' start: ```javascript let limit = array.length let tmp for (let i = 0; i < limit; i++) { if (array[i] === 0 || array[i] === '0') { } } ``` Now that we are iterating over the array what we need to do is to move the zero at the end but also move all the other values a step back too. ```JS let limit = array.length; let tmp; for (let i = 0; i < limit; i++) { if (array[i] === 0 || array[i] === "0") { tmp = array[i]; // iterate again over the array for (let j = i--; j < array.length-1; j++) { array[j] = array[j+1]; } } } ``` The new For Loop that we added is iterating again over the Array, moving items back one position, look at this example: ```JS // before our loop [1,2,0,3,4,5] // after our loop [1,2,3,4,5,5] ``` As you can see, our loop will move every value back one spot and we will then put the zero back at the end, replacing the now duplicate final value. To save the zero value we created a `tmp` variable because we need to know if it's an integer 0 or a string '0'. Let's finalize the function like so: ```JS function removeZeros(array) { let limit = array.length; let tmp; for (let i = 0; i < limit; i++) { if (array[i] === 0 || array[i] === "0") { tmp = array[i]; // iterate again over the array for (let j = i--; j < array.length-1; j++) { array[j] = array[j+1]; } // replace last value with the zero array[array.length-1] = tmp; limit --; } } return array; } ``` After we moved everything back one place we replace the last value with `array[array.length-1] = tmp;` If you are wondering why are we reducing the `limit` variable at the end of the loop it's because we are moving zeroes at the back of the array so we are effectively reducing the portion of the array that needs to be checked by one after each iteration where zero is found. This is an example: ```js let array = [1, 2, '0', 3, 0, 4, 5] // after one iteration where a zero is found // [1,2,3,0,4,5,'0']; // after another iteration where a zero is found // [1,2,3,4,5,'0',0]; // if we don't reduce the size of the iteration we end up with one more iteration like this // [1,2,3,4,5,0,'0']; ``` If you see in the above example, if we don't reduce the size of the iterable array, we will end up with one more iteration where we will push the '0' at the back, resulting in a wrong result as we are not respecting the correct order. That is why we are calling `limit --`. There are many other ways of solving this problem, let me know yours in the comment. If you liked this type of content, please let me know in the comments and I'll create more of these. --- --- # JS Challenge 2: Word Scrambles Published: 2020-10-01T00:00:00.000Z Modified: 2020-10-01T00:00:00.000Z Category: challenge Tags: challenge Keywords: javascript, codewars, javascript challenge, coding problem, javascript word scrambles, word scrambles codewars URL: https://montalesi.dev/blog/challenge/challenge-2-word-scrambles   In this article we will solve together the _Scrambles_ challenge from CodeWars, you can find it at this [link](https://www.codewars.com/kata/55c04b4cc56a697bb0000048/train/javascript). the difficulty of this challenge is medium. Let's read the task together: > Complete the function scramble(str1, str2) that returns true if a portion of str1 characters can be rearranged to match str2, otherwise returns false. > > Notes: > > Only lower case letters will be used (a-z). No punctuation or digits will be included. > Performance needs to be considered > Input strings s1 and s2 are null-terminated. The first example we see is this one: ```js scramble('rkqodlw', 'world') ==> True ```   ## First Solution My Approach for this challenge will be to iterate over the second string and create a map of how many occurrences of a character appear in it. Let's start by doing this: ```javascript const count = {} str2.split('').forEach((c) => { count[c] = count[c] ? (count[c] += 1) : 1 }) ``` I've instantiated an empty object and then I looped over the `str2` to populate it, using the letters as the keys and increasing a count to know how many times each letter appears. We need to do this because if we didn't keep track of the count, we could end up with errors where `str1` contains all the letters from `str2` but only once, meaning it does not fulfill the requirement of being able to be re-arranged into `str2`. Be careful, we cannot call `.forEach` on a `string`, that's why we need to first convert it into an array using `.split('')`. Now, taking the first example and running the code against it we will get something like this: ```javascript { w: 1, o: 1, r: 1, l: 1, d: 1 } ``` What we have to do now is to iterate over the _first_ string and for each character of it, check if it appears in this Object we created. If it does, we decrease the count by 1 every time we find it. ```js str1.split('').forEach((c) => { !!count[c] && count[c]-- }) ``` Here we are doing the same as before, transforming the `string` into an `Array` and iterating over it. At each iteration, we check if the `count` has a truthy value and in that case, we reduce it by 1. We need to check first, because the second string may contain different letters altogether so it could try accessing the `Object` with properties that don't exist on it. Once we have done this we need to check if every property of the `count` `Object` is now at 0. ```javascript return Object.keys(count).every((key) => count[key] === 0) ``` If you don't know how to use `.every` you can read more about in my article about find and replace in Array. Putting everything together, it will look like this: ```javascript function scramble(str1, str2) { const count = {} str2.split('').forEach((c) => { count[c] = count[c] ? (count[c] += 1) : 1 }) str1.split('').forEach((c) => { count[c] && count[c]-- }) return Object.keys(count).every((key) => count[key] === 0) } ```   ## Second Solution Let's try now with a different solution and instead of creating a count map of the letters from `str2` let's do it with `str1`. ```javascript const count = {} str1.split('').forEach((c) => { count[c] = count[c] ? (count[c] += 1) : 1 }) ``` This is the same code as before, I just replaced `str2` with `str1`. Now, instead of mapping `str1`, reducing the count of each letter from `str2` and then checking the Object if all keys are now of value 0, we can do it a bit differently. We can loop over `str2` and for each letter, we try to reduce the value in our `count` Object. If the action succeeds for all letters in `str2` it means that `str1` can be rearranged to form `str2`. Let's see it in action: ```javascript return str2.split('').every((c) => { return count[c]-- }) ``` What this code is doing is iterating over each letter of `str2`, reducing the count each time. We don't care if the count reached 0 or not in this case because `str1` may be much much longer than `str2`. What we are checking here is that `return count[c]--` will not return `false` either by not finding the corresponding match or by going to a negative value which would mean that `str2` contains more occurrences of that letter than `str1`. The complete solutions looks like this: ```javascript function scramble(str1, str2) { const count = {} str1.split('').forEach((c) => { count[c] = count[c] ? (count[c] += 1) : 1 }) return str2.split('').every((c) => { return count[c]-- }) } ``` There are many other ways of solving this problem, let me know yours in the comment. If you liked this type of content, please let me know in the comments and I'll create more of these. --- --- # JS Challenge 1: Simple Pig Latin Published: 2020-09-29T00:00:00.000Z Modified: 2020-09-29T00:00:00.000Z Category: challenge Tags: challenge Keywords: javascript, codewars, javascript challenge, coding problem, pig Latin javascript, pig Latin codewars URL: https://montalesi.dev/blog/challenge/challenge-1-pig-latin   In this article we will solve together the _Simple Pig Latin_ challenge from CodeWars, you can find it at this [link](https://www.codewars.com/kata/520b9d2ad5c005041100000f). the difficulty of this challenge is medium. Let's read the task together: > Move the first letter of each word to the end of it, then add "ay" to the end of the word. Leave punctuation marks untouched The first example given to us is this one `pigIt('Pig latin is cool'); // igPay atinlay siay oolcay` Alright, after reading it one time we can already see different ways of solving this problem: - Using RegEx to remove the first character after space and to add `ay` at the end of each word - Splitting the string in an array and iterating over each portion RegEx can be very powerful and allow you to do a lot in very little but they can also get very hard to read for your others and also for yourself going back to a project after several times. Let's go with the more basic approach of using `JavaScript` to iterate over the string and perform our modifications. First, let's split our string into an array: ```JavaScript const arr = str.split(" "); ``` Next, we want to iterate over the array, removing the first character and appending it at the end, followed by `ay`. ```javascript arr.map((word) => { return `${word.substr(1)}${word.substr(0, 1)}ay` }) ``` Here we are iterating over the strings with `map` and at each iteration, we remove the first character with `substr(1)` which will return us a substring from character 1 to the end of the string, then we add the first letter and finally we append `ay` at the end of it. The only problem with this implementation is that it will not skip characters such as !,? etc... Let's use a very simple RegEx to determine if our character is a letter. We can implement a simple check like the following: `word.match(/[A-z]/i)` This will ensure that only characters from a-z will be taken into account Now let's put everything together: ```javascript function pigIt(str) { const arr = str.split(' ') return arr .map((word) => { return word.match(/[A-z]/i) ? `${word.substr(1)}${word.substr(0, 1)}ay` : word }) .join(' ') } ``` There you have it, a simple functions that will: - iterate over each word in a string - remove the first letter of said string and add it at the end of it - append `ay` at the end of each word If you liked this type of content, please let me know in the comments and I'll create more of these. --- # Everything new coming in ES2022 Published: 2020-09-08T00:00:00.000Z Modified: 2020-09-08T00:00:00.000Z Category: article Tags: beginners, article Keywords: ecmascript, es2022, javascript 2022, learn javascript URL: https://montalesi.dev/blog/article/what-is-coming-es2022 Every year since 2015, `JavaScript` has been receiving constant yearly updates to its specification with new interesting features added. In this article we will have a look at what's to come since many features already reached stage 4 and will be included in the specification. For those of you who don't know, there are 4 stages in the proposal process, with the 4th one being the last one which marks the proposal as finished. As a developer, it's important to stay updated with the new specs of a language and if you feel like you've been left behind by the many updates that `JavaScript` received in the past years, I can recommend you my book that covers everything from the basics of the language all the way to the latest ES2020 specs, including a little intro to `TypeScript`. You can read it for free on Github where you will also find links where to buy the ebook or you can check out my course on Educative Now, let's get started with the first of the new ES2022 features: ## Class Fields ### Class public Instance Fields & private Instance Fields Before ES2022 we would define properties of a `class` in its `constructor` like this: ```js class ButtonToggle extends HTMLElement { constructor() { super() // public field this.color = 'green' // private field this._value = true } toggle() { this.value = !this.value } } const button = new ButtonToggle() console.log(button.color) // green - public fields are accessible from outside classes button._value = false console.log(button._value) // false - no error thrown, we can access it from outside the class ``` Inside of the `constructor`, we defined two fields. As you can see one of them is marked with an `_` in front of the name which is just a `JavaScript` naming convention to declare the field as `private` meaning that it can only be accessed from inside of a `class` method. Of course, that's just a naming convention and not something that the language itself enforces and that's why when we tried to access it, it didn't raise any error. In ES2022 we have an easier way to declare both `public` and `private` fields. Let's have a look at this updated example: ```js class ButtonToggle extends HTMLElement { color = 'green' #value = true toggle() { this.#value = !this.#value } } const button = new ButtonToggle() console.log(button.color) // green - public fields are accessible from outside classes // SyntaxError - cannot be accessed or modified from outside the class console.log(button.#value) button.#value = false ``` The first thing to notice is that don't have to define them inside of the `constructor`. Secondly, we can also define `private` fields by pre-pending `#` to their names. The main difference with the previous example is that this time an actual error will be thrown if we try to access or modify the field outside of the class.   ### Private methods and getter/setters for JavaScript classes Similar to how we did in the previous example, we can also define `private` methods and getter/setters for our classes. ```js class ButtonToggle extends HTMLElement { color = 'green' #value = true; #toggle(){ this.#value = !this.#value } set #setFalseValue(){ this.#value = false; } } const button = new ButtonToggle(); // SyntaxError - cannot be accessed or modified from outside the class button.#toggle(); // SyntaxError - cannot be accessed or modified from outside the class button.#setFalseValue; ``` In the example above we replaced `toggle()` with `#toggle()` thus making the `toggle` method `private` and only accessible from inside of the `class`. ### Static class fields and private static methods A `static` field or method is only accessible in the prototype and not in every instance of a `class` and ES2022 provides us with the means to define `static` fields and `static` public/private methods by using the `static` keyword. Previously we would have to define them outside of the `class` body such as: ```js class ButtonToggle extends HTMLElement { // ... class body } ButtonToggle.toggle(){ // static method define outside of the class body } ``` Now, instead, we can define them directly inside of the `class` body with the use of the `static` keyword: ```js class ButtonToggle extends HTMLElement { #value = true static toggle() { this.#value = !this.#value } } // this will work ButtonToggle.toggle() // SyntaxError - private static field const button = new ButtonToggle() button.toggle() ``` As you can see in the example above, we can access `toggle()` directly on our `ButtonToggle` but we cannot do the same on a new instance of it. We can use the `static` keyword in front of fields and methods (both private and public) and by combining it with the `#` (`private`) we can create a `private static` method only accessible from inside of our prototype `class`. ```js class ButtonToggle extends HTMLElement { #value = true static #toggle() { this.#value = !this.#value } } // this will error, it's a private static method ButtonToggle.#toggle() ```   ## Ergonomic brand checks for private Fields As we saw in the examples above, if we try to access a `private` field outside of a `class` it will throw an exception and will not return `undefined` like it does with `public` fields. We could try using a simple `try/catch` inside of the `class` to check if the field exists: ```js class ButtonToggle extends HTMLElement { // initialised as null #value = null get #getValue() { if (!this.#value) { throw new Error('no value') } return this.#value } static isButtonToggle(obj) { try { obj.#getValue return true } catch { // could be an error internal to the getter return false } } } ``` In the example above we added a `private` `getter` that will throw an error if there is no value yet. We then created a `static` method to access that `getter` and tried to determine if it exists by checking with a `try/catch`. The problem lies in the fact that we don't know if the code in the `catch` is executed because the `getter` is not present or simply because it threw an error. ES2022 provides us with an easy way to check if said field belongs to a `class` by using the operator `in`. Let's rework our example code: ```js class ButtonToggle extends HTMLElement { // initialised as null #value = null get #getValue() { if (!this.#value) { throw new Error('no value') } return this.#value } static isButtonToggle(obj) { return #value in obj && #getValue in obj } } ``` Our method `isButtonToggle` will check if the `class` contains the `private` fields '#value' and '#getValue'.   ## Class Static Block This is yet another upgrade to the `static` fields in ES2022 that allows us to have `static` blocks inside of classes. The issue this is trying to solve arises from the fact that we cannot evaluate statements such as a `try/catch` during initialization meaning that we would have to put that code **outside** of the `class` body: ```js class ButtonToggle { #value = false get getValue() { if (!this.#value) { throw new Error('no value') } return this.#value } } // this has to sit outside of the class body try { const val = ButtonToggle.getValue ButtonToggle.value = val } catch { ButtonToggle.value = false } ``` As you can see, our `try/catch` had to be put outside of the `class` body. Thankfully we can replace that with a `static` block like the following: ```js // method defined outside of the class body let initVal class ButtonToggle { #value = false get getValue() { if (!this.#value) { throw new Error('no value') } return this.#value } static { initVal = () => { this.#value = this.getValue } } } initVal() ``` We created a `static` block inside of our `class` that defines a function that we declared outside of the context of that `class`. As you can see, the method will have access to '#value' which is a `private` field or our class. They will have access to `private` methods and fields, being them `instance-private` (meaning non `static`, `private` fields) or `static-private`. ## RegExp Match Indices This upgrade will allow us to use the `d` character to specify that we want to get the indices (starting and ending) of the matches of our RegExp. We can use `Regexp.exec` or `String.matchAll` to find a list of matches, with the main difference between them being that `Regexp.exec` returns its results one by one whereas `String.matchAll` returns an iterator. Let's see them in practice: ```js const fruits = 'Fruits: mango, mangosteen, orange' const regex = /(mango)/g // .exec RegExp(regex).exec(fruits) // [ // 'mango', // index: 8, // input: 'Fruits: mango, mangosteen, orange', // groups: undefined // ] // matchAll const matches = [...fruits.matchAll(regex)] matches[0] // [ // 'mango', // 'mango', // index: 8, // input: 'Fruits: mango, mangosteen, orange', // groups: undefined // ] ``` Both return the index of the match, the match itself, and the initial input. What we don't know are the indices at which the string ends, something that we will now be able to do like this: ```js const fruits = 'Fruits: mango, mangosteen, orange' // /gd instead of the previous /g const regex = /(mango)/dg const matches = [...fruits.matchAll(regex)] matches[0] // [ // "mango", // "mango", // groups: undefined // index: 8 // indices:[] // [8, 13], // [8, 13] // ] // groups: undefined ``` As you can see it returned [8,13] as the indices of the first occurrence of 'mango' in our string.]   ## Top-level await "`await` operator can only be used within an `async` method" is probably an error you have encountered frequently. In ES2022 we will be able to use it outside of the context of an `async` method in our modules. For example, we could defer the execution of a module and its parent until something else is imported. This can be useful in many scenarios, for example when we have a **dynamic path** for a dependency that depends on a runtime value: ```js // we need to get the appropriate translation keys based on the language const translationKeys = await import(`/i18n/${navigator.language}`) ``` Another use could be to provide a fallback for a dependency: ```js let jQuery try { jQuery = await import('https://cdn-a.com/jQuery') } catch { jQuery = await import('https://cdn-b.com/jQuery') } ``` ## .at() In `JavaScript` you can do `arr[1]` to access the value at index 1 of an `Array` but you cannot do `arr[-1]` to count backward from the ending of the `Array`. The reason is that the brackets syntax is used not only for arrays but also for Objects, where `obj[-1]` would simply refer to the property '-1' of that `Object`. With the .`at()` method we now have an easy way to access any index, positive or negative of arrays and strings: ```js const arr = [10, 20, 30, 40] // same -> 20 arr[1] arr.at(1) // same -> 40 arr[arr.length - 1] arr.at(-1) ``` Note that a negative value simply means: 'Start counting backward from the end of the array'.   ## Accessible Object.prototype.hasOwnProperty In `JavaScript` we already have an `Object.prototype.hasOwnProperty` but, as the MDN documentation also suggests, it's best to not use `hasOwnProperty` outside the prototype itself as it is not a protected property, meaning that an `object` could have its property called `hasOwnProperty` that has nothing to do with `Object.prototype.hasOwnProperty`. For example: ```js const obj = { hasOwnProperty: () => { return false }, } obj.hasOwnProperty('prop') // false ``` As you can see, we defined our own method `hasOwnProperty` that has overridden the one on the prototype, an issue that is not present with `Object.hasOwn()`. `Object.hasOwn()` takes our `Object` as the first argument and the property we want to check as the second: ```js const student = { name: 'Mark', age: 18, } Object.hasOwn(student, 'age') // true Object.hasOwn(student, 'grade') // false ``` --- # Everything new coming in ES2021 Published: 2020-07-25T00:00:00.000Z Modified: 2020-07-25T00:00:00.000Z Category: article Tags: beginners, article Keywords: ecmascript, es2021, javascript 2021, learn javascript URL: https://montalesi.dev/blog/article/what-is-coming-es2021 Every year since 2015, `JavaScript` has been receiving constant yearly updates to its specification with new interesting features added. Despite the release of ES2021 still being far in the future, we can already have a look at what's to come since many features already reached stage 4 and will be included in the specification. For those of you who don't know, there are 4 stages in the proposal process, with the 4th one being the last one which marks the proposal as finished. As a developer, it's important to stay updated with the new specs of a language and if you feel like you've been left behind by the many updates that `JavaScript` received in the past years, I can recommend you my book that covers everything from the basics of the language all the way to the latest ES2020 specs, including a little intro to `TypeScript`. You can read it for free on Github where you will also find links where to buy the ebook or you can check out my course on Educative Now, let's get started with the first of the new ES2021 features: ## String.prototype.replaceAll `String.replace` is a useful method that allows us to replace a pattern in a string with something else. The problem is that if we want to use a `string` as a pattern and not a RegEx, only the **first** occurrence will get replaced. ```js const str = 'I like my dog, my dog loves me' const newStr = str.replace('dog', 'cat') newStr // "I like my cat, my dog loves me" ``` As the name implies, `String.replaceAll` will do exactly what we need in this scenario, replace all the matching pattern, allowing us to easily replace all mentions of a substring, without the use of RegEx: ```js const str = 'I like my dog, my dog loves me' const newStr = str.replaceAll('dog', 'cat') newStr // "I like my cat, my cat loves me" ``` [Read More](https://github.com/tc39/proposal-string-replaceall)   ## Promise.any During the past years we've seen new methods such as `Promise.all` and `Promise.race` with ES6, `Promise.allSettled` last year with ES2020 and ES2021 will introduce a new one: `Promise.any`. I bet you can already tell what it does from the name of the method. `Promise.any` shorts-circuits once a given promise is fulfilled but will continue until all promises are rejected. Don't get confused with `Promise.race` because with `race`, the promise short-circuits once one of the given promises resolves **or rejects**. They have similar behavior for what concerns fulfillment but very different for rejection. If all the promises inside of `Promise.any` fails, it will throw an `AggregateError` (a subclass of `Error`) containing the rejection reasons of all the promises. We can use it like this: ```javascript // example taken from: https://github.com/tc39/proposal-promise-any Promise.any(promises).then( (first) => { // Any of the promises was fulfilled. }, (error) => { // All of the promises were rejected. } ) ``` [Read More](https://github.com/tc39/proposal-promise-any)   ## Logical Operators and Assignment Expressions With ES2021 we will be able to combine Logical Operators (`&&`, `||` and `??`) with Assignment Expression (`=`) similarly to how it's already possible to do in Ruby. If you skipped on ES2020 you may not be aware of `??` which is the **nullish coalescing** operator. Let's look at an example: ```js const a = null ?? 'test' // 'test' const b = 0 ?? 'test' // 0 ``` The **nullish coalescing** operator returns the _right_ hand-side when the left-hand-side is `null` or `undefined`, otherwise it returns the _left_ hand-side. In the first example the left-hand-side was `null` thus it returned the right-hand-side while on the second example it returned the left-hand-side because it was neither `null` nor `undefined`. Moving back to ES2021 stuff, in `JavaScript` we already have many [assignment opeartors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#Assignment_operators) like the following basic example: ```js let a = 0 a += 2 // 2 ``` But with this new proposal we will be able to do the following: ```js a ||= b // equivalent to a = a || b c &&= d // equivalent to c = c && d e ??= f // equivalent to e = e ?? f ``` Let's go over each one by one: - `a ||= b` will return `a` if `a` is a truthy value, or `b` if `a` is falsy - `c &&= d` will return `d` if both `c` and `d` are truthy, or `c` otherwise - `e ??= f` will return `f` if `e` is `null` or `undefined` otherwise it will return `e` [Read More](https://github.com/tc39/proposal-logical-assignment)   ## Numeric Separators The introduction of Numeric Separators will make it easier to read numeric values by using the `_` (underscore) character to provide a separation between groups of digits. Let's look at more examples: ```js x = 100_000 // 100 thousand dollar = 55_90 // 55 dollar 90 cents fraction = 0.000_1 // 1 thousandth ``` [Read more](https://github.com/tc39/proposal-numeric-separator)   ## WeakRefs From [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef#:~:text=A%20weak%20reference%20to%20an%20object%20is%20a%20reference%20that,reclaimed%20by%20the%20garbage%20collector.&text=When%20an%20object%20no%20longer,object%20and%20reclaim%20its%20memory.): A weak reference to an object is a reference that does not prevent the object from being reclaimed by the garbage collector. With this new proposal for ES2021, we will be able to create weak references to objects with the `WeakRef` class. Please follow the link below to read a more in-depth explanation. [Read More](https://github.com/tc39/proposal-weakrefs)   ## Intl.ListFormat The `Intl.ListFormat` object is a constructor for objects that enable language-sensitive list formatting. Looking at an example is easier than explaining it: ```js const list = ['Apple', 'Orange', 'Banana'] new Intl.ListFormat('en-GB', { style: 'long', type: 'conjunction' }).format(list) // Apple, Orange and Banana new Intl.ListFormat('en-GB', { style: 'short', type: 'disjunction' }).format(list) // Apple, Orange or Banana ``` You are not limited to English, let's try with a few different languages: ```js const list = ['Apple', 'Orange', 'Banana'] // Italian console.log(new Intl.ListFormat('it', { style: 'long', type: 'conjunction' }).format(list)) // Apple, Orange e Banana // Spanish console.log(new Intl.ListFormat('es', { style: 'long', type: 'conjunction' }).format(list)) // Apple, Orange y Banana // German console.log(new Intl.ListFormat('de', { style: 'long', type: 'conjunction' }).format(list)) // Apple, Orange und Banana ``` Pretty neat uh? For a more detailed look at this specification check out the link below. [Read More](https://github.com/tc39/proposal-intl-list-format)   ## dateStyle and timeStyle options for Intl.DateTimeFormat We can use `dateStyle` and `timeStyle` to request a locale-specific date and time of a given length. ```js // short new Intl.DateTimeFormat('en', { timeStyle: 'short', }).format(Date.now()) // "2:45 PM" // medium new Intl.DateTimeFormat('en', { timeStyle: 'medium', }).format(Date.now()) // "2:45:53 PM" // long new Intl.DateTimeFormat('en', { timeStyle: 'long', }).format(Date.now()) // "2:46:05 PM GMT+7" ``` Now let's try with `dateStyle`: ```js // short new Intl.DateTimeFormat('en', { dateStyle: 'short', }).format(Date.now()) // "7/25/20" // medium new Intl.DateTimeFormat('en', { dateStyle: 'medium', }).format(Date.now()) // "Jul 25, 2020" // long new Intl.DateTimeFormat('en', { dateStyle: 'long', }).format(Date.now()) // "July 25, 2020" ``` You can pass whatever locale you want and you can also pass both `dateStyle` and `timeStyle` options at the same time, choosing between the three options of 'short', 'medium', and 'long' that best suit your needs. [Read More](https://github.com/tc39/proposal-intl-datetime-style)   What's the feature you are most excited to try? Leave a comment down below, for me, it's probably the combination of Logical Operators and Assignment Expressions, I love my syntax to be short and clean. If you want to learn everything about JavaScript from ES6 all the way to ES2020, please check out my book available to read for free on Github. A course is also on Educative   --- # 30 Useful CSS Examples For Logically Creative Minds Published: 2020-07-15T00:00:00.000Z Modified: 2020-07-15T00:00:00.000Z Category: CSS3 Tags: #css, #tutorial Keywords: URL: https://montalesi.dev/blog/article/30-useful-css-examples-for-logically-creative-minds ## Cinyras ea tulit in inducit qui mater Lorem markdownum facit? Hinc tutus serisque, mihi iaculum curam, vicibus aliquando se posses gentis quidem. Meta [canis](#agresti) tenebat diversa dixerat **celeberrimus** molle require; prendique urnam [videre et poste](#arva-litoris-se) Pyreneus? Haut mei sive digna noctisque percussit dicta, in pars certaminis iuvenalis. Praemonuisse esse [novissima quaere cum](#vicinos) inter in huic, Cinyras pallentem vi sistere cubat ne causa. ## Utque tu canibus Possent quippe. Conata fera ab Hersilie iam auditur haesit. Culpa ignis retia Aonides ictus crescendo micantes, petere, ambustaque vicem in digitos iubet cornigeris. - Iura demens satus vino simulac celanda - Exhibuere frustra utque - Panda pars umidus ## Fregit aut Caystro equos Manet pro aere superest adiacet sua purpura Tereus in **multis conantem culpa**, inque **fingit et referebat**? Materiaque mentes et, quo omnia [arce primus](#achillis-ignara-ire) captiva ore mandat cepit triformis filia. Prius _sorte nomina_ in repellite sentit facunde te aures, vires. ```js const { createFilePath } = require(`gatsby-source-filesystem`) exports.onCreateNode = ({ node, getNode, actions }) => { const { createNodeField } = actions // Ensures we are processing only markdown files if (node.internal.type === 'MarkdownRemark') { // Use `createFilePath` to turn markdown files in our `data/faqs` directory into `/faqs/slug` const relativeFilePath = createFilePath({ node, getNode, baseslug: 'data/faqs/', }) } } ``` Fama creatis cum; ait atque et ictaque stabat, si texit continuere exsatiata vestes, humana arces. Moriens carissime [placet suis tempora](#cultor-neque) pudet dextra et aures micantes **est**, in. Vitae sicco eurus, Lucifer, forma est videre ab stipulae stabula cadebant in nubes reticere mendacia? Adice [quid](#rite) Ladon petis. Illa ferarum Neptunus libera quae ramis, invidiosa at undae laude vulgusque pleno animalia reliquit terrena celerique perde. --- # Find and Replace elements in Array with JavaScript Published: 2020-07-06T00:00:00.000Z Modified: 2020-07-06T00:00:00.000Z Category: tutorial Tags: beginners, tutorial Keywords: array javscript, array js, array indexof, array splice, javascript find in array, javascript filter array, array filter URL: https://montalesi.dev/blog/tutorial/find-replace-in-array Arrays are a very common data structure and it's important to know how to manipulate them by retrieving, adding, and replacing data inside of them. In this article, we are going to learn what are the different ways to find and replace items inside of arrays.   ## Check that an Array contains a value First, let's look at different ways of checking if our Array includes a certain value provided. We can do that in different ways such as: ```js const arr = [1, 2, 3, 4, 5] arr.includes(2) // true arr.includes(6) // false ``` `Array.includes` is probably the easiest method to remember and it will return us `true` or `false` if our Array includes or not the value we passed. This method can take an additional argument which defines the index from where we want to start looking, leave empty if you want to check the whole Array. Let's continue with more methods: ```js const arr = [1, 2, 3, 4, 5] !!arr.find((a) => a === 2) // true !!arr.find((a) => a === 6) // false ``` `Array.find` is also another method we can use to check if our Array contains a certain value. This method will return the value itself or undefined if no value is found so we can use the `!!` operator to convert the result to boolean and quickly see if there's a match or not. It's a more powerful method compared to `Array.includes` as we can pass a callback to it, not just a value to check, meaning that we can do more complex checks such as: ```js const arr = [1, 2, 3, 4, 5] !!arr.find((a) => a > 2 && a < 4) // true ``` Being able to pass a callback to it it means that unless your check is a very straightforward one, you are most likely going to use `find` over `includes`. You can pass a second argument to the callback function defining the starting point where to start checking, leave empty to check the whole Array. Next up we have `Array.indexOf` and `Array.findIndex`: ```js const arr = [1, 2, 3, 4, 5] arr.indexOf(1) !== -1 // true arr.indexOf(6) !== -1 // false arr.findIndex((el) => el === 1) !== -1 // true arr.findIndex((el) => el === 6) !== -1 // false ``` `Array.indexOf` and `Array.findIndex` are similar because they both return the index of the first matching element found in our Array, returning us `-1` if it's not found. To check if an element exists, we simply need to check if the returned value is `-1` or not. These methods are useful because they can be used to both checks if an element exists in the Array while at the same time getting a reference as to where that element is positioned, which we can use to then replace that said element. The difference between the two methods is the same as the one we saw between `Array.includes` and `Array.find`, where the first one (`Array.indexOf`) will accept a value to check whereas the second one (`Array.findIndex`) will accept a callback to perform more advanced checks. Similarly to all the methods we previously saw, you can also define a starting index where to start check the Array. Next up are two new metho introduced in ES6 (ES2015): ```js const arr = [1, 2, 3, 4, 5] arr.some((el) => el === 2) // true arr.every((el) => el === 3) // false ``` `Array.some` will check if at least one value in the array matches the condition in our callback function and `Array.every` will check that ALL of the elements in the Array match that condition.   ## Replacing an element of an Array at a specific index Now that we know how to check if the Array includes a specific element, let's say we want to replace that element with something else. Knowing the methods above, it couldn't be easier! In order to replace an element we need to know its index, so let's see some examples using the methods we just learned: ```js const arr = [1, 2, 3, 4, 5] const index = arr.indexOf(2) arr[index] = 0 arr // [1,0,3,4,5]; ``` Ass you can see, first, we got the index of the element we wanted to change, in this case, the number 2 and then we replaced it using the brackets notation `arr[index]`. We can do the same using `findIndex`: ```js const arr = [1, 2, 3, 4, 5] const index = arr.findIndex((el) => el === 2) arr[index] = 0 arr // [1,0,3,4,5]; ``` Pretty easy right? Using `findIndex` we can also check scenarios like the following where we have an Array of Objects: ```js const arr = [ { id: 1, val: 'one', }, { id: 2, val: 'two', }, { id: 3, val: 'three', }, { id: 4, val: 'four', }, { id: 5, val: 'five', }, ] const index = arr.findIndex((el) => el.id === 2) arr[index] = { id: 0, val: 'zero', } arr // [ // { // id:1, // val: 'one' // }, // { // id:0, // val: 'zero' // }, // { // id:3, // val: 'three' // }, // { // id:4, // val: 'four' // }, // { // id:5, // val: 'five' // }, // ]; ``` As you can see, using `findIndex` we can easily find and then replace Objects in an Array of Objects. Let's say we are not interested in replacing a value but we just want to remove it, we will now look at different ways of doing so.   ## Removing a value from an Array First, let's look at the more basic methods to remove values from an Array: `Array.pop` and `Array.shift` ```js const arr = [1, 2, 3, 4, 5] arr.pop() arr // [1,2,3,4] const arr2 = [1, 2, 3, 4, 5] arr2.shift() arr2 // [2,3,4,5]; ``` `Array.pop` will remove the **last** element of the Array while `Array.shift` will remove the **first** one. No additional arguments are allowed, so you can see that these methods are fairly basic. Both methods will modify your origianl array and both return the removed element so you can do the following: ```js const arr = [1, 2, 3, 4, 5] const el = arr.pop() el // 1 ``` Now we will look at a couple of ways to remove a specific element from an array. First, let's look at `Array.splice` used in combination with `Array.indexOf`. `Array.splice` allows us to remove elements from an Array starting from a specific index. We can provide a second argument to specify how many elements to delete. ```js const arr = [1, 2, 3, 4, 5] const index = arr.indexOf(2) arr.splice(index, 1) arr // [1,3,4,5]; const arr2 = [1, 2, 3, 4, 5] const index = arr2.indexOf(2) arr2.splice(index) arr2 // [1] ``` As you can see, in the first example we specified 1 as the number of elements to remove, whereas in the second example we didn't pass any argument thus removing all items in the array from our starting index. `Array.splice` will modify your original array and return the removed elements so you can do the following: ```js const arr = [1, 2, 3, 4, 5] const index = arr.indexOf(2) const splicedArr = arr.splice(index, 1) arr // [1,3,4,5]; splicedArr // [2] ``` Next up, we can also remove elements from an array based on a condition and not just on an index with the use of `Array.filter`: ```js let arr = [1, 2, 3, 4, 5] const newArr = arr.filter((el) => el > 2) newArr // [3,4,5] arr // [1,2,3,4,5]; ``` Differently from `Array.pop`, `Array.shift` and `Array.splice` , `Array.filter` creates a new array with all the elements that pass the condition in the callback function so your original array won't get modified as you can see from the code above. In this case, our new Array consisted of all the elements of the original that are greater than 2. --- --- # What is the difference between passing by value or by reference in JavaScript Published: 2020-06-06T00:00:00.000Z Modified: 2020-06-06T00:00:00.000Z Category: article Tags: beginners, article Keywords: javascript value or reference, javascript pass by value, javascript pass by reference, pass by value, pass by reference URL: https://montalesi.dev/blog/article/pass-by-value If you just started learning how to code you may have heard the terms pass by value and pass by reference but you may not be 100% clear as to what they mean. In this article we will go over the difference between the two, using `JavaScript` as the language of reference. First of all, let's define what these two terms mean: - pass by value means that when we pass a variable to a function, it is copied over onto a new one and a change inside of the function scope will **not** be reflected outside of it - pass by reference, on the other hand, means that our variable is not copied over onto a new one but simply referenced in our function so a change inside of the function **will** be reflected outside of it   ## Pass by value `JavaScript` **always** passes arguments by values, meaning that a new variable is created inside the scope of the function so changing its value inside of it will **not** affect what's outside of the scope. Let's look at this simple example: ```javascript function incrementNumber(num) { num = num + 1 console.log(num) } let myNumber = 1 incrementNumber(myNumber) // 2 console.log(myNumber) // 1 ``` As you can see, the value got updated **inside** of the function, but the original variable that we passed as the argument of the function did **not** change.   ## Pass by reference We just mentioned that `JavaScript` **always** passes arguments by value so when is it that we actually can leverage passing by reference? Let's look at this example: ```javascript function increaseAge(person) { person.age = person.age + 1 console.log(person.age) } const me = { name: 'Alberto', age: 27, } increaseAge(me) // 28 console.log(me.age) // 28 ``` As you can see, this time instead of a Primitive, I passed an Object and when I changed the value of a property of that object, the change was reflected outside of the scope of the function. Does this mean that Objects are passed by reference in `JavaScript`? The answer is no and this simple example will show you why `JavaScript` **always** passes by value. ```javascript function increaseAge(person) { person = { name: 'Alberto', age: person.age + 1, } console.log(person.age) } const me = { name: 'Alberto', age: 27, } increaseAge(me) // 28 console.log(me.age) // 27 ``` What happened here? Why this time when we accessed `me.age` the value was not changed? The reason is that the Object is passed by value but its value (its properties) is just a reference to that of the original Object. That's why when we changed a property of the object inside of our function, that change was reflected outside of it but when we change the Object itself to a new one the change was not reflected outside because we changed the new one that lived inside of the function scope.   --- --- # Discover more Console methods available in JavaScript and learn how to style them Published: 2020-04-24T00:00:00.000Z Modified: 2020-04-24T00:00:00.000Z Category: tutorial Tags: beginners, tutorial Keywords: javascript console, console log, console methods URL: https://montalesi.dev/blog/tutorial/console-logging One of the first things that new `JavaScript` programmers learn is how to use `console.log` to print their statements and view the output of their code. While an undoubtedly useful thing to know, the `console` Object actually has many more methods available to use and in this article, we are going to look over a few of the more interesting ones. ## `console.log()` Let's just have a quick review of this one. As the name implies, it is used for logging values, whether they are primitives such as string or number or the result of a function. ```JavaScript console.log(5); // 5 const sayHello = () => { return 'hello' } console.log(sayHello()); // hello ```   ## `console.info()` In substance, it's the same as `console.log()`, it differs only in the meaning and to provide a degree of separation between informative logs and debug logs. You may want to keep `console.info()` in your code but probably you want to get rid of all your `console.log()` before pushing it as they were added while debugging. In Firefox, a little 'i' icon is displayed to show that it's a `console.info` output.   ## `console.warn()` `console.warn()` is used to output a warning to the console and in Firefox a little yellow warning icon will be displayed alongside the output message.   ![console.warn image](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/console-log/console_warn.png)   ## `console.error()` This one is used to log errors to the console, in Firefox a red warning icon is displayed alongside the output message while in Chrome it will display a white cross inside of a red circle. The difference with the previous ones is that in this case a stack trace will also be logged, allowing you to see where the error comes from. ```JavaScript function sayHello() { console.error('Error!!!') } sayHello() ```   ![console.error image](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/console-log/console_error.png)   ## `console.trace()` If you want to know the stack trace of a method even when there's no error, then you should use the method `console.trace()`. ```JavaScript const func = () => { const nestedFunction = () => { console.trace() }; nestedFunction() } func() ```   ![console.trace image](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/console-log/console_trace.png)   As you can see this logged the stack trace of our method and since it's not an error, it's not displayed in red.   ## `console.time()`, `timeEnd()`, `timeLog()` With `console.time()` you can start a timer to track how long an operation takes. You can give the timer a unique name and then call `console.timeEnd(nameOfYourTimer)` to stop it and log the duration to the console. ```JavaScript console.time('countToTen'); setTimeout(function(){ console.timeEnd('countToTen') },10000) // countToTen: 10000.5087890625ms ``` After 10 seconds you will see the timer logged in the console, this can be useful if you want to monitor the performance of your methods. You can have up to 10,000 unique timers at the same time so create as many as you need. If you only want to log the current timer but you don't want to stop it yet, use the method `console.timeLog()` with the name of your timer and it will be logged in the console without stopping it. This can be useful if you are monitoring different blocks of a method and you want to see where the performance issue may be located.   ## `console.dir()`, `dirxml()` `console.dir()` prints an interactive list of properties of your object. Nowadays, browsers like Chrome and Firefox display interactive objects even when using `console.log()` so the need to use this is limited. `console.dirxml()` prints an interactive tree markup of a DOM element, so for example if you were to run `console.dirxml(console.body);` on this very page you would see an interactive tree of all the DOM elements inside of the body of this page.   ## `console.assert()` This method is used to run an assertion. If the first argument fails the subsequent arguments are printed to the console. ```javascript console.assert(1 > 2, '1 is not more than 2') // Assertion failed: 1 is not more than 2 console.assert(1 < 2, ' 1 is less than 2') // nothing is printed ``` The first line logged to the console our custom message '1 is not more than 2' along with a stack trace. The second `console.assert()` did not print anything because the assertion did not fail. You can't set a message to be printed when the assertion succeeds, only when it fails. ## `console.clear()` As the name implies, this method is used to clear the console, simple and easy. Every browser has a dedicated button and shortcuts to clear the console so you'll probably rarely use this method but it's worth knowing that it exists.   Now that you know how to use more methods than just `console.log()`, let's have a look at how to style them to make them more recognizable. It is actually very simple to style your messages and you can do it this way: ```javascript console.log('%cThis is red', 'color:red') ``` We prepended '%c' before the string where we want to apply some styling and we added a second argument to the method to apply some CSS styles to it. You are not limited to colors, you can apply any type of font styling you want such as font-weight, font-family, etc... using the same syntax you would use for CSS, separating each style with a semicolon. ```javascript console.log('%cThis is red', 'color:red; font-size:30px') ```   This wraps up this intro to the `console` API methods for `JavaScript` if you want to learn all of them you can head over to [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Console) and have a look at the one I didn't mention here.   --- --- # Stay motivated during lockdown by learning Programming Published: 2020-03-30T00:00:00.000Z Modified: 2020-03-30T00:00:00.000Z Category: article Tags: article Keywords: lockdown, learn programming, stay motivated URL: https://montalesi.dev/blog/article/learn-programming-during-quarantine Many of us are currently stuck at home because of the Covid-19 virus that spread all over the world and only a fraction of us is lucky enough to be able to work from home, leaving many others unemployed and with a lot of free time at hand. Netflix and other services planned, or are planning to lower the quality of their services during this moment to save bandwidth as an unprecedented amount of people are connected to the internet, using streaming services the whole day. While it's important to take care of your physical health by washing hands, practicing social distancing and staying at home, I think it's equally important to take care of your mental health as well. In this article, I want to give you an alternative to spend your time that will hopefully help you feel more engaged and motivated, compared to sitting in front of a TV the whole day. I'm not trying to judge anybody, I understand how you can feel after having lost your job, my aim is only to provide an alternative to spend the day that will make you feel rewarded when you go to sleep. What I'm saying is not that you should stop using Netflix and similar at all, just that it's not good for you to get stuck on your it for the whole day. I am Alberto Montalesi, a self-taught full-stack developer, author of the book Complete Guide to Modern JavaScript, and I want to share with you why I love programming and why I think it would make a great hobby for you. Alternatively, if you are already a programmer, you should still find something interesting in this article so keep reading! Remember, if you find this article useful, to share with your friends, especially the one that are struggling right now to fill up their days in lockdown.   ## Why you should learn to program? This article is not about switching careers and becoming a developer, even though that's what I did. I got into programming at the age of 24, after a Bachelor's of Law and the reason why I got into it was by accident, thanks to my girlfriend ( if you are interested, I've got a whole story about my career switch here). Before getting into coding, I always thought about it as something difficult and only for very smart people. That is only partially true, sure there are fields of it that are very complex and you won't be picking them up in a few weeks, but you don't have to be a genius to start! Also, you don't need to love math to be a programmer! That was a misconception I also had before starting. Anyway, the reason I love to code is that I can be creative and build useful tools for myself and others with only the use of my laptop. I don't consider myself a creative person, I don't play instruments and I don't know how to draw but programming allows me to be creative in more unconventional ways. Also, it's a very inexpensive hobby! You only need a computer, which most of us already have and it doesn't even need to be a powerful one and you can start building simple websites, games or tools to use in your daily life. The other day I was thinking that it would be cool to let the users on my blog to be able to highlight the text of an article to tweet it, so I spent a few hours and built a plugin to do that and then wrote a tutorial to teach others how to do it. For as much as I love binge-watching shows and playing videogames the whole day, the feeling I get when I spend some time sitting down and writing code to create even simple projects like the one above is much more satisfying and rewarding. Also, I mentioned before that this article won't be about a career change but if you end up loving programming as I did, it's a career full of opportunities, most of them that allow you to work remotely which is proving to be a lifesaver for me as I'm still able to work and pay my rent even though everything around me is shutting down.   ## How to get started learning to program? A lot of companies are offering extended free trials of their products or free courses to encourage people to pick up programming during this period of quarantine and lockdown. I'm now going to go over a few that I've tried and I know that are good places where you start learning as a self-taught developer. A good place where to start is the **CS 50** course by Harvard which covers the very basics of Computer Science and it's very well taught. You can take this course on Edx. It's sort of a must if you have zero knowledge of programming, it will give you some good foundations so you will understand what those other tutorials are about when you start reading them. If you are a student, you can take advantage of **CodeCademy Pro** (read more here) where you can start learning the basics of languages such as Python or JavaScript and practice with simple exercises. These two languages are very popular and not too difficult to pick up. There are many tutorials out there to keep you busy trying to build small projects. The best starting point I think would be HTML and CSS, used respectively to create and to style web pages. They are not programming languages but I included them as together with JavaScript they are the building blocks of basically every website on the internet. HTML is very easy to pick up and it's quite fun to create your website so you should give that a try. Another website I highgly recommend is Educative where you can find many interesting courses for free such as this one on Python. I also authored a course on Educative about JavaScript which you can find here. **Coursera** is another great website where you can find high-quality courses, not only about programming. I really enjoyed taking this one about HTML CSS and JavaScript and it's totally free. The last website I want to recommend you is FreeCodeCampwhich again covers HTML CSS and JavaScript with interesting lessons, exercises and projects. Most importantly, it also boasts a huge community of developers that help each other. They have a global Facebook group and many local ones full of nice people ready to help you so I recommend you join it. During this time of quarantine, being part of a community, helping and keeping each other motivated is vital to get through these difficult days. To reiterate, if you are completely new to programming, CS 50 by Harvard is a great choice to get to know the basics and it will only take you a few days to complete. Once you are done I suggest picking up HTML and CSS as they are very easy and, in my personal experience, they proved to be a great introduction to what the programming world was about from the eyes of a total noob. After that, dive into JavaScript with one of your choices from Educative, FreeCodeCamp, or Coursera. None of them will disappoint you. There are many other websites you can use, such as Udemy, Udacity and Khan Academy but I didn't want to overwhelm you with links. Joining a community is also important to keep yourself motivated, especially during this moment, so get yourself Discord, Reddit or Facebook and join a group, introduce yourself as a newbie and you will find people willing to help and guide you further. If, on the other hand, you are already a programmer, use this time in quarantine to learn something new. Maybe you know JavaScript and you are good at it so why don't you try learning Python? Or maybe practice your skills on some challenges at CodeWars or try working on a project to challenge yourself.   ## Conclusion Stay motivated and always try to finish your day with something positive to look back at. It can be something as simple as learning what is an `Array`, or what are functions, it's not important as long as you feel like you did not waste your entire day in front of the TV, just letting time pass by. Take programming as a hobby and don't feel discouraged if you get stuck for hours on something you don't understand. It's just like in a game, when you get stuck against a difficult boss, just go take some side quests and level up and come back stronger. Thank you for reading, if you like this article please share it with your friends and follow my blog Montalesi.dev for more articles and tutorials. --- # Create a JavaScript plugin to highlight and tweet text Published: 2020-03-20T00:00:00.000Z Modified: 2020-03-20T00:00:00.000Z Category: tutorial Tags: beginners, tutorial Keywords: twitter, highlight to tweet, javascript tutorial, javascript plugin URL: https://montalesi.dev/blog/tutorial/highlight-to-tweet ## Create a plugin to highlight and tweet text Many times I found myself reading a passage on a website and thinking I wanted to share that with my friends or random people of the internet, but few are the times where the website facilitated that process for me. Usually, I would have to copy the passage I wanted to share, go on Twitter and tweet it but we all know that most people are lazy so, if you want your user to tweet content from your articles/blogs, etc... in this tutorial, I will teach you how to create a simple plugin to do that. Alternatively, if you don't want to bother with coding it yourself, I've already packaged it for you and you can find it on npm at highlight-to-tweet. Credits for most of the idea and the code go to this user on WebFlow. I mostly transformed the JQuery code into a native `JavaScript` code and published it as an npm package. The plugin we are going to build will work in the following way: - A user highlight some text on your page - They are prompted to tweet it with a button - They click the button and they can tweet it, all without leaving your site   ## Create the tweetHighlighted function Now that you are ready to start, let's open your `JavaScript` file and start with: ```javascript document.addEventListener('DOMContentLoaded', () => { window.tweetHighlighted = () => { // our function will be built here } // we call it once the page loads window.tweetHighlighted() }) ``` The first thing we want to do know is to define some properties that will come in handy later on. Inside of the ` window.tweetHighlighted = () => {` function, we want to add this code: ```javascript const settings = { node: "Tweet", maxLength: 280, extra: null, via: null, popupArgs: 'width=400,height=400,toolbar=0,location=0', } ``` These are the basic settings of our plugin: - node defines the element that will be contained in the button that pops up - maxLength is the max length allowed for the tweet, here I've set it as 280 because that's the max allowed for a tweet, but if you want to set it lower you can do it - extra is simply some extra text that you want to include in your tweets - via defines the handler for twitter, if you want to be tagged whenever a user tweets something from your site - popupArgs is used to define the twitter popup Our next step will be to create a button, add it to the DOM and give an event listener to it. Continuing after the code we just wrote, add this: ```javascript let url = '' let text = '' const shareButton = document.createElement('div') shareButton.style.display = 'none' shareButton.addEventListener('click', (e) => { e.preventDefault() e.stopPropagation() window.open(url, '_blank', settings.popupArgs) }) const body = document.querySelector('body') body.appendChild(shareButton) ``` Firstly, we defined two empty variables that will hold our `url` and `text` for the tweet. Secondly, we created a new `div` element and assign it to our variable `shareButton`. We then hid it with `display:'none'` and added an event listener to it to listen for `click` events. When a user clicks our button we use `stopPropagation` to avoid the click event to bubble down to the `a` tag that we assigned above to the `node` in our settings and we also call `window.open` passing the `url` that will be populated later and our arguments to define the size of the window to open. After that, we are simply adding this newly created element to the `body` of our page. One thing you may be wondering is how we are going to identify when the user highlights texts on the page. The answer to that is simple, we will use the `mouseup` event and check if the user selected something.   ## Add event listeners to the function Continuing from where we left, let's add this code: ```javascript document.addEventListener('mouseup', (e) => { text = getSelectedText() const btnExists = shareButton.style.display !== 'none' if (btnExists || !text.length) { return } else { appendShareButton(e) } }) const getSelectedText = () => { if (window.getSelection) { return window.getSelection().toString() } else if (document.selection) { return document.selection.createRange().text } return '' } ``` Awesome, these two functions will ensure that when the user triggers the `mouseup` event, if there is some text highlighted, we will capture it, store it in our `text` variable and call the function `appendShareButton` to add that button to the DOM. Let's continue and define that function: ```javascript const appendShareButton = (e) => { url = getTweetURL(text, settings.extra, settings.via) shareButton.innerHTML = '' shareButton.innerHTML += settings.node shareButton.innerHTML += tweetIcon if (settings.cssClassess && settings.cssClassess.length) { shareButton.classList.add(settings.cssClassess) } shareButton.style.top = `${e.pageY}px` shareButton.style.left = `${e.pageX}px` shareButton.style.position = 'absolute' shareButton.style.cursor = 'pointer' shareButton.style.display = 'flex' shareButton.style.justifyContent = 'space-between' shareButton.style.alignContent = 'center' shareButton.style.alignItems = 'center' shareButton.style.opacity = 0 shareButton.style.fontFamily = 'Arial, Helvetica, sans-serif' shareButton.style.backgroundColor = '#3898EC' shareButton.style.padding = '10px 15px' shareButton.style.width = '100px' shareButton.style.borderRadius = '5px' shareButton.style.color = 'white' shareButton.firstChild.style.color = 'white' shareButton.firstChild.style.textDecoration = 'none' shareButton.lastChild.style.fill = 'white' } ``` Wow, that is a long function but don't worry, it does not do much. Most of those lines are just styling. Firstly, we get the create the complete `url` by calling yet another function that we haven't defined, called `getTweetURL`, passing it the highlighted text, the extra text and the via handler. We then define a list of styles on our `shareButton` to display it and position it appropriately. The only important ones are the one relative to the positioning of the button, everything else is purely styling. It may be gross to define each style on a different line like this but I figured it would be clearer for you to see. If you want, you can define styles this way too: ```javascript shareButton.style.cssText = ` /* your list of style here, same as how you would add it in a CSS file*/ ` ``` You may have noticed this line: `shareButton.innerHTML += tweetIcon;` We haven't defined yet a `tweetIcon` so let's go outside this function and copy this code: ```javascript const tweetIcon = `` ``` This is the tweet icon, it's a simple SVG I've found online, this will allow us to don't have to call it from a CDN or somewhere else. Awesome, now we have a function to append the button to the DOM, we only need to define that function `getTweetURL`. Let's do that now:   ## Construct the URL for the tweet ```javascript const getTweetURL = function (text, extra, via) { let url = 'https://twitter.com/intent/tweet?text=' // trim the text to fit in the max allowed 280 characters const viaUrl = `&via=${via}` const maxLength = settings.maxLength > 280 ? 280 : settings.maxLength const maxAllowedLength = maxLength - viaUrl.length - extra.length let textToTweet = text if (text.length > maxAllowedLength) { textToTweet = text.substring(0, maxAllowedLength - 1) } url += encodeURIComponent(textToTweet) if (extra) url += encodeURIComponent(' ' + extra) if (via) url += viaUrl return url } ``` Let's break down this function: - first, we define the base URL that we need - then we create the portion of URL that contains our `via` handler - after that, we calculate how many characters in our text allowed to take, based on the maxLength we defined (or the max of 280), the via handler and the extra text - if the text is too long, we use `substring` to take only a portion of it - we then stick everything together and use `encodeURIComponent` to ensure all characters are escaped properly There you have it, this function returns a perfect URL to share the tweet. Now you can try this code on your webpage and you will see that everything should work fine. If you want a more customizable plugin you can check out the one i've published on Github. --- --- # Copy text to the clipboard with JavaScript in 10 lines of code Published: 2020-02-25T00:00:00.000Z Modified: 2020-02-25T00:00:00.000Z Category: tutorial Tags: beginners, tutorial Keywords: copy to clipboard, javascript copy to clipboard URL: https://montalesi.dev/blog/tutorial/copy-to-clipboard   ## Create a copy to clipboard button In this short tutorial, we are going to look at how to implement the **copy to clipboard** functionality in your website or app with just a few lines of `JavaScript`. There are various reasons why you would prefer to have a button to copy to the clipboard rather than simply have your user have to highlight and manually copy text and fortunately for you, it's a very simple feature to implement. The way we are going to do that is by creating an invisible `textarea` into which we are going to copy our string and execute a 'copy' command to save the value to our clipboard. Once done, we will delete that DOM element. First of all, let's start creating our dummy content: ```html

I copied this text from Montalesi.dev

``` Nothing much to see here, a `p` tag with some dummy content and a `button` with an onclick function. I had to put an `id` on my `p` tag to be allowed to target it with my function.   ## Write the JavaScript to copy to clipboard Now let's write our function and then we'll go over each line of code: ```js function copyToClipboard() { const str = document.getElementById('item-to-copy').innerText const el = document.createElement('textarea') el.value = str el.setAttribute('readonly', '') el.style.position = 'absolute' el.style.left = '-9999px' document.body.appendChild(el) el.select() document.execCommand('copy') document.body.removeChild(el) } ``` Let's go over the code line by line: Firstly, we get the content of the target element, you can omit this line if you are already passing a string to your function. In this case, the content is derived from a specific element of the page so we need to get it upon click. We then proceed to create a new `textarea` element and set some properties onto it: - we set the value to match the content of our string - we set _readonly_, position absolute and _left -9999px_ just to make our `textarea` invisible to the user We then append the element to the DOM so that right after we do that, we can call `select()` onto it. What select does is simply select the content of our element. You may be asking: why didn't we simply call `select()` on the `p` tag? Why did we have to create a new `textarea`? The answer to that is very straightforward, we can only call `select()` on `textarea` and `input` elements. If you are implementing copy to clipboard on a comment field, for example, which may be already using a `textarea` element, then you can call `select()` directly onto it, without having to create a new DOM element as we are doing in this tutorial. After we are done with `select()` we are calling `document.execCommand('copy')` which will copy the selected content. Lastly, we remove the `textarea` from the DOM with `removeChild(el)`. Now, if you try to press 'ctrl + v' or simply right-click and select _paste_ you will see that the content of the `p` tag got copied to the clipboard; Let's make it more visual and add one more line to our function, right after the `removeChild()` call: ```js alert(`Copied: ${str}`) ``` Now, go ahead and try again. You will see an alert telling you what content you just copied. Awesome! In just 10 lines of code, you created a simple yet very useful functionality.   --- --- # Add dark mode to your website with just a few lines of code Published: 2020-02-08T00:00:00.000Z Modified: 2020-02-08T00:00:00.000Z Category: tutorial Tags: beginners, tutorial Keywords: dark mode, localstorage, toggle dark mode, css dark mode URL: https://montalesi.dev/blog/tutorial/dark-mode-toggle Dark mode has become incredibly popular in the last year and all popular apps nowadays offer a toggle to turn it on. In this short tutorial we are going to look at how to add support for dark mode in your website in different ways: first with just `CSS` and lastly with a toggle built with `JavaScript`. ## Adding Dark Mode support with CSS If you don't want to get too fancy with dark mode and just want your website to change color palette if the user is using a browser with dark mode enabled, `CSS` is going to be enough for you. Inside of your `CSS` file, write this media query: ```css @media (prefers-color-scheme: dark) { /* all your styles for dark mode here */ } ``` With this media query, we can define a set of custom styles to apply when the user is browsing with dark mode enabled. According to [CanIUse.com](https://caniuse.com/#search=prefers-color-scheme) the support is at around 78%, leaving out Internet Explorer and Edge (not Edge Chromium). If you are not working on enterprise software where you really have to worry about users still using Internet Explorer, I think that this media query can work well. The downside of this method is that your user won't have control over how they want to view your website so I would consider it only if you don't have time or don't want to implement a toggle.   ## Toggle Dark Mode with JavaScript Let's now go one step further and implement a toggle for Dark Mode with `JavaScript`. To be able to do that you will need to create two different stylesheets, one for each theme (light and dark). If you need, you can create a third stylesheet which will contain non-theme related styles. The first step will be to define a default theme stylesheet in the `head` of our `html` like so: ```html ``` What we are going to do now is to create a button to swap that stylesheet with another one. Go ahead and create a button like the following and put it wherever you like, preferably at the top of the page for quicker access by the user. ```html ``` Now that we have a simple button, let's add some `JavaScript` to it. Open your `JavaScript` file and write the following lines of code: ```js // this one is jut to wait for the page to load document.addEventListener('DOMContentLoaded', () => { const themeStylesheet = document.getElementById('theme') const themeToggle = document.getElementById('theme-toggle') themeToggle.addEventListener('click', () => { // if it's light -> go dark if (themeStylesheet.href.includes('light')) { themeStylesheet.href = 'dark-theme.css' themeToggle.innerText = 'Switch to light mode' } else { // if it's dark -> go light themeStylesheet.href = 'light-theme.css' themeToggle.innerText = 'Switch to dark mode' } }) }) ``` This code is simply adding an event listener to our `button` so that every time we click it it will look at the `href` of our stylesheet and toggle between dark and light. We are also changing the text of the button itself to reflect the change in the theme. You can play around with the button itself and define some neat icons to better differentiate between dark and light themes. If you try the above code you will see that when you click the button the stylesheet changes but there is one problem. Can you guess what the problem may be? If you are thinking that the next time a user comes back to the website they will have to click again the button to toggle again the theme, then you guessed right. At the moment the user choice is not saved anywhere so once they leave the site and come back they will have to switch theme again. Luckily there's a quick way that allows us to overcome this problem and that is **LocalStorage**.   ## Saving users' preferences in localStorage As the name implies, preference set to it will be stored locally on your browser so if your user changes browser or device they will lose their choice of theme but most of the time they will probably come back to your site using the same device so this can be a quick and effective way to store their preference. **LocalStorage** can store key value pairs and we can use it like this: ```js localStorage.setItem('theme', 'dark-theme.css') ``` Let's go ahead and add it to our previous code: ```JavaScript // this one is jut to wait for the page to load document.addEventListener('DOMContentLoaded', () => { const themeStylesheet = document.getElementById('theme'); const storedTheme = localStorage.getItem('theme'); if(storedTheme){ themeStylesheet.href = storedTheme; } const themeToggle = document.getElementById('theme-toggle'); themeToggle.addEventListener('click', () => { // if it's light -> go dark if(themeStylesheet.href.includes('light')){ themeStylesheet.href = 'dark-theme.css'; themeToggle.innerText = 'Switch to light mode'; } else { // if it's dark -> go light themeStylesheet.href = 'light-theme.css'; themeToggle.innerText = 'Switch to dark mode'; } // save the preference to localStorage localStorage.setItem('theme',themeStylesheet.href) }) }) ``` As you can see in the code above, on page load we do a check to see if there is a theme preference stored in **localStorage** by using `localStorage.getItem('theme')`. If we find something, we then apply it right away, restoring the user's preferences. I've also updated the code that runs when we click a button, including this line `localStorage.setItem('theme',themeStylesheet.href)` to store the user selection. Now we have a fully functional light-dark theme toggle that will remember the user selection, improving considerably the user experience. What's great is that this took only 10 minutes to do! Remember that you are not limited to a dark-light theme, you can have as many as you want and you can even get fancy with them. A few last words about localStorage: its support is now more than 93% so you can confidently use it without worrying too much about legacy browsers since it's supported even on IE8-9-10!. Another way to quickly store user preferences, other than localStorage, are **sessionStorage** which, as the name implies persists only for the current session until the browser session is active which does not suit our case scenario well. One thing to know about both localStorage and sessionStorage is that they stick to the same-origin policy meaning that if you access your website over both Http and Https, your choice of the theme made over https won't be reflected over Http. If you start wondering why your preference is not being saved, knowing this little caveat can help you avoid spending half an hour trying to guess what's the issue.   ### Implement Dark Mode with a single css file Another way of achieving the same result, but with using only one styleheet would be to toggle a global class on the `body`. Add this to your `JavaScript` ```js button.addEventListener('click', () => { document.body.classList.toggle('dark') localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light') }) if (localStorage.getItem('theme') === 'dark') { document.body.classList.add('dark') } ``` And your `css` will look like the following: ```css /* Light mode */ body { background: #fff; color: #000; } /* Dark mode */ body.dark { background: #000; color: #fff; } ``` Edit: Thanks to [Thomas](https://dev.to/thomasbnt) and [Taufik](https://dev.to/taufik_nurrohman) for corrections and edits.   --- --- # Create a dynamic sticky table of contents for your website Published: 2020-02-02T00:00:00.000Z Modified: 2020-02-02T00:00:00.000Z Category: tutorial Tags: beginners, tutorial Keywords: javascript, table of contents, dynamic table of contents URL: https://montalesi.dev/blog/tutorial/tutorial-5-create-a-dynamic-table-of-content When reading a long article it's easy to get lost, and that's why the table of contents is very useful. In this short tutorial, I am going to show you how you can create a dynamically generated table of contents for your article with just a few lines of `JavaScript`. What you are going to achieve by the end of this tutorial will be: - a dynamic table of the content generated based on the headings of your article - on page load, if the URL includes one of the sections, jump directly at the appropriate part of the content. This is especially good if you want to share a specific section of your article. - add smooth scrolling with just one line ## Demo This is a demo of how the result will look like. ![javascript sticky table of contents](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/master/screenshots/sticky_table_of_content_inspiredwebdev.gif)   ## Creating the HTML structure for the table of contents The HTML for this tutorial is very simple, we will simply create a dummy page with some lorem ipsum content. Go ahead and copy this code: ```html

Section 1

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Section 2

table of contents

``` For the sake of keeping the code short, I've only added one section but feel free to add as many as you want, and also change the text to something more fun than a boring lorem ipsum. Now that we have the skeleton that we'll use for the tutorial, let's go ahead and outline what we'll need to do with `JavaScript`. Let's add some few lines of `CSS` to display both our two sections next to each other instead of one after the other. Open your `CSS` file and add: ```css #container { display: flex; justify-content: space-around; align-items: flex-start; } #content { width: 70vw; } #content div { height: 100vh; } #table-of-content { width: 30vw; } ``` What we did here was just making the container flex and setting the width for our content and table of contents sections. I also made each `div` in the content to be as tall as the viewport so that we can better see the scrolling in action.   ## Build the JavaScript to create a dynamic table of contents These are the steps that we will follow to achieve the result that you saw in the demo above: - after DOM is loaded, get all the heading and store them in a variable - loop over them and for each of them create a `li` that will be part of our table of contents - for each of the headings, add an anchor before the heading itself to link it with the one in the table of contents - look at the URL and check if there is already something and in that case, jump directly to the correct section Ok, now that we outlined our steps, let's start our `JavacScript` page with a listener: ```javascript document.addEventListener('DOMContentLoaded', () => { // our code will go here }) ``` We want to wait until the page is loaded before we start interacting with the DOM. The first step now is to take all the headings in our page and interate over them: ```javascript const headings = document.querySelectorAll('#content h3') if (headings && headings.length) { // our code will continue inside here } ``` We save all our headings in a variable and set a simple `if` statement to check if there are any before proceeding. To create the table of the content we will need two elements: - an anchor tag in the table of the content itself - an anchor tag for the corresponding section of our article Inside of the `if` statement, write this code: ```javascript let tableOfContentInner = '' headings.forEach((heading, i) => { // generate an 'li' element that includes a link to the appropriate section tableOfContentInner += `
  • ${heading.textContent}
  • ` const originalHeadingContent = heading.innerHTML const anchor = `` // add the anchor to the

    tag heading.innerHTML = anchor + originalHeadingContent }) ``` What this code is doing is iterating over our list of headings and for each of them it's first creating a `li` with an anchor tag inside and then it's creating another anchor element and prepending it before our section headings. As you can see, we set the `href` property of the first anchor to `#section_${i}` which will become '#section_1', '#section_2' and so on. We use the `#` symbol to tell the hyperlink that this link is to an 'id' in the page and that is why the anchor that we prepended to the headings has an `id="section_${i}"`. Now that we have our variable `tableOfContentInner` that includes a list of `li` element, one for each section, what we need to do is to add it to the DOM and we can do that with two lines of code, outside of the `forEach` loop. ```javascript const tableOfContent = `
      ${tableOfContentInner}
    ` // add the generated table of contents to the dive document.querySelector('#table-of-content').innerHTML += tableOfContent ``` First, we added our list of `li` to an `ol` element and then pushed everything inside of our container in the DOM. Awesome, go ahead and check it out in the browser, you will see that when you click an anchor tag it goes right at the point in the document that you need. Our anchor currently sits right above the headings so when you click on a link the content will be right at the top of the page. In a real-life website, you probably have a navbar up there or you may just want to keep some breathing space on top of the title so you should add some CSS to the 'offset-anchor' class that I've given to the anchor. ```css .offset-anchor { display: block; position: relative; top: -150px; visibility: hidden; } ``` Giving it a 'top' negative value will move it upwards, giving some breathing space to the content when you click on the relevant section. Another problem that we have right now is that the table of contents does not follow the content itself so once you click a link you will lose sight of it. Don't worry, `CSS` has a property that it's perfect for what we need, it's called **sticky** and will help us make the table of contents stick at the top of the page. What we need to do is simply add this `CSS` lines: ```css #table-of-content { width: 30vw; /* these two lines will do the trick */ position: sticky; top: 0; } ``` The support for this property is quite widespread, even without prefixes. Now that we have our sticky table of contents, we want to add a quick check on page load to see if the URL already contains a section and in that case, navigate right to it. Open again your `JavaScript` file and after the last line we typed, still inside of our `if` statement, add this: ```javascript // automatically go to the correct section on load if (location.hash) { const target = location.hash const offsetY = document.querySelector(target).offsetTop window.scrollTo(0, offsetY) } ``` In case somebody shared your article in section 1, `location.hash` will contain '#section_1' so what we are doing here is intercepting it on load and scrolling the window right to the appropriate section. This can be useful if you want to share a specific part of your article and want the page to load at the appropriate part of the content, not at the top. Awesome, go ahead and try everything we did so far. It works fine right? But wouldn't it be nicer if clicking a link scrolled smoothly to the appropriate section instead of jumping? `CSS` these days is amazing and for this, we only need one line of code. ```css html { scroll-behavior: smooth; } ``` This will do it!, unfortunately, it's not as supported as 'sticky' and it won't work on Safari (and Internet Explorer and Edge). You can use a polyfill such as https://www.npmjs.com/package/smoothscroll-polyfill to achieve the expected result. Now you have a fully functional table of contents generated dynamically based on the headings of your article. It's time for you to do some homework! These are two possible improvements that this small project could benefit from: - if there are no headings, hide the table of contents and only display the content in full width - currently, we only display `h3` tags in the table of contents, how would we go about allowing for nested headings? `h3` inside of `h2` for example? --- --- # Learn JavaScript with this interactive course Published: 2020-02-01T00:00:00.000Z Modified: 2020-02-01T00:00:00.000Z Category: article Tags: beginners, article Keywords: javascript, educative, interactive course, javascript course, es2019, javascript interactive course URL: https://montalesi.dev/blog/article/educative-course
    Disclaimer: I am the author of this course and the book on which it was based. This website contains affiliate links. See my disclosure about affiliate links here

    **Tl;dr** -> I've got a new course out, it's about `JavaScript` and I'm really happy with the result, you can check it out Here (preview lessons available if you want to get an idea) `JavaScript` has evolved a lot during the past years and the way developers use it has changed quite a bit. Since 2015, a lot of new features have been added to the language specification, from new ways of declaring variables to new primitives and new useful methods. Keeping up with the updates can take a lot of time and that's why I originally wrote the book Complete Guide to Modern JavaScript, to have a book with a collection of all those new updates, easy to read, concise but without lacking substance. The book recently got updated to include ES2019 material and the guys at Educative contacted me to create an interactive course based on it. ## Why should you consider taking this course? This course's aim is to provide you with all the tools you need to start writing code using the latest version of the language. Each lesson will cover a new set of features and guide you through them with interactive examples and exercises to test your understanding. At the end of the course,you will also find an introduction to `TypeScript`, a must have knowledge for any `JavaScript` developer going into 2020. The course includes a bunch of lessons that are free to preview so you just go ahead and have a look for yourself without having to commit to purchasing it right away.   ## What will I be able to do at the end of the course? At the end of the course you will be able to understand and use all of the new additions to `JavaScript` since 2015. Stay ahead of the game and practice new features that will come out next year. If you work in a company that is still stuck using old ES5 code, you will be able to get your skills up to speed and be able to refactor your code in a cleaner, more concise way. ## What is cool about the Educative platform? Video courses (e.g: Udemy kind) are nice, but as a personal preference, I think that written courses are quicker to go through and easier to go back and forth between lessons. The thing I like the most about courses on Educative is that despite being written courses, they still offer a great degree of interactivity. Simply reading an article full of code snippets is no a great way of learning but luckily on Educative you can have executable snippets, code exercises and even full-fledged html+css+js executable code all inside of an article. This makes for quick, easy to read and interactive courses that I find are much faster to go through compared to video courses and also let you play around with your instructor's code.     ## Other interesting courses from Educative Educative has courses for everybody and if you are not interested in `JavaScript` they have plenty other topics such as Machine Learning or React or even Blockchain --- # 10 Must Know JavaScript string methods Published: 2020-01-11T00:00:00.000Z Modified: 2020-01-11T00:00:00.000Z Category: article Tags: beginners, article Keywords: javascript, javascript string, string methods, must know string methods, must know javascript string methods URL: https://montalesi.dev/blog/article/10-javascript-string-methods
    `string` is a `JavaScript`'s primitive type that is used to represent a sequence of characters. They are used to store much different information, from names, product descriptions, etc.. and hopefully NOT passwords!. In this article, we are going to look at 10 String methods that you will see yourself use on an almost daily basis once you start working with `JavaScript`. At the end of this article you will find a link to download a set of **flashcards** to bring with you and revise the concepts discussed in this article. If you are not too familiar with `JavaScript` you may be wondering why `string` (the primitive) and `String.` in the method names are written in two different cases. The answer is that lowercase `string` refers to the primitive type while uppercase `String` refers to the global object on which we can call several built-in methods. The conversion between the primitive `string` and the `String` object is done automatically and that is why you don't have to write code like the following: ```javascript const primitiveString = 'Alberto' const str = new String([primitiveString]) str.length // 7 ``` Here we are creating a new `String` object from our original string but since JavaScript does the conversion automatically we can simply call the `String` methods directly on the primitive like this: ```javascript const primitiveString = 'Alberto' primitiveString.length // 7 ``` Now that we covered some basics, let's start looking at some useful methods.
    ## String.prototype.indexOf() The `String.prototype.indexOf()` returns the index of the **first** occurrence in the calling `String` object of the value that we specify as an argument. ```javascript const str = 'Watermelon' str.indexOf('melon') // 5 const str2 = 'My dog is named boo. My dog is 7 years old' str2.indexOf('dog') // 3 const str3 = 'My DOG is named boo. My dog is 7 years old' str3.indexOf('dog') // 24 ``` In the second `String`, the word "dog" appears twice but `indexOf()` only returns the index of the **first** occurrence. In the third `String` you will see that "DOG" is now uppercase, thus the result changed from '3' to '24' because the `indexOf()` method is **case sensitive**.
    ## String.protoype.includes() The `String.protoype.includes()` method is similar to the previous, in that it's used to find one string inside another one but it won't return the index of it but simply a boolean, whether the first string can or cannot be found in the second one. ```javascript const str = 'Watermelon' str.includes('melon') // true const str2 = 'WATERMELON' str2.includes('melon') // false ``` As you can see, this method is also **case sensitive**, returning us `false` where looking for lowercase "melon" inside of uppercase "WATERMELON". Since these two methods are very similar, you may be wondering why you should use one over the other and the answer is simply to choose the one that best fits what you are trying to achieve. Do you need to know at what index does string B appear in string A? use `indexOf()`. Conversely, are you just checking if string B is present in string A? You could use something like: `a.indexOf(b) !== -1 ` but you should just use `includes()` for better clarity of your code.
    ## String.protoype.startsWith() / String.protoype.endsWith() These two methods have been added with the ECMAScript 2015 (ES6) specification and are used to determine if one string starts, or ends, with a specified set of characters returning `true` of `false` appropriately. Similar to the two methods above, these two are also **case sensitive** Both methods can take two parameters, the first one is the same for both and it's a string. The second one differs between the two methods: - `startsWith()` can take an optional parameter indicating the **starting position** where to begin searching for a string. It defaults to 0 - `endsWith()` can take an optional parameter indicating the **length** of the original string to check. It defaults to the length of the string. Let's look at the following examples for `startsWith()` ```javascript const str = 'Watermelon' str.startsWith('Water') // true str.startsWith('Water', 1) // false str.startsWith('melon', 5) // true str.startsWith('lon', 7) // true ``` Let's break the code down: - `str.startsWith('Water');` returns `true` because "Watermelon" includes the string 'Water' right at the beginnng - `str.startsWith('Water', 1);` returns `false` because the string that is used as the base to check is the original string starting at index 1 which equals to 'atermelon' - `str.startsWith('melon',5 )` and `str.startsWith('lon',7 )` both return `true` because the string we used to check are the original string starting from index 5 and index 7, which equal to 'melon' and 'lon'. Now let's look at some examples for `endsWith()`: ```javascript const str = 'Watermelon' str.endsWith('melon') // true str.endsWith('me', 7) // true str.endsWith('melon', 8) // false ``` Let's break the code down: - `str.endsWith('melon')` returns `true` because 'Watermelon' ends with 'melon' - `str.endsWith('me', 7)` returns `true` because we are only checking the first 7 characters of the string, which in turn transforms it from 'Watermelon' to 'Waterme'. - `str.endsWith('melon', 8)` returns `false` because we specified a max length of 8 which transformed the string to check to 'Watermel' which does not end with 'melon'.
    ## String.protoype.slice() `String.protoype.slice()` is a useful method to extract a section of a string into another string without modifying the original one. This method takes two parameters: a beginning index and an end index. The second one is optional and it defaults to the end of the string if not specified. Let's look at an example: ```javascript const str = 'Watermelon' const str2 = str.slice(1) // atermelon const str3 = str.slice(1, 5) // ater const str4 = str.slice(5) // melon const str5 = str.slice(10) // '' ``` Let's look at what we just did: - `str.slice(1)` extracts every character from index 1 to the end of the string - `str.slice(1,5)` extracts characters from index 1 to index 5 - `str.slice(5)` extracts characters from index 5 to the end of the string - `str.slice(11)` extracts characters from index 11 to the end of the string. Since the string does not have 11 characters, the result we got was an empty string
    ## String.prototype.substring() `String.prototype.substring()` is very similar to the previous `slice()` method, in that it is used to extract a portion of a string. It takes two arguments, one for a start index and one for an end index. Let's look at some examples: ```javascript const str = 'Watermelon' const str2 = str.substring(1) // atermelon const str3 = str.substring(1, 5) // ater const str4 = str.substring(5) // melon const str5 = str.substring(10) // '' ``` If you look at the examples above and compare them with the ones from the `slice()` method you will wonder what's the difference as they both returned the same substring. While for the most part, you can use them interchangeably, there are differences between the two. Look at this example for the first difference: ```javascript const str = 'Watermelon' const subStr = str.substring(10, 0) // Watermelon const sliceStr = str.slice(10, 0) // '' ``` In this case, the start index was higher than the end index I've provided and as you can see the two methods behaved differently: `substring()` will **swap** start and end index if start is **higher** than end while `slice()`, on the other hand, won't do that, thus returning an empty string. Another difference we can observe has to do with negative indexes: ```javascript const str = 'Watermelon' const subStr = str.substring(-3) // Watermelon const sliceStr = str.slice(-3) // lon ``` When we set the starting point as a negative value, `substring()` will simply treat it as 0 (and that is also valid for `NaN` values) while `slice()` will start counting the index from the **end** of a string. That is why `str.slice(-3)` returned 'lon', because it started counting from 3 steps from the end of the string, all the way to the end. For the most part, you will be fine using either `slice` or `substring()` but it is useful to know that there are some differences between the two.
    ## String.prototype.split() `String.prototype.split()` is another very useful method that turns a `String` into an array of strings. The string gets split based on a specified separator. This method takes two arguments, a separator, and a limit. The separator specifies how to split the string while the limit is a non-negative integer that specifies how many split to perform. Let's look at an example to see this method in action: ```javascript const str = 'apple, banana, mango, watermelon' const arr = str.split(', ') // ["apple", "banana", "mango", "watermelon"] const arr2 = str.split(', ', 1) // "apple"] ``` As you can see, in the first example we split our string based on this separator ', ' which means that every string in between a comma followed by a space got put into the array. In the second example, I also passed a limit of 1 which told the method to perform only one split, thus returning an array with only one element inside.
    ## String.prototype.trim() / String.prototype.trimEnd() / String.prototype.trimStart() `String.prototype.trim()` removes whitespaces from both the end and the beginning of a string. `String.prototype.trimEnd()` removes them only from the end while `String.prototype.trimStart()` removes them only from the start. These are pretty straightforward, but let's look at an example: ```javascript const str = ' watermelon ' const trim = str.trim() // "watermelon" const trimStart = str.trimStart() // "watermelon " const trimEnd = str.trimEnd() // " watermelon" ```
    ## String.prototype.padStart() / String.prototype.padEnd() These two methods may seem like the opposite of the `trim()` method but while they can be used to add whitespace to the beginning or end of a string, they can do more than that. They take two arguments, one for the length of the retuning string after the pad has been added (if lower than the current length of the string, the string is returned as-is, without any modification) and another argument for the string to add at the beginning or end of the original one. If it's long to fit in the length we defined in the first argument, it will be truncated. Let's look at a few examples: ```javascript const str = 'Watermelon' const str2 = str.padStart(15, ' ') // " Watermelon" const str3 = str.padEnd(15, ' ') // "Watermelon " ``` In the examples above we used `padStart()` and `padEnd()` to add whitespace to the string. Since we defined our max length as 15, and the length of the original string was 10, 5 characters were added to the string as whitespace (" "). As mentioned above, we are not limited to add whitespace, we can also add new strings onto the original one. ```javascript const str = 'Watermelon' const str2 = str.padStart(17, 'I like ') // "I like Watermelon" const str3 = str.padStart(11, 'I like ') // "I Watermelon" const str4 = str.padEnd(19, ' is yummy') // "Watermelon is yummy" const str5 = str.padEnd(13, ' is yummy') // "Watermelon is" ``` As you can see, we managed to add a new string onto the original one but when the string to add was too long for our specified length, it got truncated, resulting in "I Watermelon" and "Watermelon is".
    ## String.prototype.toUpperCase() / String.prototype.toLowerCase() There's not much to say about these two methods as they are very straightforward in what they do. `String.prototype.toUpperCase()` transforms a string in uppercase whilst `String.prototype.toLowerCase()` transforms it into lowercase. Both are useful when you want to display a string differently from how it's stored in your variable. ```javascript const str = 'Watermelon' str.toUpperCase() // WATERMELON str.toLowerCase() // watermelon ```
    ## String.prototype.concat() `String.prototype.concat()` is a useful method used to concatenate a string with the calling arguments, returning a new string. Let's look at an example: ```javascript const str = 'Watermelon' const newStr = str.concat(' is a ', 'fruit') // Watermelon is a fruit ``` As you can see we called `concat()` on our original string and concatenated two new strings to it, returning a new string _newStr_. You can pass as many strings as you want as the argument of `concat()` --- # Everything you need to know from ES2016 to ES2019 Published: 2020-01-03T00:00:00.000Z Modified: 2020-01-03T00:00:00.000Z Category: article Tags: beginners, article Keywords: javascript, ES2016, ES2017, ES2018, ES2019, ecmascript URL: https://montalesi.dev/blog/article/es2016-to-es2019 `JavaScript` is a language in constant evolution and in the past few years many new features have been added to the `ECMAScript` specification. This article is an extract of my book Complete Guide to Modern JavaScript and it covers the new additions of ES2016, ES2017, ES2018, ES2019. **At the end of the article you will find a link to download a cheatsheet that summarizes everything.**
    ## Everything new in ES2016 ES2016 introduced only two new features: - `Array.prototype.includes()` - The exponential operator
    ## `Array.prototype.includes()` The `includes()` method will return `true` if our array includes a certain element, or `false` if it doesn't. ```javascript let array = [1, 2, 4, 5] array.includes(2) // true array.includes(3) // false ```
    ### Combine `includes()` with `fromIndex` We can provide `.includes()` with an index to begin searching for an element. Default is 0, but we can also pass a negative value. The first value we pass in is the element to search and the second one is the index: ```javascript let array = [1, 3, 5, 7, 9, 11] array.includes(3, 1) // find the number 3 starting from array index 1 // true array.includes(5, 4) //false array.includes(1, -1) // find the number 1 starting from the ending of the array going backwards // false array.includes(11, -3) // true ``` `array.includes(5,4);` returned `false` because, despite the array actually containing the number 5, it is found at the index 2 but we started looking at position 4. That's why we couldn't find it and it returned `false`. `array.includes(1,-1);` returned `false` because we started looking at the index -1 (which is the last element of the array) and then continued from that point onward. `array.includes(11,-3);` returned `true` because we went back to the index -3 and moved up, finding the value 11 on our path.
    ## The exponential operator Prior to ES2016 we would have done the following: ```javascript Math.pow(2, 2) // 4 Math.pow(2, 3) // 8 ``` Now with the new exponential operator, we can do the following: ```javascript 2 ** 2 // 4 2 ** 3 // 8 ``` It will get pretty useful when combining multiple operations like in this example: ```javascript 2 ** (2 ** 2) // 16 Math.pow(Math.pow(2, 2), 2) // 16 ``` Using `Math.pow()` you need to continuously concatenate them and it can get pretty long and messy. The exponential operator provides a faster and cleaner way of doing the same thing.
    ## ES2017 string padding, `Object.entries()`, `Object.values()` and more ES2017 introduced many cool new features, which we are going to see here. ## String padding (`.padStart()` and `.padEnd()`) We can now add some padding to our strings, either at the end (`.padEnd()`) or at the beginning (`.padStart()`) of them. ```javascript 'hello'.padStart(6) // " hello" 'hello'.padEnd(6) // "hello " ``` We specified that we want 6 as our padding, so then why in both cases did we only get 1 space? It happened because `padStart` and `padEnd` will go and fill the **empty spaces**. In our example "hello" is 5 letters, and our padding is 6, which leaves only 1 empty space. Look at this example: ```javascript 'hi'.padStart(10) // 10 - 2 = 8 empty spaces // " hi" 'welcome'.padStart(10) // 10 - 6 = 4 empty spaces // " welcome" ```
    ### Right align with `padStart` We can use `padStart` if we want to right align something. ```javascript const strings = ['short', 'medium length', 'very long string'] const longestString = strings.sort((str) => str.length).map((str) => str.length)[0] strings.forEach((str) => console.log(str.padStart(longestString))) // very long string // medium length // short ``` First we grabbed the longest of our strings and measured its length. We then applied a `padStart` to all the strings based on the length of the longest so that we now have all of them perfectly aligned to the right. ### Add a custom value to the padding We are not bound to just add a white space as a padding, we can pass both strings and numbers. ```javascript 'hello'.padEnd(13, ' Alberto') // "hello Alberto" '1'.padStart(3, 0) // "001" '99'.padStart(3, 0) // "099" ```
    ## `Object.entries()` and `Object.values()` Let's first create an Object. ```javascript const family = { father: 'Jonathan Kent', mother: 'Martha Kent', son: 'Clark Kent', } ``` In previous versions of `JavaScript` we would have accessed the values inside the object like this: ```javascript Object.keys(family) // ["father", "mother", "son"] family.father ;('Jonathan Kent') ``` `Object.keys()` returned only the keys of the object that we then had to use to access the values. We now have two more ways of accessing our objects: ```javascript Object.values(family) // ["Jonathan Kent", "Martha Kent", "Clark Kent"] Object.entries(family) // ["father", "Jonathan Kent"] // ["mother", "Martha Kent"] // ["son", "Clark Kent"] ``` `Object.values()` returns an array of all the values whilst `Object.entries()` returns an array of arrays containing both keys and values.
    ## `Object.getOwnPropertyDescriptors()` This method will return all the own property descriptors of an object. The attributes it can return are `value`, `writable`, `get`, `set`, `configurable` and `enumerable`. ```javascript const myObj = { name: 'Alberto', age: 25, greet() { console.log('hello') }, } Object.getOwnPropertyDescriptors(myObj) // age:{value: 25, writable: true, enumerable: true, configurable: true} // greet:{value: ƒ, writable: true, enumerable: true, configurable: true} // name:{value: "Alberto", writable: true, enumerable: true, configurable: true} ```
    ## Trailing commas in function parameter lists and calls This is just a minor change to a syntax. Now, when writing objects we can leave a trailing comma after each parameter, whether or not it is the last one. ```javascript // from this const object = { prop1: 'prop', prop2: 'propop', } // to this const object = { prop1: 'prop', prop2: 'propop', } ``` Notice how I wrote a comma at the end of the second property. It will not throw any error if you don't put it, but it's a better practice to follow as it make your colleague’s or team member’s life easier. ```javascript // I write const object = { prop1: "prop", prop2: "propop" } // my colleague updates the code, adding a new property const object = { prop1: "prop", prop2: "propop" prop3: "propopop" } // suddenly, he gets an error because he did not notice that I forgot to leave a comma at the end of the last parameter. ```
    ## Shared memory and `Atomics` From [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics): > When memory is shared, multiple threads can read and write the same data in memory. **Atomic** operations make sure that predictable values are written and read, that operations are finished before the next operation starts and that operations are not interrupted. `Atomics` is not a constructor, all of its properties and methods are static (just like `Math`) therefore we cannot use it with a new operator or invoke the `Atomics` object as a function. Examples of its methods are: - add / sub - and / or / xor - load / store Atomics are used with `SharedArrayBuffer` (generic fixed-length binary data buffer) objects which represent generic, fixed-length raw binary data buffer. Let's have a look at some examples of `Atomics` methods: ## `Atomics.add()`, `Atomics.sub()`, `Atomics.load()` and `Atomics.store()` `Atomics.add()` will take three arguments, an array, an index and a value and will return the previous value at that index before performing an addition. ```js // create a `SharedArrayBuffer` const buffer = new SharedArrayBuffer(16) const uint8 = new Uint8Array(buffer) // add a value at the first position uint8[0] = 10 console.log(Atomics.add(uint8, 0, 5)) // 10 // 10 + 5 = 15 console.log(uint8[0]) // 15 console.log(Atomics.load(uint8, 0)) // 15 ``` As you can see, calling `Atomics.add()` will return the previous value at the array position we are targeting. when we call again `uint8[0]` we see that the addition was performed and we got 15. To retrieve a specific value from our array we can use `Atomics.load` and pass two argument, an array and an index. `Atomics.sub()` works the same way as `Atomics.add()` but it will subtract a value. ```javascript // create a `SharedArrayBuffer` const buffer = new SharedArrayBuffer(16) const uint8 = new Uint8Array(buffer) // add a value at the first position uint8[0] = 10 console.log(Atomics.sub(uint8, 0, 5)) // 10 // 10 - 5 = 5 console.log(uint8[0]) // 5 console.log(Atomics.store(uint8, 0, 3)) // 3 console.log(Atomics.load(uint8, 0)) // 3 ``` Here we are using `Atomics.sub()` to substract 5 from the value at position `uint8[0]` which is equivalent to 10 - 5. Same as with `Atomics.add()`, the method will return the previous value at that index, in this case 10. We are then using `Atomics.store()` to store a specific value, in this case 3, at a specific index of the array, in this case 0, the first position. `Atomics.store()` will return the value that we just passed, in this case 3. You can see that when we call `Atomics.load()` on that specific index we get 3 and not 5 anymore.
    ## `Atomics.and()`, `Atomics.or()` and `Atomics.xor()` These three methods all perform bitwise AND, OR and XOR operations at a given position of the array. You can read more about bitwise operations on [Wikipedia](https://en.wikipedia.org/wiki/Bitwise_operation) at this link https://en.wikipedia.org/wiki/Bitwise_operation
    ## ES2017 Async and Await ES2017 introduced a new way of working with promises, called "async/await".
    ## `Promise` review Before we dive in this new syntax let's quickly review how we would usually write a promise: ```javascript // fetch a user from github fetch('api.github.com/user/AlbertoMontalesi') .then((res) => { // return the data in json format return res.json() }) .then((res) => { // if everything went well, print the data console.log(res) }) .catch((err) => { // or print the error console.log(err) }) ``` This is a very simple promise to fetch a user from GitHub and print it to the console. Let's see a different example: ```javascript function walk(amount) { return new Promise((resolve, reject) => { if (amount < 500) { reject('the value is too small') } setTimeout(() => resolve(`you walked for ${amount}ms`), amount) }) } walk(1000) .then((res) => { console.log(res) return walk(500) }) .then((res) => { console.log(res) return walk(700) }) .then((res) => { console.log(res) return walk(800) }) .then((res) => { console.log(res) return walk(100) }) .then((res) => { console.log(res) return walk(400) }) .then((res) => { console.log(res) return walk(600) }) // you walked for 1000ms // you walked for 500ms // you walked for 700ms // you walked for 800ms // uncaught exception: the value is too small ``` Let's see how we can rewrite this `Promise` with the new async/await syntax.
    ## Async and Await ```javascript function walk(amount) { return new Promise((resolve, reject) => { if (amount < 500) { reject('the value is too small') } setTimeout(() => resolve(`you walked for ${amount}ms`), amount) }) } // create an async function async function go() { // use the keyword `await` to wait for the response const res = await walk(500) console.log(res) const res2 = await walk(900) console.log(res2) const res3 = await walk(600) console.log(res3) const res4 = await walk(700) console.log(res4) const res5 = await walk(400) console.log(res5) console.log('finished') } go() // you walked for 500ms // you walked for 900ms // you walked for 600ms // you walked for 700ms // uncaught exception: the value is too small ``` Let's break down what we just did: - to create an `async` function we need to put the `async` keyword in front of it - the keyword will tell `JavaScript` to always return a promise - if we specify to `return ` it will return a value wrapped inside a promise - the `await` keyword **only** works inside an `async` function - as the name implies, `await` will tell `JavaScript` to wait until the promise returns its result Let's see what happens if we try to use `await` outside an `async` function ```javascript // use await inside a normal function function func() { let promise = Promise.resolve(1); let result = await promise; } func(); // SyntaxError: await is only valid in async functions and async generators // use await in the top-level code let response = Promise.resolve('hi'); let result = await response; // SyntaxError: await is only valid in async functions and async generators ``` > **Remember**: You can only use `await` inside an `async` function.
    ## Error handling In a normal promise we would use `.catch()` to catch eventual errors returned by the promise. Here, it is not much different: ```javascript async function asyncFunc() { try { let response = await fetch('http:your-url') } catch (err) { console.log(err) } } asyncFunc() // TypeError: failed to fetch ``` We use `try...catch` to grab the error, but in a case where we do not have them we can still catch the error like this: ```javascript async function asyncFunc() { let response = await fetch('http:your-url') } asyncFunc() // Uncaught (in promise) TypeError: Failed to fetch asyncFunc().catch(console.log) // TypeError: Failed to fetch ```
    {' '}
    ## ES2018 Async Iteration and more? Let's now have a look at what was introduced with ES2018.
    ## Rest / Spread for Objects Remember how ES6 (ES2015) allowed us to do this? ```javascript const veggie = ['tomato', 'cucumber', 'beans'] const meat = ['pork', 'beef', 'chicken'] const menu = [...veggie, 'pasta', ...meat] console.log(menu) // Array [ "tomato", "cucumber", "beans", "pasta", "pork", "beef", "chicken" ] ``` Now we can use the rest/spread syntax for objects too, let's look at how: ```javascript let myObj = { a: 1, b: 3, c: 5, d: 8, } // we use the rest operator to grab everything else left in the object. let { a, b, ...z } = myObj console.log(a) // 1 console.log(b) // 3 console.log(z) // {c: 5, d: 8} // using the spread syntax we cloned our Object let clone = { ...myObj } console.log(clone) // {a: 1, b: 3, c: 5, d: 8} myObj.e = 15 console.log(clone) // {a: 1, b: 3, c: 5, d: 8} console.log(myObj) // {a: 1, b: 3, c: 5, d: 8, e: 15} ``` With the spread operator we can easily create a clone of our `Object` so that when we modify the original `Object`, the clone does not get modified, similarly to what we saw when we talked about arrays.
    ## Asynchronous Iteration With Asynchronous Iteration we can iterate asynchronously over our data. From the documentation: > An async iterator is much like an iterator, except that its `next()` method returns a promise for a `{ value, done }` pair. To do so, we will use a `for-await-of` loop which works by converting our iterables to a Promise, unless they already are one. ```javascript const iterables = [1, 2, 3] async function test() { for await (const value of iterables) { console.log(value) } } test() // 1 // 2 // 3 ``` > During execution, an async iterator is created from the data source using the `[Symbol.asyncIterator]()` method. > Each time we access the next value in the sequence, we implicitly await the promise returned from the iterator method.
    ## `Promise.prototype.finally()` After our promise has finished we can invoke a callback. ```javascript const myPromise = new Promise((resolve, reject) => { resolve() }) myPromise .then(() => { console.log('still working') }) .catch(() => { console.log('there was an error') }) .finally(() => { console.log('Done!') }) ``` `.finally()` will also return a `Promise` so we can chain more `then` and `catch` after it but those Promises will fulfill based on the `Promise` they were chained onto. ```javascript const myPromise = new Promise((resolve, reject) => { resolve() }) myPromise .then(() => { console.log('still working') return 'still working' }) .finally(() => { console.log('Done!') return 'Done!' }) .then((res) => { console.log(res) }) // still working // Done! // still working ``` As you can see the `then` chained after `finally` returned the value that was returned by the `Promise` created not by `finally` but by the first `then`.
    ## RegExp features Four new RegExp related features made it to the new version of `ECMAScript`. They are: - [`s(dotAll)` flag for regular expressions](https://github.com/tc39/proposal-regexp-dotall-flag) - [RegExp named capture groups](https://github.com/tc39/proposal-regexp-named-groups) - [RegExp Lookbehind Assertions](https://github.com/tc39/proposal-regexp-lookbehind) - [RegExp Unicode Property Escapes](https://github.com/tc39/proposal-regexp-lookbehind)
    ### `s (dotAll)` flag for regular expression This introduces a new `s` flag for `ECMAScript` regular expressions that makes `.` match any character, including line terminators. ```javascript ;/foo.bar/s.test('foo\nbar') // true ```
    ### RegExp named capture groups [From the documentation:](https://github.com/tc39/proposal-regexp-named-groups) > Numbered capture groups allow one to refer to certain portions of a string that a regular expression matches. Each capture group is assigned a unique number and can be referenced using that number, but this can make a regular expression hard to grasp and refactor. For example, given` /(\d{4})-(\d{2})-(\d{2})/` that matches a date, one cannot be sure which group corresponds to the month and which one is the day without examining the surrounding code. Also, if one wants to swap the order of the month and the day, the group references should also be updated. A capture group can be given a name using the `(?...)` syntax, for any identifier `name`. The regular expression for a date then can be written as `/(?\d{4})-(?\d{2})-(?\d{2})/u`. Each name should be unique and follow the grammar for `ECMAScript` IdentifierName.Named groups can be accessed from properties of a `groups` property of the regular expression result. Numbered references to the groups are also created, just as for non-named groups. For example: ```javascript let re = /(?\d{4})-(?\d{2})-(?\d{2})/u let result = re.exec('2015-01-02') // result.groups.year === '2015'; // result.groups.month === '01'; // result.groups.day === '02'; // result[0] === '2015-01-02'; // result[1] === '2015'; // result[2] === '01'; // result[3] === '02'; let { groups: { one, two }, } = /^(?.*):(?.*)$/u.exec('foo:bar') console.log(`one: ${one}, two: ${two}`) // one: foo, two: bar ```
    ### RegExp Lookbehind Assertions [From the documentation:](https://github.com/tc39/proposal-regexp-lookbehind) > With lookbehind assertions, one can make sure that a pattern is or isn't preceded by another, e.g. matching a dollar amount without capturing the dollar sign. Positive lookbehind assertions are denoted as `(?<=...)` and they ensure that the pattern contained within precedes the pattern following the assertion. For example, if one wants to match a dollar amount without capturing the dollar sign, `/(?<=\$)\d+(\.\d*)?/` can be used, matching `'$10.53'` and returning `'10.53'`. This, however, wouldn't match `€10.53`. Negative lookbehind assertions are denoted as `(? ### RegExp Unicode Property Escapes [From the documentation:](https://github.com/tc39/proposal-regexp-unicode-property-escapes) > This brings the addition of Unicode property escapes of the form `\p{…}` and` \P{…}`. Unicode property escapes are a new type of escape sequence available in regular expressions that have the `u` flag set. With this feature, we could write: ```javascript const regexGreekSymbol = /\p{Script=Greek}/u regexGreekSymbol.test('π') // true ```
    ## Lifting template literals restriction When using _tagged_ template literals the restriction on escape sequences are removed. You can read more [here.](https://tc39.github.io/proposal-template-literal-revision/#sec-template-literals)
    ## What's new in ES2019? Let's have a look at what is included in the latest version of `ECMAScript`: ES2019.
    ## `Array.prototype.flat()` / `Array.prototype.flatMap()` `Array.prototype.flat()` will flatten the array recursively up to the depth that we specify. If no depth argument is specified, 1 is the default value. We can use `Infinity` to flatten all nested arrays. ```javascript const letters = ['a', 'b', ['c', 'd', ['e', 'f']]] // default depth of 1 letters.flat() // ['a', 'b', 'c', 'd', ['e', 'f']] // depth of 2 letters.flat(2) // ['a', 'b', 'c', 'd', 'e', 'f'] // which is the same as executing flat with depth of 1 twice letters.flat().flat() // ['a', 'b', 'c', 'd', 'e', 'f'] // Flattens recursively until the array contains no nested arrays letters.flat(Infinity) // ['a', 'b', 'c', 'd', 'e', 'f'] ``` `Array.prototype.flatMap()` is identical to the previous one with regards to the way it handles the 'depth' argument but instead of simply flattening an array, with `flatMap()` we can also map over it and return the result in the new array. ```javascript let greeting = ['Greetings from', ' ', 'Vietnam'] // let's first try using a normal `map()` function greeting.map((x) => x.split(' ')) // ["Greetings", "from"] // ["", ""] // ["Vietnam"] greeting.flatMap((x) => x.split(' ')) // ["Greetings", "from", "", "", "Vietnam"] ``` As you can see, if we use `.map()` we will get a multi level array, a problem that we can solve by using `.flatMap()` which will also flatten our array.
    ## `Object.fromEntries()` `Object.fromEntries()` transforms a list of key-value pairs into an object. ```javascript const keyValueArray = [ ['key1', 'value1'], ['key2', 'value2'], ] const obj = Object.fromEntries(keyValueArray) // {key1: "value1", key2: "value2"} ``` We can pass any iterable as argument of `Object.fromEntries()`, whether it's an `Array`, a `Map` or other objects implementing the iterable protocol. You can read more about the iterable protocol here: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol)
    ## `String.prototype.trimStart()` / `.trimEnd()` `String.prototype.trimStart()` removes white space from the beginning of a string while `String.prototype.trimEnd()` removes them from the end. ```javascript let str = ' this string has a lot of whitespace ' str.length // 42 str = str.trimStart() // "this string has a lot of whitespace " str.length // 38 str = str.trimEnd() // "this string has a lot of whitespace" str.length // 35 ``` We can also use `.trimLeft()` as an alias of `.trimStart()` and `.trimRight()` as an alias of `.trimEnd()`.
    ## Optional Catch Binding Prior to ES2019 you had to always include an exception variable in your `catch` clause. E2019 allows you to omit it. ```javascript // Before try { ... } catch(error) { ... } // ES2019 try { ... } catch { ... } ``` This is useful when you want to ignore the error. For a more detailed list of use cases for this I highly recommend this article: [http://2ality.com/2017/08/optional-catch-binding.html](http://2ality.com/2017/08/optional-catch-binding.html)
    ## `Function​.prototype​.toString()` The `.toString()` method returns a string representing the source code of the function. ```javascript function sum(a, b) { return a + b } console.log(sum.toString()) // function sum(a, b) { // return a + b; // } ``` It also includes comments. ```javascript function sum(a, b) { // perform a sum return a + b } console.log(sum.toString()) // function sum(a, b) { // // perform a sum // return a + b; // } ```
    ## `Symbol.prototype.description` `.description` returns the optional description of a `Symbol` Object. ```javascript const me = Symbol('Alberto') me.description // "Alberto" me.toString() // "Symbol(Alberto)" ```
    ## Download the cheatsheet If you want to download this cheatsheet please follow this link

    --- # What is MDX and how you can use it on your Gatsby blog Published: 2019-12-27T00:00:00.000Z Modified: 2019-12-27T00:00:00.000Z Category: article Tags: beginners, article Keywords: javascript, mdx, markdown, gatsby mdx, gatsbyjs, mdx in gatsby URL: https://montalesi.dev/blog/article/what-is-mdx ## Why I love writing using Markdown If you never used Markdown, let me introduce it to you in a few words. It's a simple conversion tool that allows you to write a simple text format that gets converted to valid HTML. For example, to create headings (`h1`) you would do use `#`, to create bold tags you would use `**text**` and so on, you can read more about Markdown on this guide. Since the moment I've started using Markdown, I fell in love with it. It's so simple, yet so powerful and I even went as far as using it to write a 300 pages book ([here](https://github.com/AlbertoMontalesi/The-complete-guide-to-modern-JavaScript) if you are curious). It allows me to use the same format to write articles on my blog and Dev.To and if I need, I can use tools like Pandoc to easily convert it to PDF or DOC. There are many apps you can use to write Markdown, I talk about my favorite here. After using it extensively on my blog ([Montalesi.dev](https://Montalesi.dev)) I felt like I wanted it to do more, to be able to more easily implement custom HTML and JS inside of it. Markdown supports HTML so, for example, if you want to have a particular heading in your article, you can still write: ```html

    I am a special Heading

    ``` instead of writing the following, which would make impossible to add a custom `id` to the HTML tag. ```markdown ## I am a special Heading ``` I like my Markdown to be as clean as possible so I tend to avoid putting too much HTML inside of it, but there are times where it can be useful. Sometimes I felt like it would have been nice to implement that cool carousel component in the middle of my article, instead of putting it at the end, outside of the Markdown file and in the JSX template of the page (in the case of a Gatsby blog). Unfortunately, in Markdown I would have not been able to do so and that is where I discovered **MDX**.
    ## What is MDX and why it's awesome MDX is for JSX what MD is for JS. Thanks to it you can now easily import your components inside of an MDX file and seamlessly integrate them in your Markdown. If now I want to add that nice carousel component in the middle of my article I can do it in just two lines: First I need to import the component like so: ```JSX import Carousel from "nuka-carousel"; ``` and then I use it the same way I would in a JSX file: ```JSX ``` The rest of my article doesn't have to change at all, I can continue writing `##` for my `h2` etc. > Remember that if you are referencing your components, the path needs to be relative to the folder where the **MDX** file is located.
    ## How to install it on my Gatsby blog I had two pre-existing Gatsby blogs that I wanted to migrate to use **MDX** and it took me roughly 10 minutes to do that. To summarize the steps you need to take to upgrade your existing blog: 1. Install the required packages like so: `npm install --save gatsby-plugin-mdx @mdx-js/mdx @mdx-js/react` and remember to uninstall your old `gatsby-transformer-remark` plugin. 2. Go inside your `gatsby-config` file and replace the old `gatsby-transformer-remark` with the new `gatsby-plugin-mdx` and be sure to add ` extensions: [`.mdx`, `.md`],` inside the options array of the plugin 3. Inside of `gatsby-node.js`, you need to replace mentions of `allMarkdownRemark` with `allMdx` 4. Find your `index.js` page or wherever you display a list of posts and replace all mentions of `allMarkdownRemark.edges` with `allMdx.edges`. Remember to replace it in the GraphQL query. 5. Inside of your single post template you need to replace `data.markdownRemark` with `data.mdx`. Again, remember to replace it in the GraphQL query too. 6. Inside of your single post template, add `import { MDXRenderer } from "gatsby-plugin-mdx"` and replace mentions of `html` with `body` both in the code and in the query. 7. In the last step, we need to replace the section where we use `dangerouslySetInnerHTML` with the new `{post.body}` and remember to replace `post.body` with the relevant variable name you are using in your template. That should do it. During my process of upgrading, I've encountered a few errors but all related to some unclosed HTML tags in my Markdown files, once I fixed those minor issues everything was smooth. I bet your migration will also go smoothly. If you need a more in-depth guide to upgrade, you should check out the official Gatsby blog they also have articles to implement MDX on a new blog, in case you are not coming from a pre-existing one like me.
    ## Working with MDX Working with **MDX** has been great so far, I haven't encountered any problem and the ability to add components to my Markdown files, without having to give up the simplicity of the Markdown syntax, has been amazing. If you are working on VSCode, you will have to install a new extension to enable syntax highlight. You can just search for **MDX** in the extension store and the first one that comes up will be good for you. If you encounter any bug while using **MDX** please report them in Github at this link
    ## Caveats for working with MDX If you know how GatsbyJS works, you will know that each JS file in the **pages** folder will become a page. If you are working with Markdown files, this won't matter but if you are using MDX then you need to be aware that each MDX file inside of that folder will also become a page. So, for example, if you have a folder called **blog** in your **pages** folder, each `.mdx` file will become a page of URL `Sitename/blog/fileName`. If you don't want to automatically generate pages and instead want to create your own, inside of **gatsby-node** then the solution it's simple: move the **blog** folder outside of **pages**. By doing that you will skip the automatic generation and instead you will be able to manually define the way you want those pages to be created in the **gatsby-node** file. Remember to update the import paths of your components in the MDX files when you move the folder! ## Final Considerations What are your thoughts about **MDX**? Was this the first time you heard about it? Did it catch your attention? Or have you been using it for a while? In that case, what is your experience with it? Leave a comment. --- # 5 Best Gatsby plugins for your programming blog Published: 2019-12-21T00:00:00.000Z Modified: 2019-12-21T00:00:00.000Z Category: article Tags: beginners, article Keywords: gatsby plugins, static site, blog, GatsbyJS URL: https://montalesi.dev/blog/article/5-best-gatsby-plugins ## What is GatsbyJS? GastbyJS is a Static Site Generator that you can use to build super fast blogs and websites. Together with Hugo and Jekyll is the most popular and it's currently my favorite one due to the fact that it uses React. Getting started with GatsbyJS is very easy and if you download one of their starter template you can get your blog up and running in literally five minutes, just push your code to Github and deploy to Netlify. If you want two examples of blogs built with GatsbyJS you can check out my girlfriend's vietnamese learning website elingos.com. One thing I like about GatsbyJS is the ecosystem of plugins you can use to extend its functionalities and to make your life easier. Being built on React means that every React plugin that you love will work on GatsbyJS but in this article i'm going to cover my favorite plugins specifically for GatsbyJS. In this article I will introduce you to what I think are 5 of the best plugins for GatsbyJS. These are all plugins that I currently use on my two aforementioned websites.   ## gatsby-remark-prismjs If you are building a programming blog such as mine, chances are you are going to need syntax highlight for your code blocks. This plugin will make it very easy to add PrismJS to your website, letting you choose among different choices of syntax highlight which you can preview on the [PrismJS website](https://prismjs.com/). You can get it [here](https://www.gatsbyjs.org/packages/gatsby-remark-prismjs/)   ## gatsby-plugin-google-analytics This plugin will let you easily connect your GatsbyJS website to Google Analytics so that you can have a clear idea of how many users you have and their behavior. What I like about this plugin is the `a` component that let's you track clicks on outbound links. I use it to track how many people click on my Leanpub link to check out my [book](https://leanpub.com/completeguidetomodernjavascript2020). You can get this plugin [here](https://www.gatsbyjs.org/packages/gatsby-plugin-google-analytics/).   ## gatsby-plugin-manifest Progressive Web Apps are amazing, I love them, and the choice of making your site a PWA should be a no brainer. This plugin will help you easily set up a manifest for your website so that users can add it to their home screen. You can edit the color and the background of the splash page and the plugin also helps you autogenerate icons. Making your site a PWA can enhance the experience of your followers and make it much easier for them to get back to your site from the home screen of their phones. You can get this plugin [here](https://www.gatsbyjs.org/packages/gatsby-plugin-manifest/).   ## gatsby-transformer-json When you write blog posts on your GatsbyJS you will mostly use Markdown, and for that you will need the plugin `gatsby-transformer-remark` but there are times where you might want to have configuration files and you are probably going to store them as JSON files. In my case, I have JSON file called products where I store information about different articles, such as title, description, price and image. Those information are then pulled in the page with the use of this plugin and I dynamically generate cards to display my products. To see what I mean you can check out [this page of one of my sites](http://elingos.com/shop). Other examples of instances where I would use a JSON file are: a list of team members or a list of testimonials. You can get this plugin [here](https://www.gatsbyjs.org/packages/gatsby-transformer-json/).   ## gatsby-plugin-react-helmet This plugin adds support for React Helmet, a component which lets you control your document head using their React component. This includes passing metadata such as page title, description and different images for when your page get's shared on social medias. It's definitely a useful plugin that will make your life (and your SEO) better. You can get this plugin [here](https://www.gatsbyjs.org/packages/gatsby-plugin-react-helmet/).   This concludes the list of my 5 favorite GatsbyJS plugin. If you know others that can be useful or that you personally love, please leave a comment and share them with everybody. --- # Send automated tweets from a Google Sheet with Google Scripts Published: 2019-11-23T00:00:00.000Z Modified: 2019-11-23T00:00:00.000Z Category: tutorial Tags: beginners, tutorial Keywords: twitter, google script, send tweet, send automated tweets, google scripts URL: https://montalesi.dev/blog/tutorial/send-daily-tweets-from-google-sheet   ## What we are going to build My girlfriend runs a [Vietnamese language blog](https://elingos.com) (which you should definitely check out, it's static site built with Gatsby that she designed and I built) and I wanted to help her be able to start a _Word of the day_ project for twitter. Having to go to Twitter every day just to post a new word is not ideal, repetitive tasks are the worst, they are boring and take up time that you could spend doing something else. That's why I set up a simple Google Script to post a new tweet everyday from a Google Sheet. The whole process took me less than 2 hours with zero prior knowledge of how to use Google Scripts (which is very easy to use if you are familiar with JavaScript). At the end of this tutorial you will know **how to create a script to get rows from a Google Sheet and send them as tweets**. ## Set up   Firstly, before we start we will need a twitter developer account, to do that follow this [link](https://developer.twitter.com/en/apps). Once you apply it will take roughly a few hours to get approved. What you want to do after that is create a new app and save both the Consumer API keys and the Access token & access token secret. Remember to not share them with anyone! While your application is still pending approval from Twitter let's start creating our Google Sheet: ![Google sheet](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/google-sheet-twitter/google-sheet1.png) It's a simple sheet with 4 column: 3 for the content and 1 for the date that will be used to post that tweet. Now, inside of Google Sheet click on _Tools_ > _Script editor_ and a new window will open where you can write your Google Script. Before we start writing our code, let's import the Twitter library that we'll need. To do that you need to click _Resources_ > _Libraries_ and paste this code inside of the _Add library_ field: `MKvHYYdYA4G5JJHj7hxIcoh8V4oX7X1M_`. ![Google script library](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/google-sheet-twitter/google-sheeet2.png) Before you save, rename the identifier of the library to `Twitter`, just so we can call methods on `Twitter.` instead of `Twitterlib.`, not necessary but just a personal preference.   ## Writing the Google Script Now it's finally time to write our script which we can break down in two parts: - parse the Google Sheet content, get the correct row and construct our tweet - authenticate Twitter and tweet our post My Google Sheet is structured so that I will be able to tweet a different _Word of the day_ everyday. The first thing I need to do is to parse the Google Sheet content and find the correct row to post today. Let's start by getting our sheet like this: ```js function sendDailyTweet() { var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet() var startRowNumber = 1 var endRowNumber = sheet.getLastRow() } ``` Now what we want to do is to loop over all our rows and see if the date of that row corresponds to today. Our function now will look like this: ```js function sendDailyTweet() { var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet() var startRowNumber = 1 var endRowNumber = sheet.getLastRow() // variables to create our tweet var vietnameseWord var englishWord var sentenceExample var identifier for ( var currentRowNumber = startRowNumber; currentRowNumber <= endRowNumber; currentRowNumber++ ) { var row = sheet.getRange(currentRowNumber + ':' + currentRowNumber).getValues() // check that the fourth column (Date) is equal to today if (isToday(row[0][3])) { console.log(row) break } } } ``` What we are doing now is loop over each row and get the content of it with `sheet.getRange(currentRowNumber + ":" + currentRowNumber).getValues();`. What we get is a an `Array` containing an `Array` of values, one per column. Since the date was stored in the 4th column, I'm getting it like this: `row[0][3]` and passing it as an argument to the `isToday` function that we can define outside of our primary function as: ```js function isToday(date) { var today = new Date() var dateFromRow = new Date(date) return ( dateFromRow.getDate() == today.getDate() && dateFromRow.getMonth() == today.getMonth() && dateFromRow.getFullYear() == today.getFullYear() ) } ``` This function is very simple and will help us compare the current date with the one stored in that particular row. If they match it will return `true` If you try now to run your code everything should work fine and you can see the output of the `console.log` by clicking on the menu _View_ > _Stackdriver Logging_. Now, replace that `console.log` with the following lines: ```js vietnameseWord = row[0][0] englishWord = row[0][1] sentenceExample = row[0][2] identifier = currentRowNumber - 1 ``` We are simply assigning values to all the variables that we need based on the corresponding column. Hopefully by now Twitter already approved your request so you can continue implementing the final part of this code. After you create a new app on https://developer.twitter.com/ define a new `Object` inside of your `sendDailyTweet` function and replace my placeholders with your keys: ```js var twitterKeys = { TWITTER_CONSUMER_KEY: '[your_key_here]', TWITTER_CONSUMER_SECRET: '[your_key_here]', TWITTER_ACCESS_TOKEN: '[your_key_here]', TWITTER_ACCESS_SECRET: '[your_key_here]', } ``` Next, right under the `Object` let's store those properties like this: ```js var props = PropertiesService.getScriptProperties() props.setProperties(twitterKeys) // we don't really need params for this example so we'll leave them empty var params = new Array(0) var service = new Twitter.OAuth(props) ``` See this: `new Twitter.OAuth(props);`, we are calling `Twitter.` because we renamed the identifier of the library to `Twitter`, otherwise it would have been `Twitterlib.`. Our final step will be to authenticate and finally send the tweet. Right after our `for` loop, let's add this `if...else`: ```js if (!service.hasAccess()) { console.log('Authentication Failed') } else { console.log('Authentication Successful') } ``` Try running your code now, if the credentials you passed in `props.setProperties(twitterKeys);` are correct, you shouldn't be having any problem. Inside of the `else` statement we will construct our tweet and send it: ```js var status = 'Vietnamese Word #' + identifier + '\n\n' + vietnameseWord + ' - ' + englishWord + '\n\n' + 'E.g: ' + sentenceExample + '\n\n' + 'Comment with your sentence. Learn more @ elingos.com' + '\n\n' + '#wordoftheday #languagelearning #learnvietnamese #vietnameselanguage #elingosvietnamese' try { var response = service.sendTweet(status, params) console.log(response) } catch (e) { console.log(e) } ``` We are using the variables we defined above to create the status for our tweet. Inside of our `try...catch` we try to send our tweet with `service.sendTweet(status, params);`, otherwise we will see the error logged in our console. Awesome, we are done with Google Script, the only thing missing here is a trigger to make our script run everyday. ## Turning on a trigger for the google script To do that we don't have to write a single line of code, from the menu click _Edit_ > _Current project's trigger_ and a new tab will open. Click the button _Add trigger_ in the bottom corner ![google script trigger](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/google-sheet-twitter/google-sheet3.png) These are the settings that I've chosen for my script: - `sendDailyTweet` as the function to run - time-driven as the event source - day timer - 1am to 2am as the time frame This script will run everyday and post a new tweet on the account twitter for [Elingos](https://twitter.com/Elingos1). If you like languages, real ones and not just programming ones, and you want to learn a new one, check out her blog at [Elingos.com](https://elingos.com). You can get the complete code for the script [here](https://github.com/AlbertoMontalesi/InspiredWebDev-Tutorials/blob/master/Google%20Script%20for%20twitter/google%20script.js). If you want to learn even an even more complex script, check out this great article on [Medium](https://medium.com/javascript-in-plain-english/i-made-a-twitter-bot-from-nothing-but-a-google-sheet-ef0ba6e1b194). --- --- # An introduction to CSS Variables Published: 2019-11-12T00:00:00.000Z Modified: 2019-11-12T00:00:00.000Z Category: article Tags: beginners, article Keywords: css variables, css, stylesheet, css stylesheet URL: https://montalesi.dev/blog/article/css-variables Writing CSS may seem like an easy task compared to writing something like JavaScript, at the end of the day, it's just a bunch of styles right? Well, that's generally true and unless you are going for very complex layouts or you have specific needs, CSS is fairly easy to pick up and get started with. Problems may arise when you have a large project and you want to keep your styling consistent throughout all pages. You may feel like using SASS is a bit too overkill but you still want to be able to define values once and re-use them in multiple places. This is where CSS Variables will come to help you. Let's have a look at a basic scenario: ```css .main-section { /* ...other styles */ background-color: #3498db; } .primary-button { /* ...other styles */ color: #3498db; } ``` Here we are styling two different classes with a color. If one day we would like to change that color we would have to replace all mentions of it. With CSS Variables we can simplify the code, writing this: ```css :root { --lightblue: #3498db; } .main-section { /* ...other styles */ background-color: var(--lightblue); } .primary-button { /* ...other styles */ background-color: var(--lightblue); } ``` Let's go through what I did here: - define a variable inside of the pseudo-class `:root` so that we can use it on every element in our document - define the variable using the syntax: `--NAME: VALUE` - inside of your element, use the variable with the syntax `PROPERTY: var(VARIABLE_NAME)` Now, if we want to change that light blue color to a different shade of blue, we only have one place in the code where to do so. Variables are not limited to colors of course! You can use them for whatever you want. Box shadows can be quite long to copy paste on different elements, we can use a variable to simplify our life: ```css :root { --shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75); } div { box-shadow: var(--shadow); -webkit-box-shadow: var(--shadow); -moz-box-shadow: var(--shadow); } ``` And if we want to, we can even go further and combine CSS Variables with `calc()` , a native CSS Function to perform simple calculation. Let's say we defined our container and header height in variables like this: ```css :root { --container-height: 100%; --header-height: 60px; } .container { heigth: var(--container-height); } .header { height: var(--header-height); } ``` We want our content to always take up as much space as there is left under the header. We can do so by writing this: ```css .content { height: calc(100% - 60px); } ``` But what if we want to leverage our variables? ```css .content { height: calc(var(--conainer-height) - var(--header-height)); } ``` It may seem overkill to do that in a simple project but if your styles start to become more complex and you see yourself copying, pasting and editing values multiple times, it's worth creating variables to make editing quicker,easier and less prone to error since you only have one spot to tweak.   ### Can i use CSS Variables and `calc()` ? The answer is a big YES, you can. Unless you have to provide support for old browsers, these two properties are supported in all modern browsers. You can see the two screenshots below, taken from [caniuse.com](https://caniuse.com/). If you need support for IE you can use this polyfifll for CSS Variables https://www.npmjs.com/package/css-vars-ponyfill. ![css variables can i use it map](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/css-variables/css-variables.png)   ![css calc can i use it map](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/css-variables/calc.png) Now open the most messy CSS stylesheet you have in your computer and start cleaning it up with the use of variables. --- # What's new in JavaScript: Optional Chaining Published: 2019-10-25T00:00:00.000Z Modified: 2019-10-25T00:00:00.000Z Category: article Tags: beginners, article Keywords: javascript, optional chaining, javascript optional chaining URL: https://montalesi.dev/blog/article/what-is-optional-chaining   As of the date of writing this article (24th October 2019), Optional Chaining is at Stage 3 of the TC39 process, meaning that you won't be able to natively use it in your browser yet. You can read more about the stages of the TC39 process [here](https://tc39.es/process-document/).   ## What is Optional Chaining? Let's take these simple `Object` that represent our Users. ```js const user1 = { name: 'Alberto', age: 27, work: { title: 'software developer', location: 'Vietnam', }, } const user2 = { name: 'Tom', age: 27, } ``` Let's say we want to display the job title of our user. As we can see, `work` is an optional property of our `Object` so we would have to write something like this: ```js let jobTitle if (user.work) { jobTitle = user.work.title } ``` or using a ternary operator: ```js const jobTitle = user.work ? user.work.title : '' ``` Before we access the property `title` of `work` we need to check that the user actually has a `work`. When we are dealing with simple objects it's not such a big deal but when the data we are trying to access is deeply nested, it can be a problem. This is where the Optional Chaining `?.` operator comes to the rescue. This is how we would rewrite our code with this new operator: ```js const jobTitle = user.work?.title ``` Done! More concise and readable. You can read the code above as `does the user have a work property? if yes, access the title property inside of it` ```js const user1JobTitle = user1.work?.title // software developer const user2JobTtile = user2.work?.title // undefined ``` As soon as we hit a property that is not available on the `Object`, the operator will return `undefined` Imagine dealing with a deeply nested object with optional properties such as these two users and their school record. ```js const elon = { name: 'Elon Musk', education: { primary_school: { /* primary school stuff */ }, middle_school: { /* middle school stuff */ }, high_school: { /* high school stuff here */ }, university: { name: 'University of Pennsylvania', graduation: { year: 1995, }, }, }, } const mark = { name: 'Mark Zuckerberg', education: { primary_school: { /* primary school stuff */ }, middle_school: { /* middle school stuff */ }, high_school: { /* high school stuff here */ }, university: { name: 'Harvard University', }, }, } ``` Not all of our Users have studied in University so that property is going to be optional and the same goes for the graduation as some have dropped out and didn't finish the study. Now imagine wanting to access the graduation year of our two users: ```js let graduationYear if ( user.education.university && user.education.university.graduation && user.education.university.graduation.year ) { graduationYear = user.education.university.graduation.year } ``` And with the Optional Chaining operator: ```js const elonGraduationYear = elon.education.university?.graduation?.year // 1992 const markGraduationYear = mark.education.university?.graduation?.year // undefined ``` This is how you access optional properties with this new operator, if you want to start using it, it's going to be part of TypeScript 3.7 which I highly recommend learning! You can read more about TypeScript 3.7 [here](https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-rc/); Alternatively, you can use [Babel](https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining) to start using this operator. --- # Best laptops for programmer under 800 Dollars Published: 2019-10-14T00:00:00.000Z Modified: 2019-10-14T00:00:00.000Z Category: article Tags: beginners, article Keywords: laptop, laptop for programmer, best laptops for programmer, laptop under 800 URL: https://montalesi.dev/blog/article/best-laptops-under-800 > Disclaimer: I am not a reviewer nor a tester, this are my opinions based on the reviews that I've read online > Disclaimer part 2: Amazon links are affiliate links, if you do not agree with that, you can copy the laptop name and search for it directly on Amazon. As a programmer, my need for a laptop are quite straightforward: - good battery - decent screen - good keyboard + touch pad - good amount of memory I work with JavaScript so, as a full stack developer, I don't need strong GPU, huge storage or a touch screen. This list takes into account the needs of similar developers, if you are a game developer I guess your needs will be a bit different than mine so you might find this list not very useful. In this article I will show you what I think are the best laptops for programmers under 800 dollars. At the end of the article you can find a summary of all the laptops in this list. If your budget is higher, don't worry! I'll soon release a list of laptop between 800 and 1500 dollar.  

    Asus Vivobook S15 - 700/800 USD

    ![Asus Vivobook S15](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/laptop-under-800/vivobook.jpg)   Read a full review here The 2019 version just came out and uses Asus new ScreenPad 2.0 which transforms your touch pad in a 5 inches touch screen that you can use. The link I've put is for the 2018 version with a normal touch pad. What I like: - Beautiful design that makes it look more premium than the price tag - Good performance What I don't like: - Poor color coverage of the display. Not such a big deal if you use your laptop only for programming and not multimedia use.  

    Huawei Matebook D14 - 700 USD

    ![Huawei Matebook D14](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/laptop-under-800/matebook.png)   Read a full review here or here What I like: - Nice, simple design - Great keyboard What I don't like: - Bad touch pad - Average battery life - Smaller display, 14 inches compared to 15.6 of other laptop in this list  

    Acer Swift 3 - 770 USD

    ![Acer Swift 3](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/laptop-under-800/swift3.jpg)   Read a full review here or here. What I like: - Intel Core i7, 16GB ram - Great keyboard and touch pad What I don't like: - Good but not amazing battery life  

    Lenovo Ideapad 530s - 700 USD

    ![Lenovo Ideapad 530s](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/laptop-under-800/ideapad.jpg)   Read a full review here. What I like: - Good performance - Nice Design What I don't like: - Average display   --- If you are not really concerned about carrying around a 2+ kgs laptop and would prefer to save more money by compromising on design or you would like to have a more performant GPU, these are some of my pics.  

    Acer Aspire E15 - 600 USD

    ![Acer Aspire E15](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/laptop-under-800/aspire.jpg)   Read a full review here What I like: - Insane battery life at over 10 hours - Solid performance with i5 8th gen, 256GB SSD and 8GB ram - Great price at only 600 USD What I don't like: - Design is not the best  

    Dell G5 - 700/800 USD

    ![Dell G5](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/laptop-under-800/dellg5.jpg)   Read a full review here What I like: - It has an Intel H CPU instead of a low power U - Dedicated GPU if you also want to game - Good battery life What I don't like: - Bulky and Heavy   ## Summary Note: the link to Amazon will redirect you to your local amazon store, where available. The products in your local store may not have the same specifications, I tried to find the same where possible but sometimes they were not available so read carefully the spec list in amazon! | Model | Asus Vivobook S15 | Huawei Matebook D | Acer Swift 3 | Lenovo Ideapad 530s | Acer Aspire E15 | Dell G5 | | --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | Screen size (in) | 15.6 | 14 | 15.6 | 15.6 | 15.6 | 15.6 | | CPU | Intel Core i7-8565u | AMD R5 | Intel Core i7-8550U | AMD R5 2500U | Intel Core i5-8250U | Intel Core i5 8300H | | RAM (GB) | 8 | 8 | 16 | 16 | 8 | 8 | | Storage SSD (GB) | 256 + 1TB HDD | 256 | 512 | 256 | | 128 + 1TB HDD | | GPU | MX150 | AMD Radeon Vega 8 | Intel UHD Graphics 620 | AMD Radeon Vega 8 | MX150 | NVIDIA GeForce GTX 1050 Ti | | Battery life (in hrs) | ~8 | ~4/5 | ~8 | ~7/8 | ~10 | ~8 | | Weight (in kgs) | 1.5 | 1.5 | 1.7 | 1.7 | 2.5 | 2.7 | | Price | 799 | 699 | 770 | 699 | 599 | 790 | | Link to Amazon | Amazon | Amazon | Amazon | Amazon | Amazon | Amazon | --- # 5 Best note taking apps for programmers Published: 2019-10-13T00:00:00.000Z Modified: 2019-10-13T00:00:00.000Z Category: article Tags: beginners, article Keywords: vscode, markdown, note taking apps, markdown app, typora, notion URL: https://montalesi.dev/blog/article/5-best-note-taking-apps Taking notes is a vital part of learning and as a programmer, we have specific needs that software such as Docs or Word can't cover. That's why I compiled this list of my 5 most favorite note-taking apps. In the past couple of years I've used all of them, some of them I still use them, some I've stopped using, but any of these 5 will help you. You will see that all of them use Markdown (either the standard syntax or a custom one) and that's because I find it the fastest way of taking notes since it allows us to quickly create documents with simple formatting and also allows you to add code block with syntax highlight. Before we look at what app to use to write your notes, if you are serious about the quality of the text, i.e: you will use for an article, documentation or anything like that, I suggest that you use a tool such as Grammarly to ensure there are no spelling errors and weird punctuation mistakes. Now let's look at the 5 best note taking apps for programmers (in my opinion). Note: these apps are all free or have a free tier so you won't need to fork out a cent to start using them.

    1){' '} Notion

    Available for: Windows, macOS, Android, iOS, Web. This is the app I've used to write this blog post. It's great because it's not just a markdown text editor, you can do so much more, including tables, kanbans, calendar into your pages. You can sync your notes across your devices and the fact that it has a Web version means that even if you use Linux, like me, you can still use it. It has very solid support for code blocks, with highlights and the ability to wrap the code. The thing I like about Notion is that it's very powerful, meaning you can do so much more than taking plain notes with it. Since you can insert charts, tables and much more, you can use it to create documentation and/or reports. If you just need to jot down some notes for yourself, don't worry, the app is not overwhelming nor difficult to use even if you are not a power user. The free version includes enough space that you should be good for a while. The paid plan starts at 4\$ a month, reasonable if you are going to use all the features that Notion has to offer, otherwise, there are many other, simpler apps that are available completely for free.

    2) Stackedit

    Available for: Web Stackedit doesn't have a mobile app but you can still use it comfortably from the browser. It's much simpler than Notion, being a straightforward markdown editor that syncs with your Google Drive. I use it daily for my work notes whenever I need to write down my thoughts and I want to make sure that I can access them from both my office computer and my laptop. It's completely free and the markdown files are stored in your Google Drive so if you want to migrate them somewhere else it's going to be very straightforward. The support for code blocks is great, with syntax highlight for any language you need. What I like about StackEdit is that it's very simple, yet has everything I need from a Markdown Editor and it syncs with my Google Drive. If you need a simple Markdown editor to take notes and you need to be able to access your notes from everywhere, StackEdit will be great for you. The only downside I can think of is that it does not have a mobile app, meaning you will be forced to use the browser to edit your notes, good for quick edits but maybe not the best if you are looking for a proper UI suitable for small devices.

    3){' '} Typora

    Available for: Windows, macOS, Linux Simple and clean, Typora is a powerful markdown editor. Unfortunately, it doesn't have a mobile version or a web client, but the desktop client is solid and powerful. I've used it write my first JavaScript ebook and I liked the integration with Pandoc to export my markdown ebook straight into epub, pdf and doc files. It has great support for code blocks, using prism for the syntax highlight and it also allows you to create your CSS file to style the exported PDF files. You can install Pandoc and Typora will easily allow you export your Markdown files to export your notes to _.doc_ or _.epub_ formats, a must if you plan on publishing your material on a platform like Amazon or Leanpub.

    4){' '} Quip

    Available for: Windows, macOS, Web, Android, iOS Quip is the first editor that I've used and albeit I don't use it anymore, it's still a great solution. The mobile app is not the best, but the web client is solid and powerful allowing you to easily add tables and more. Some features are paid but overall the free version is good enough. The support for highlighted code blocks is basic and not on the same level as the others. On the other hand, it has great support for teamwork, meaning that you can leave comments and see what other users are doing on your file, similarly to Google Docs, which makes it great for teams.

    Bonus:{' '} VSCode

    Available for: Windows, macOS, Linux Despite not being meant for it, VSCode is a great note-taking app. When writing the second edition of my ebook I've used VSCode to create individual markdown files and a simple node script to join them into a single one. You can also take advantage of a GitBooks to connect your repo and have your notes published online, available privately or publicly. Editing on the fly is not the easiest since you can't use VSCode on your phone but you can still edit directly the files hosted in the Github repo from apps such as FastHub or similar 3rd party clients. Being a code editor it means you can also have more freedom compared with other Markdown editors. For example, for the second edition of my ebook, I opted for individual Markdown files for each chapter instead of a single large one. Of course, I needed a way of getting a single Markdown file of the entire book to convert to _.epub_ to sell it on Amazon but I just had to write a simple node script to join all the Markdown files together and leverage Pandoc to convert it to _.epub_. That meant I retained the simplicity of working on smaller, individual files without having to waste too much time joining and converting them. --- # 5 Great VSCode extensions for web developers Published: 2019-10-06T00:00:00.000Z Modified: 2019-10-06T00:00:00.000Z Category: article Tags: beginners, article Keywords: vscode extensions, vscode, github URL: https://montalesi.dev/blog/article/5-best-vscode-extensions I use VSCode as my only text editor for both work and personal project, and these are some of my most favorite extensions that every web developer should consider installing. ## 1) [Git Lens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) A must have if you work in a team but still useful even for personal projects, this extension will let you see who edited each line of code. ![i blame you](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/5-vs-code-extensions/gitblame.jpg) ## 2) [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) / [TSLint](https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-typescript-tslint-plugin) As an Angular developer, TS Lint is something I can't live without. Keeping your code clean and aligned with proper style rules makes it easier for you and your colleagues to read and work on. If you don't use TypeScript, be sure to install ES Lint and not TS Lint.   ## 3) [Live Share](https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare) If you are a "lone wolf" you can skip this one but if you work in a team and especially if you work remotely, this is a must have. Several times I got stuck on a problem and live sharing with my senior helped me crack the issue I was struggling with.   ## 4) [Chrome Debugger](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) Stop console-logging everywhere! Just get yourself a debugger and start using breakpoints. Easy to set up and a great time saver, being able to stop your code and have a look at what's going on is a must have that will help you speed up your work.   ## 5) [Settings sync](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync) If you are like me and work on two different machines, you may find this extension very useful, as it will allow you to keep all your computers synced in term of extensions and settings. ## Extra [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) If you are a non native speaker, this extension can help you keep your code free of typos and errors. I still remember that day I was writing tests and i wrote "testes" instead of "tests" ahha you don't want that kind of code to be pushed to production. --- # Create Pomodoro Clock in JavaScript Tutorial | freeCodeCamp Published: 2019-09-09T00:00:00.000Z Modified: 2019-09-09T00:00:00.000Z Category: tutorial Tags: js, tutorials, freecodecamp Keywords: javascript tutorial, freecodecamp, pomodoro clock, free tutorial, pomodoro timer, pomodoro clock with javascript URL: https://montalesi.dev/blog/tutorial/project-2-pomodoro-clock # Create a Pomodoro Clock with JavaScript In this tutorial, inspired by the freeCodeCamp curriculu, we are going to create a [Pomodoro Clock](https://en.wikipedia.org/wiki/Pomodoro_Technique) to help you track the time you spend working on different tasks.   ## The final Pomodoro Clock result ![javascript pomodoro clock gif](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDev-Tutorials/master/screenshots/javascript_pomodoro_clock.gif) ## The Task - Difficulty: Beginner/Intermediate - Tools: Text Editor of your choice - Duration: 1-2 hours These are the user stories for this Pomodoro Clock: - [ ] User can start / pause / stop a timer - [ ] User can edit the title of a task - [ ] User can see a list of the completed pomodoro sessions - [ ] User can customize the duration of each work / break session Now that we know what we want to achieve with this Pomodoro Clock, let's start building a simple HTML structure.   ### Play and Pause a timer We will start by creating a simple HTML structure to display a timer and add buttons to start, pause and stop it. ```html
    ``` Now that we have a basic structure let's start working on our `toggleClock` function in the `script.js` file. This function will be called by all three buttons and will either start, pause or stop the timer. First, let's attach an event listener to our buttons: ```js const pomodoroTimer = document.querySelector('#pomodoro-timer') const startButton = document.querySelector('#pomodoro-start') const pauseButton = document.querySelector('#pomodoro-pause') const stopButton = document.querySelector('#pomodoro-stop') // START startButton.addEventListener('click', () => { toggleClock() }) // PAUSE pauseButton.addEventListener('click', () => { toggleClock() }) // STOP stopButton.addEventListener('click', () => { toggleClock(true) }) ``` We stored each of our buttons in a variable and attached event listeners to them. As you can see, for the `stopButton` we are passing an argument in the `toggleClock` function. You will see why in a moment. In order to know whether we need to play or pause the timer, we need an additional variable which we'll call `isClockRunning` which by default will be bind to `false`. ```js let isClockRunning = false ``` We will need a few more variables to complete our initial set: ```js // in seconds = 25 mins let workSessionDuration = 1500 let currentTimeLeftInSession = 1500 // in seconds = 5 mins; let breakSessionDuration = 300 ``` Now let's start writing our `toggleClock` function. ```js const toggleClock = (reset) => { if (reset) { // STOP THE TIMER } else { if (isClockRunning === true) { // PAUSE THE TIMER isClockRunning = false } else { // START THE TIMER isClockRunning = true } } } ``` `toggleClock` takes one argument, `reset` which gets passed only when we are stopping the timer, otherwise we will look at the value of the variable `isClockRunning` to see whether we need to play or pause the timer. We will leverage the built-in method `setInterval` to track our timer. Inside of the `else` statement, right below `isClockRunning = true` we can write: ```js clockTimer = setInterval(() => { // decrease time left / increase time spent currentTimeLeftInSession-- }, 1000) ``` What this does, is decrease our session time by 1 every second. We want to be able to pause this timer when we click the pause button so go ahead and add this code to the `toggleClock` function right above `isClockRunning = false` : ```js clearInterval(clockTimer) ``` This will clear the timer that we set when we click the play button.   ### Create a function to format and display the time The last step for this initial milestone will be to display the timer in our page. To do that we will create a function called `displayCurrentTimeLeftInSession` which will get called every second from our timer. First, let's add this line right under `currentTimeLeftInSession--;` so that our `setInterval` looks like this ```js clockTimer = setInterval(() => { currentTimeLeftInSession-- displayCurrentTimeLeftInSession() }, 1000) ``` Now, under our `toggleClock` function, let's create a new one: ```js const displayCurrentTimeLeftInSession = () => { const secondsLeft = currentTimeLeftInSession let result = '' const seconds = secondsLeft % 60 const minutes = parseInt(secondsLeft / 60) % 60 let hours = parseInt(secondsLeft / 3600) // add leading zeroes if it's less than 10 function addLeadingZeroes(time) { return time < 10 ? `0${time}` : time } if (hours > 0) result += `${hours}:` result += `${addLeadingZeroes(minutes)}:${addLeadingZeroes(seconds)}` pomodoroTimer.innerText = result.toString() } ``` Wow, I bet you got caught off-guard by this function but don't worry, it's not as complicate as it seems. Since we are storing our timer in seconds, we need a way to format it so that the user can see minutes and seconds and not just seconds. The symbol `%` is called the remainder and you can read more about it [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Remainder). What it does is return the left over of the division of the first and second operand. Example: ```js const x = 70 x % 60 // 10 ``` Now image that `x` is our `secondsLeft`. 70 seconds essentially means 1 minute and 10 seconds. As you can see, by using `% 60` we get the seconds to display. The next step is to get how many minutes are left in our timer and we do that like this: ```js const minutes = parseInt(secondsLeft / 60) % 60 ``` This will return us 1. The last step is to count the hours like so: ```js let hours = parseInt(secondsLeft / 3600) ``` 3600 is the amount of seconds in one hour. A proper clock should display time in this format: "07:08" so we need to have a way to add leading zeroes when the minutes or seconds are less than 10. ```js function addLeadingZeroes(time) { return time < 10 ? `0${time}` : time } ``` This syntax may be confusing for a beginner but this is what is called a ternary operator and it is actually very simple and easy to use. ```js return time < 10 ? `0${time}` : time ``` Everytime before the '?' is what gets evaluated, in this case "is time less than 10?" and the first part in between the '?' and the ':' is what will return if the answer is YES whie the code after the ':' is what returns for a NO answer. In plain text: "If time is less than 10, return time with a zero in front of it (eg: 09 instead of 9) and if time is more than 10, just return it". The last part of the code simply creates a string by interpolating hours (if any), minutes and seconds together. ```js if (hours > 0) result += `${hours}:` result += `${addLeadingZeroes(minutes)}:${addLeadingZeroes(seconds)}` ``` If you don't know what `${}` means, you can read more about string interpolation [here](https://github.com/AlbertoMontalesi/The-complete-guide-to-modern-JavaScript/blob/master/ebook/04_template_literals.md). In short, it allows us to write both variables and plain text together without having to constantly add strings to each other with a plus sign. Once we have our nicely formatted string representing the time left in our timer, it's time to add it to our page with this simple line of code: ```js pomodoroTimer.innerText = result ``` ## Stop and reset the timer Currently we can start and pause the timer but there is no way yet to stop it and reset it. We already created a button for it and we also already hooked it up to an event listener so what is left now is to write the code for it. Inside of our `toggleClock` function, right inside of the first `if` statement `if (reset) {` we write this: ```js stopClock() ``` We are calling a function that we haven't created yet, so let's do it now, outside of our `toggleClock` function. When we stop the clock we want to do a couple of things: - clear the timer that we set - restore the timer to its original state ```js const stopClock = () => { // 1) reset the timer we set clearInterval(clockTimer) // 2) update our variable to know that the timer is stopped isClockRunning = false // reset the time left in the session to its original state currentTimeLeftInSession = workSessionDuration // update the timer displayed displayCurrentTimeLeftInSession() } ``` Ok, now we can reset the timer to its original state and if we press play again we can see it starts again from 25 minutes.   ## Toggle between work and break sessions and display a log of our completed sessions It's time now to upgrade our pomodoro to do a bit more. In this section we will add a couple of features to it: - toggle between a 'work' and 'break' session - display a log of the current completed / stoppped session - be able to edit the label of a 'work' session Go to the top of our code, where we declared all our variables and declare another one, called `type` which will hold a string of either 'work' or 'break': ```js let type = 'Work' ``` First let's start with being able to toggle between 'work' and 'break' session. Find this part of the code: ```js clockTimer = setInterval(() => { // decrease time left / increase time spent currentTimeLeftInSession-- displayCurrentTimeLeftInSession() }, 1000) ``` and substitute the line `currentTimeLeftInSession--;` with `stepDown()`. As we are going to make this part more complicate, it makes sense to take it out of this `setInterval` and make it its own function which I am going to call `stepDown`. This function will be responsible of toggling between a 'work' and 'break' session when the timer runs out. Outside of our `toggleClock` function we are going to create our `stepDown` function like so: ```js const stepDown = () => { if (currentTimeLeftInSession > 0) { // decrease time left / increase time spent currentTimeLeftInSession-- } else if (currentTimeLeftInSession === 0) { // Timer is over -> if work switch to break, viceversa if (type === 'Work') { currentTimeLeftInSession = breakSessionDuration displaySessionLog('Work') type = 'Break' } else { currentTimeLeftInSession = workSessionDuration type = 'Work' displaySessionLog('Break') } } displayCurrentTimeLeftInSession() } ``` This function is fairly simple, let's break it down: - if `currentTimeLeftInSession > 0` it means that the timer is still running, therefore we simply want to decrease it - if `currentTimeLeftInSession === 0` it means that the timer is over and we need to - toggle session type and session duration - display a log of the current sessions As you can see, i've already added a call to `displaySessionLog` but I haven't declared that function yet. This function will take display a simple log of our completed sessions below our timer. Firstly, let's add some HTML to our page to make space for the logs that we are going to display. Update your HTML so that it looks like this: ```html

    Your Sessions

      ``` Let's declare a new variable called `timeSpentInCurrentSession` that will increase every seconds that we spend in our session: ```js let timeSpentInCurrentSession = 0 ``` Now, inside of the `stepDown` function, right under `currentTimeLeftInSession--` let's add this: ```js timeSpentInCurrentSession++ ``` We will reset this counter every time a session finishes because the timer is over or because we stop it. Still inside of `stepDown` we add a line right inside of the `else if (currentTimeLeftInSession === 0) {`: ```js timeSpentInCurrentSession = 0 ``` And also in `stopClock` we add the same line. This way, when the user stops a sessions, or when a session is over, we reset the counter. Now we need to create a function to display the session log: ```js const displaySessionLog = (type) => { const sessionsList = document.querySelector('#pomodoro-sessions') // append li to it const li = document.createElement('li') let sessionLabel = type let elapsedTime = parseInt(timeSpentInCurrentSession / 60) elapsedTime = elapsedTime > 0 ? elapsedTime : '< 1' const text = document.createTextNode(`${sessionLabel} : ${elapsedTime} min`) li.appendChild(text) sessionsList.appendChild(li) } ``` What we are doing here is getting our container `div` and appending a `li` with the content of a label and a duration in minutes. Since we added a stop functionality, we need to also display a log when a user stops a timer. Go inside of our `stopClock` function and edit it to look like this: ```js const stopClock = () => { // new displaySessionLog(type) clearInterval(clockTimer) isClockRunning = false currentTimeLeftInSession = workSessionDuration displayCurrentTimeLeftInSession() // new type = 'Work' } ``` We only added two more lines: - `displaySessionLog(type);` to display the time spent so far in this session - `type = 'Work';` to reset the session to work We want to reset the session to work because it does not make sense for the user to reset a break session and start another break session so we want to always revert to a work session when the user stops. If you think that it should be better to normally toggle the session type instead of always reverting to work you can try to implement it your way. A starting point would be to substitute the line `type = 'Work` with ```js type = type === 'Work' ? 'Break' : 'Work' ``` This will toggle between work and break.   ## Customize the work label and the duration of the sessions In this section we will continue upgradin the pomodoro to be able to customize the label of the work sessions and to be able to also customize the duration of both work and break session. First, we will start with customizing the work label. Inside our HTML code, right above our `div` of id `pomodoro-clock-actions` let's put this code: ```html
      ``` Now your Pomodoro should look like this: ![first look of pomodoro](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/pomodoro-clock/pomodoro-1.png); It's a simple `input` tag with a placeholder. We want to display the label when the user stops or completes a sessions. Also, we will make the label customizable **only** for work sessions, break sessions will always be displayed as break. If you want the pomodoro to allow custom labels for break sessions you are free to try and implement it on your own, it's very easy! First, let's create a new variable right below where we declared all the others: ```js let currentTaskLabel = document.querySelector('#pomodoro-clock-task') ``` Now, we will have to upgrade our `displaySessionLog` function and instead of `let sessionLabel = type;`, write this: ```js if (type === 'Work') { sessionLabel = currentTaskLabel.value ? currentTaskLabel.value : 'Work' workSessionLabel = sessionLabel } else { sessionLabel = 'Break' } ``` What this code does is first look at the type of session we are currently in, if it's a 'work' session, it will look at the value of the `input` tag. In case we left it empty, 'Work' will be displayed, otherwise it will take our custom value. If the session is of type 'Break' it will simply use the string 'Break' as the label for the log. There is one more place where we have to edit the code and that is our `stepDown` function. We need to update the function to take in account labels when finishing a session. When a 'Break' session finishes we want to display the proper 'Work' label and vice versa. Update your `stepDown` function so that the `else if (currentTimeLeftInSession === 0)` looks like this: ```js else if (currentTimeLeftInSession === 0) { timeSpentInCurrentSession = 0; // Timer is over -> if work switch to break, viceversa if (type === 'Work') { currentTimeLeftInSession = breakSessionDuration; displaySessionLog('Work'); type = 'Break'; // new currentTaskLabel.value = 'Break'; currentTaskLabel.disabled = true; } else { currentTimeLeftInSession = workSessionDuration; type = 'Work'; // new if (currentTaskLabel.value === 'Break') { currentTaskLabel.value = workSessionLabel; } currentTaskLabel.disabled = false; displaySessionLog('Break'); } } ``` Since I said that I wanted only the 'Work' label to be customizable, I am disabling the `input` tag when we are in a 'Break' session by using `currentTaskLabel.disabled = true;`; As I mentioned above, if you want you can customize this pomodoro to suit your needs. The thought behind this choice is that I don't think there is a need for a user to customize a 'Break' label since that would make it more confusing but maybe you want to let your user edit it so they can differentiate a 'toilet break' from a 'coffe break'. Now, the next step is going to be the customization of the duration of both type of session. First, let's start adding two new `input` tags to our HTML. Update your code so that it looks like this: ```html
      Changes made here will reflect at the start of the next work / break session

      Your Sessions

      ``` I have added a new title that says `Changes made here will reflect at the start of the next work / break session`, this is to let the user know that if they change the duration of a session, that will not affect the current one but only the next one onwards. I have also added two new `input` tags, one for 'Work' sessions, one for 'Break' sessions. Don't worry too much about the classes and the overall styling of the pomodoro, we will style it at the end, now we are just focusing on the functionalities. Since we said that the updated timers will be counted at the beginning of the next session, that means that when the user edits them they won't affet our variable `workSessionDuration` and `breakSessionDuration` right away but they will be stored in two other variables and only when a session ends (because it runs out of time or because it gets stopped by the user) they will update the original timers. Let's start updating our code by first declaring four new variables at the top: ```js let updatedWorkSessionDuration let updatedBreakSessionDuration let workDurationInput = document.querySelector('#input-work-duration') let breakDurationInput = document.querySelector('#input-break-duration') workDurationInput.value = '25' breakDurationInput.value = '5' ``` As you can see we are manually setting 25 and 5 as the values for our two input tags. To make life easier we are using a string representing the minutes in that timer. That means that the user will be allowed to edit the timer with a precision of 1 minute. That also means that we will have to transform those values from minutes to seconds once we want to update the timer. Now let's add an event listener to each of our `input` tags right below our other event listeners. ```js // UPDATE WORK TIME workDurationInput.addEventListener('input', () => { updatedWorkSessionDuration = minuteToSeconds(workDurationInput.value) }) // UPDATE PAUSE TIME breakDurationInput.addEventListener('input', () => { updatedBreakSessionDuration = minuteToSeconds(breakDurationInput.value) }) ``` Whenever a user inputs a new value in one of those `input` tags we are updating our temporary variable with a new value. Here i am calling a function called `minuteToSeconds` that will help us convert the minute string from the `input` tag to seconds. Right below the code we just wrote, add this: ```js const minuteToSeconds = (mins) => { return mins * 60 } ``` Very simply, to get a second we multiply the minutes by 60. Now we will need to add a new function that will be called everytime we stop or we finish a session. This function will do two things: - look at the `updatedBreakSessionDuration` to see if the user updated the session duration - if it did, then it will set the new session duration based on the value input by the user We will call this function `setUpdatedTimers`. ```js const setUpdatedTimers = () => { if (type === 'Work') { currentTimeLeftInSession = updatedWorkSessionDuration ? updatedWorkSessionDuration : workSessionDuration workSessionDuration = currentTimeLeftInSession } else { currentTimeLeftInSession = updatedBreakSessionDuration ? updatedBreakSessionDuration : breakSessionDuration breakSessionDuration = currentTimeLeftInSession } } ``` If type is 'Work' we check if the user updated the `updatedWorkSessionDuration`. If yes, we set that as the value for the next session, else we use the default value from `workSessionDuration`. Same goes for 'Break' session. We don't want to update the timer when the user pause and then starts a new session so we are going to have a new variable called `isClockStopped` that will help us know when we are starting the clock the first time and when we are starting it after a stop. ```js let isClockStopped = true ``` By default it's true. Let's update our `toggleClock` function like this: ```js const toggleClock = (reset) => { if (reset) { stopClock() } else { // new if (isClockStopped) { setUpdatedTimers() isClockStopped = false } if (isClockRunning === true) { // pause clearInterval(clockTimer) // update icon to the play one // set the vale of the button to start or pause isClockRunning = false } else { // start clockTimer = setInterval(() => { stepDown() displayCurrentTimeLeftInSession() }, 1000) isClockRunning = true } } } ``` I have added this code: ```js if (isClockStopped) { setUpdatedTimers() isClockStopped = false } ``` Let's also add a call inside of our `stepDown` function so that we will update the timers when a session finishes. Add this function call: `setUpdatedTimers();` under these two lines `type = "Break";` and `type = "Work";` When the clock is stopped it means we are starting the clock and not simply resuming after a pause. In that case we set our updated timers and toggle the variable to false. The last part to update is our `stopClock` function which will look like this: ```js const stopClock = () => { setUpdatedTimers() displaySessionLog(type) clearInterval(clockTimer) isClockStopped = true isClockRunning = false currentTimeLeftInSession = workSessionDuration displayCurrentTimeLeftInSession() type = 'Work' timeSpentInCurrentSession = 0 } ``` When the user stops the clock, we set our variable `isClockStopped` to true and we call `setUpdatedTimers`. Awesome, now we have a fully functional Pomodoro clock. There are a few things left to do before we can call it a day.   ## Add a circular progress bar to the timer In this section we will finish our Pomodoro by adding some style to it and also implementing a circular progress bar which will show the user the progress they made so far in the current session. Before we do that, I want to update our play, pause and stop buttons to use icons instead of text. I also want to only have the play icon show when the pomodoro is paused and the pause icon when the pomodoro is playing. First, let's add Font Awesome icons to our project. Copy this code insid the `head` of our HTML: ```html ``` Now update your buttons like this: ```html ``` I ditched one of the `button` tag because we won't need it as we will simply be toggling the icon inside of the 'Play' button so go in your js code and remove these lines: ```js const pauseButton = document.querySelector('#pomodoro-pause') // PAUSE pauseButton.addEventListener('click', () => { toggleClock() }) ``` In your css file you can define the class `hidden` as such: ```css .hidden { display: none; } ``` Done! It was very easy but the overall look of the Pomodoro is now much better. ![second look of pomodoro](https://raw.githubusercontent.com/AlbertoMontalesi/InspiredWebDevAssets/master/images/articles/pomodoro-clock/pomodoro-2.png); Let's go one step further and hide the pause icon when the clock is not working. To do that, we will create a function called `togglePlayPauseIcon` ```js const togglePlayPauseIcon = (reset) => { const playIcon = document.querySelector('#play-icon') const pauseIcon = document.querySelector('#pause-icon') if (reset) { // when resetting -> always revert to play icon if (playIcon.classList.contains('hidden')) { playIcon.classList.remove('hidden') } if (!pauseIcon.classList.contains('hidden')) { pauseIcon.classList.add('hidden') } } else { playIcon.classList.toggle('hidden') pauseIcon.classList.toggle('hidden') } } ``` It's a simple function that I'm going to break down now: - the argument `reset` is a boolean that will determine if we are resetting the clock. When resetting we always want to show the play icon, regardless if we reset when the clock was paused or not. - we are looking at the `classList` of our elements and toggling a class of `hidden` This `togglePlayPauseIcon` function will be called inside of `toggleClock` so paste this code in the first line of that function: ```js const toggleClock = reset => { togglePlayPauseIcon(reset); // ... the rest of the function ``` What is missing now is the stopIcon. If you look at our HTML above you can see that by default, the stop icon is hidden. When the page first load and the clock is stopped, we have no reason to show the stop icon. It will show only when we start the clock the first time so let's create a new function called `showStopIcon` that will look like this: ```js const showStopIcon = () => { const stopButton = document.querySelector('#pomodoro-stop') stopButton.classList.remove('hidden') } ``` This function will also be called inside of our `toggleClock` function which now looks like this: ```js const toggleClock = (reset) => { togglePlayPauseIcon(reset) if (reset) { stopClock() } else { console.log(isClockStopped) if (isClockStopped) { setUpdatedTimers() isClockStopped = false } if (isClockRunning === true) { // pause clearInterval(clockTimer) // update icon to the play one // set the vale of the button to start or pause isClockRunning = false } else { // start clockTimer = setInterval(() => { stepDown() displayCurrentTimeLeftInSession() }, 1000) isClockRunning = true } // new showStopIcon() } } ``` If you try now, you will see that when the page loads the stop icon won't be there but as soon as you hit the play button, it will show alongside the stop icon. Pasting here all the css code that i've used would only make this post longer than necessary and since the focus of the tutorial is on JavaScript, you can check out this link to get the necessary css code. [ TODO] ADD LINK TO THE TUTORIALS REPO. Great, now it's time to move on to the progress bar. For this task we won't actually do the coding but we will leverage an existing library. There are many out there to choose from but I've picked ProgressBar.js. First, go to this link https://progressbarjs.readthedocs.io/en/latest/ and download the latest js file. Then, add it in your pomodoro folder and add this line in the `head` of your HMTL: ```html ``` Let'start by adding this code right after all our variable declarations in the JS file: ```js const progressBar = new ProgressBar.Circle('#pomodoro-timer', { strokeWidth: 2, text: { value: '25:00', }, trailColor: '#f4f4f4', }) ``` Now you should see a circle with a label of "25:00" in the middle of it. We can now get rid of the variable `pomodoroTimer` and also change this code: ```js pomodoroTimer.innerText = result.toString() ``` to: ```js progressBar.text.innerText = result.toString() ``` If you try to pay the pomodoro you will see that the label inside of the circle will update. We only need to animate the progress circle and we'll be done. The progress bar takes a value fro 0 to 1 so we need to calculate how much of the current session has been completed. For that, we'll create a new function: ```js const calculateSessionProgress = () => { // calculate the completion rate of this session const sessionDuration = type === 'Work' ? workSessionDuration : breakSessionDuration return (timeSpentInCurrentSession / sessionDuration) * 10 } ``` We will need to call this function every second that the session plays so let's add this line to the `stepDown` function so that `clockTimer` looks like this: ```js clockTimer = setInterval(() => { stepDown() displayCurrentTimeLeftInSession() progressBar.set(calculateSessionProgress()) }, 1000) ``` Now if we try to play the pomodoro we can see the progress bar moving every second. Awesome, this marks the end of the tutorial, we have created a customizable timer to track our projects. There are many ways that you can improve this project, one example would be to force a longer break after a certain set of work session have been completed. --- If you liked this tutorial please share it with your friends and if you have something you would like to see for a future tutorial leave a comment. Thank you for reading all the way here, the code for the project is available on github at this [link](https://github.com/AlbertoMontalesi/InspiredWebDev-Tutorials/tree/master/pomodoro-clock). --- --- # Create a Random Quote Machine in JavaScript | freeCodeCamp Published: 2019-08-05T00:00:00.000Z Modified: 2019-08-05T00:00:00.000Z Category: tutorial Tags: js, tutorials, freecodecamp Keywords: javascript tutorial, freecodecamp, random quote machine, free tutorial, random quote machine, random quote generator URL: https://montalesi.dev/blog/tutorial/project-1-random-quote-machine This project is based on a project from the freeCodeCamp Curriculum that you can find [here](https://learn.freecodecamp.org/front-end-libraries/front-end-libraries-projects/build-a-random-quote-machine/). The goals of this project is to be able to fetch random quote from a public api and display them on our page. It's a simple task suitable for beginners that will help you learn how to interact with public API to fetch and display data.   ## The Task - Difficulty: Beginner - Tools: Text Editor of your choice - Duration: < 1 hour   ## Creating the HTML for the Random Quote Machine Let's first start by creating the structure of our project. Open your text editor and create an `index.html` file. The project is very simple, we only need a container where to display quotes, a button to fetch them and a twitter button to share them. First add this to the head of your html file: ```html ``` We are importing font awesome as we are going to use one of their icon for our twitter button. Next, let's create the structure of our project which will be like this: - container `div` that will change color every time we get a new quote - an inner `div` - a `div` for the quote - a `div` for the two buttons ```html