WORDO - Simplified Dictionary #AmplifyHashnode

WORDO - Simplified Dictionary #AmplifyHashnode

Introduction


Dictionaries are great utilities, they help us grow our vocabularies and learn to communicate better. But one of the problems I've found with some digital dictionaries is the way the words and all other data of the words are structured for comprehensibility. Certain words based on context and usage possesses different parts of speech, hence different definitions and usage examples based on the part of speech.
For example the word "back" can be a noun, a verb, an adverb or an adjective and have different meanings as illustrated below:

  • as a noun - the posterior part of a human (or animal) body from the neck to the end of the spine
  • as a verb - be behind; approve of
  • as an adverb - in or to or toward a past time
  • as an adjective - of an earlier date

Wordo clearly structures this information so that users can truly comprehend the word, know where and how it applies and other properties of the word such as its meaning and examples for each part of speech (for words with more than one parts of speech just like our example above), syllables, synonyms and antonyms.
Each part of speech is represented with a unique colour to distinguish it from the other parts of speech as you'd see in the image below.

wordo article POS-1 (1).jpg

The application draws words data from Words API , there are thousands of words and other useful information about the word on this API which is why I chose to use it.
The need for a better structure and better information representation led me to building wordo and I hope you do find it useful and easy to comprehend as this is the core intent of its creation.

Feel free to explore WORDO here


Features

Wordo provides the following features :

  • Specific colours for each part of speech to help the user distinguish easily between the other parts of speech.
  • Multiple definitions of the words where necessary.
  • Transcription.
  • Examples.
  • Syllables.
  • Synonyms and Antonyms.
  • Save option for user to save favourite words and visit them later.
  • Recent searches just incase the user wishes to visit recently searched words.


Coming Features

  • New word each day to help users learn new vocabularies everyday.
  • Voice search.
  • Vocal pronunciation of searched word.
  • Word test puzzle to keep users engaged and help them practice words they've learnt.


Design Processes

Magic on Paper

20210226_172020.jpg

Everything I build or create starts on paper because I like to have a visual representation of my thoughts and ideas (you should practice this too). So on paper I wrote down ideas, sketched when I had to and once I had laid down all of the necessary info for the application I moved on to the next step.

UI/UX Design

After all of the planning had been laid out on paper, I went on to design the interface of the application using Adobe XD . The application is designed mostly using white background and dark grey fill colours. Other colours used are shown in the image below.

The application comprises of 4 pages or 4 views - the intro view, the sample view, the main view and the saved-words view.

wordo views.jpg

The Intro View - this is the first screen view found when the application is run (or visited). It briefly introduces the user to the application.

The Sample View - this view gives words sample and image representation of the word and then provides an "Explore" button that leads the user to the Main View.

The Main View - the main view is where all the fun happens. Words are searched and displayed here. The user hits the search bar, enters a word and clicks on the search button or the "Enter" key. The application then makes a request to the words api and then displays the word and other informations about the sorted word.
The main view displays

  • The searched word, its part of speech, its transcription, its definitions and a "save" button for saving the word for later reference.
  • Other definitions of word.
  • Examples.
  • Syllables.
  • Synonyms and Antonyms.
  • Search input field and a search button.

The Saved-Words View - this view as the name implies stores words saved by the user for future reference. The words are stored in users local storage and can be accessed whenever the user returns to the page. Each saved word can be deleted from the list of saved words.

Coding the application

After all the plans had been penned down and the interfaces designed, it was time to build the application. The application was built using HTML5, CSS, JAVASCRIPT and REST API from Words Api.
I followed a functional approach where I wrote several functions for different tasks. Some of the tasks included:

  • Logging messages or warnings to the user (like connection error message or word-not-found message),
  • Creation of UI components for representing the word based on its part of speech such as definitions, examples, syllables, synonyms and antonyms,
  • API request,
  • Recent searches

After which I went on to build the rest of the pages which are the 4 views we listed above - the intro view, the sample view, the main view and the saved-words view.


