DEV Community

Cover image for An emoji dictionary in Svelte
Bryce Dorn
Bryce Dorn

Posted on β€’ Edited on

3 1

An emoji dictionary in Svelte

As an avid user of the πŸ…±οΈ emoji, I get (too much) enjoyment out of the few alphabetical characters in the emoji alphabet.

But we can do more than just substitute a b with a πŸ…±οΈ; I wanted to know many words can be written entirely with emoji. Let's find out!

First I found an (English) dictionary and wrote a quick & dirty Rust script to generate the words. Just a list of words isn't fun though, it needs interactivity! I chose Svelte for this to get some hands-on with its dev experience (it's pretty good!) and performance.

To start, I made a basic webpack config with svelte-loader and three files:

Note: if you want to skip to the end, the source is here.
  • index.html, with a <body> where the Svelte app will be mounted to (just like ReactDOM)
  • main.js, where the app is mounted & passed props
  • App.svelte, for the component & filtering logic

JavaScript

In main.js, the words are imported and prepared for the component:

import words from 'output.txt';

// Associate letters & sequences with their 
// emoji equivalents
const emojiHash = {
    "id": "πŸ†”",
    "a": "πŸ…°οΈ",
        ...
    "soon": "πŸ”œ"
};

// Replace the letters/sequences in a string as 
// their respective emoji
const convertToEmoji = (word) => {
    let emojified = String(word);
    regexKeys.forEach((key, i) => {
        emojified = emojified.replace(key, emojiHash[sortedKeys[i]];
    }));
    return emojified;
};

// Render letters/sequences as emoji by running 
// the above function until there are no letters
// remaining
function emojify(word) {
    let emojified = String(word);
    do {
        emojified = convertToEmoji(emojified);
    } while (emojified.split('').some(e => /^[a-zA-Z]+$/.test(e)));
    return emojified;
};

Enter fullscreen mode Exit fullscreen mode

Then the component is mounted to the DOM:

const app = new App({
    target: document.body,
    props: {
        emoji: Object.values(emojiHash),
        sort: 'default',
        words: words.split('\n').map(emojify)
    }
});
Enter fullscreen mode Exit fullscreen mode

Svelte

Great! Now we have formatted data coming into the component, let's do something with it.

*.svelte files are HTML files with some syntactic sugar. The basic structure is as follows:

<script>
  // Functions, variables
  export let words;

  function clicky(e) {
    console.log(e.target.innerText);
  }
</script>

<!-- Any styles associated with the component -->
<style>
  .container { 
    background: palevioletred; 
  }
</style>

<!-- The rendered markup -->
<div class="container">
  <ul>
    {#each words as word}
      <li>
        <p on:click={clicky}>
          {word}
        </p>
      </li>
    {/each}
  </ul>
</div>
Enter fullscreen mode Exit fullscreen mode

πŸŽ‰ ta-da! πŸŽ‰ A list of words rendered with Svelte! Note that since words is being passed in as a prop, the export keyword is needed.

For the sake of brevity I'll just go through adding filtering (sorting is in the repo if you want to take a look).

Somewhere in the component, let's render a list of checkboxes for each emoji:

Filter:
{#each emoji as moji}
  <label>
    <input on:change={handleFilterClick} type="checkbox" checked={!filteredEmoji.includes(moji)} value={moji}>
    <span>{moji}</span>
  </label>
{/each}
Enter fullscreen mode Exit fullscreen mode

Since we're rendering the list via the words variable, we'll need to update it to reflect the filter.

<script>
  export let words;

  // Keep an immutable version of words in memory
  export let wordsImm = Array.from(words);

  function handleFilterClick(e) {
    const { checked, value } = e.target;

    // Keep immutable version of original prop & make a copy 
    // to apply filters to
    let wordsMut = Array.from(wordsImm);

    // Either add or remove the current emoji from the filters
    if (checked) {
      filteredEmoji.splice(filteredEmoji.indexOf(value), 1);
    } else {
      filteredEmoji.push(value);
    }

    // If there are filters, apply them to list of words
    if (filteredEmoji.length > 0) {
      filteredEmoji.forEach(emoji => {
        wordsMut = wordsMut.filter(word => !word.includes(emoji));
      });
    }

    // Set variable to new list
    words = wordsMut;
  }
</script>
Enter fullscreen mode Exit fullscreen mode

When words is updated to the filtered (mutated) version after selecting a filter, it will trigger an update and the DOM will render the new list.

Side-note: this could be refactored to have the filtering in the `{each}`, (preventing the need to update `words`) but I wanted to render the number of words in a different part of the component.

Final thoughts

Svelte is nice & fast! I plan to use it again, ideally for something more resource intensive/visually demanding to really push it to its limits (beyond where React would have issues).

I also want to see how it is to work on a larger project using Sapper, once the framework is more mature.

Go play with it here! https://bryce.io/emoji-dict

View source on Github.

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (3)

Collapse
 
deciduously profile image
Ben Lovy β€’

I think I hate this, but I also think I love this. Nice work?

Svelte looks cooler by the day.

Collapse
 
bryce profile image
Bryce Dorn β€’

Haha πŸ‘» it's getting better! Still a ways away from the clarity of React.

Collapse
 
deciduously profile image
Ben Lovy β€’

Yeah, but "clarity" is a complicated term, right? The sales pitch of compiling away the framework entirely is too cool to dismiss outright. React often feels like overengineering for a given problem, Svelte gets you a lot of the benefit without so much overhead.

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

πŸ‘₯ Ideal for solo developers, teams, and cross-company projects

Learn more