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.
-
index.html
, with a<body>
where the Svelte app will be mounted to (just likeReactDOM
) -
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;
};
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)
}
});
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>
🎉 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}
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>
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.