Function to log messages or warnings to the user

//-------------------- LOG MESSAGES ---------------------
function logMessage(element) {
    hide(mainBody);
    hide(searchTip);
    hide(connectionTip);
    hide(loader);
    show(messages, "flex");
    show(element, "flex");
}
function logWarning(message) {
    warning.innerText = message;
    warning.classList.toggle("slide-warning-up");
    show(warning);
    setTimeout(() => {
        warning.classList.toggle("slide-warning-up");
        warning.classList.toggle("slide-warning-down");
    }, 3500);
}
//log message to user when no word has been added
function logNoSavedWords(){
    if(savedWordsContainer.childElementCount < 1) {
        savedWordsContainer.innerHTML = `
            <div id="saved-words-message" class="saved-words-message">
                <span class="saved-words-message__exclamation-icon"><i class="fa fa-exclamation-circle"></i></span>
                <p class="saved-words-message__message-text">you haven't saved any word yet, <br> go ahead save some words you'd <br> like to remember</p>
            </div>
        `;
        savedWordsMessage = document.getElementById("saved-words-message");
    }
}

Creation of UI components for representing data


//----------------------- CREATE ELEMENTS ------------------
//create word container
export function createWordContainer(word, partOfSpeech, transcription, definition){
    if(partOfSpeech === null) partOfSpeech = "unknown";
    mainBody.innerHTML += `
        <section id="${word}-${partOfSpeech}" class="word-container">
            <div class="word-utils">
                <p class="word-utils__part-of-speech">${partOfSpeech.toLowerCase()}</p>
                <p class="word-utils__save">save</p>
            </div>
            <div class="word">
                <h3 class="word__text">${word.toUpperCase()}</h3>
                <p class="word__transcription">/ ${transcription} /</p>
                <p class="word__definition">${definition}</p>
            </div>
        </section>
    `;
    //to make id unique for each word container, set id as word-partofspeech
    let wordContainer = document.getElementById(`${word}-${partOfSpeech}`);
    //capitalize the part of speech
    wordContainer.firstElementChild.firstElementChild.style.textTransform = "capitalize";
    wordContainer.style.backgroundColor = `var(--${partOfSpeech.toLowerCase()})`;
}

//create definitions
export function createDefinitions(word, partOfSpeech, definitions) {
    mainBody.innerHTML += `
        <section id="${word}-${partOfSpeech}-definitions" class="definitions-container">
            <h4 class="definitions-container__header">Definitions</h4>
        </section>
    `;
    let definitionsContainer = document.getElementById(`${word}-${partOfSpeech}-definitions`);
    //note definitions is an array of sentences (stings)
    for(let definition of definitions){
        definitionsContainer.innerHTML += `
            <p class="definitions-container__text">${definition}</p>
        `;
    }
}

//create examples
export function createExamples(word, partOfSpeech, examples){
    mainBody.innerHTML += `
        <section class="examples-overall-container">
            <h4 class="examples-overall-container__header">Examples</h4>
            <div id="${word}-${partOfSpeech}-examples" class="example-container">
            </div>
        </section>
    `;
    let examplesContainer = document.getElementById(`${word}-${partOfSpeech}-examples`);
    for(let example of examples) {
        examplesContainer.innerHTML += `
            <section class="example">
                <p class="example__text"> ${example} </p>
            </section>
        `;
    }
}

//create syllables
export function createSyllables(word, partOfSpeech, syllable, count) {
    if(partOfSpeech === null) partOfSpeech = "unknown";
    mainBody.innerHTML += `
        <section class="syllables-container">
            <h4 class="syllables-container__header">Syllables</h4>
            <div id="${word}-${partOfSpeech}-syllables" class="syllables">
                <p class="syllables__word">${syllable}</p>
                <p id="syllables-count" class="syllables__count">${count}</p>
            </div>
        </section>
    `;
    let syllablesBg = document.getElementById(`${word}-${partOfSpeech}-syllables`);
    syllablesBg.style.backgroundColor = `var(--${partOfSpeech})`;
    //change syllable count color to match syllable background color
    let syllablesCount = document.getElementById("syllables-count");
    syllablesCount.style.color = `var(--${partOfSpeech})`;
}

//create  synonyms & antonyms
export function createSynonymAntonym(synonyms = "none", antonyms = "none"){
    //antonyms and synonyms to from array to string
    if(synonyms) synonyms = synonyms.join(", ");
    if(synonyms) antonyms = antonyms.join(", ");
    mainBody.innerHTML += `
        <section class="synonym-antonym">
            <h4 class="synonym-antonym__header">Synonyms</h4>
            <div class="synonyms">
                <p class="synonyms__text">${synonyms}</p>
            </div>
            <hr class="synonym-antonym__divider"/>
            <h4 class="synonym-antonym__header">Antonyms</h4>
            <div class="synonyms">
                <p class="synonyms__text">${antonyms}</p>
            </div>
        </section>
    `;
}

I wouldn't want to bore you with 1billion lines of code so feel free to check out the code on my github. But the most important part of the code was fetching the data from the API which wasn't a problem. The code snippet below shows how I was able to fetch the data.

API REQUEST

//------------------------- API REQUEST --------------------------
function getWordData(word){
    fetch(`https://wordsapiv1.p.rapidapi.com/words/${word.toLowerCase()}`, {
        "method": "GET",
        "headers": {
            "x-rapidapi-host": "wordsapiv1.p.rapidapi.com",
            "x-rapidapi-key": process.env.API_KEY,
        }
    })
    .then(response => response.json())
    .then(data => {
        if(data.success !== false && data.results){
            console.log(data);
            createRecentSearch(word);
            //prevent number of recently searched words from exceeding 10
            if(recentSearch.childElementCount > 10) recentSearch.removeChild(recentSearch.lastElementChild);
            hide(loader);
            hide(messages);
            mainBody.innerHTML = "";
            userInput.value = "";
            show(mainBody);
            renderData(data);    
        }
        else {
            hide(messages);
            hide(loader);
            show(mainBody);
            setTimeout(() => {
                logWarning("word not found!");   
                if(mainBody.childElementCount < 1) logMessage(searchTip);
            }, 300);         
        }
    })
    .catch(error => {
        console.log(error);
        if(error.message === "Failed to fetch"){
            logMessage(connectionTip);
        }
        else {
            alert("error encountered searching that word! please search another");
            hide(mainBody);
            logMessage(searchTip);
        }
    }); 
}

Challenges Encountered

I experienced an issue while trying to save words uniquely. I thought of simply writing a function that checks through the array of saved words and compares the new word to be saved with existing words in the array before saving the new word. This isn't ideal, the saved words can get large as there's no limit to the number of words that can be saved and so looping through each words can create a poor user experience.
The Solution - I found out about the use of Sets which lets you store unique values and this solve the problem for saving words uniquely. If you want to learn more, visit MDN Click here


How To Use

Wordo is super intuitive and very easy to use. When the page loads, an "Explore" button is available which eventually leads to the Main View we talked about. Here the user inserts a word or short phrase in the input field and hits the Enter key or the search button in the input field to initiate search. If all goes well, the word and its data is returned to the user else a corresponding message is sent to the user depending on the error encountered. This error may be "Connection Error" or "Word-not-found Error".

  • Connection Error - Connection error occurs when the user's internet connection fails, therefore the user has to recheck their connection settings, make sure everything is working fine and try again.
  • Word-not-found Error - As the name implies is an error that occurs when a user inserts a word that is improperly spelt or doesn't existed in the words api. But be rest assured that there are enough words in the words api such that you will barely encounter this problem.

You've come to end of this article. Please hit the like button or any of the appreciation buttons if you like this article and also check Wordo out, you'd be pleased!

Demo

Source Code

Thank you Hashnode for another opportunity like this. Asides the possibilities of winning awesome prices, this is a chance for developers to practice and also showcase their projects and learn from the community.
Thank you for your time ❤️