Image

build-a-gmail-clone-with-vue-3

4 min read
Last update: December 19, 2021

Email Action Bar

For the starting code for this lesson, switch to branch: https://github.com/Code-Pop/build-gmail-clone-with-vue-3/tree/video-9-start

In this lesson we’re going to start adding a set of buttons, with accompanying keyboard shortcuts, into our email modal - and we’re going to really put that useKeydown function to good use.

Let’s start by lining up a row of buttons in the template.

<div class="email-display">
    <div class="toolbar">
        <button>Archive</button>
        <button>Mark Read</button>
        <button>Newer</button>
        <button>Older</button>
    </div>

    ...
</div>

These buttons all need methods, as well as keyboard shortcuts that run those same methods.

Let’s start with one of them, marking the email as read — which should actually be toggling the read state of the email.

We’ll also need to change the text based on the current state of the email, and show the user the keyboard shortcut (in this case, ‘r’)

<div class="email-display">
    <div class="toolbar">
        <button>Archive</button>
        <button @click="toggleRead">{{email.read ? 'Mark Unread (r)' : 'Mark Read (r)'}}</button>
        <button>Newer</button>
        <button>Older</button>
    </div>

    ...
</div>

We’ll define the toggleRead method in the setup function, setting the read status to the opposite of what it was. We’ll importing axios and use it to persist our data to the server. Then we’ll import useKeydown from the last lesson in order to set a keyboard shortcut.

import { format } from 'date-fns'
import marked from 'marked'
import axios from 'axios'
import useKeydown from '../composables/use-keydown'

export default {
setup(props, {emit}){
let email = props.email;
let toggleRead = () => {
email.read = !email.read
axios.put(`http://localhost:3000/emails/${email.id}`, email)
}

useKeydown([
{key: 'r', fn: toggleRead},
])

return {
format,
marked,
toggleRead,
}
}
//...
}

Now we can mark our email as read and unread by clicking the button or hitting the ‘r’ key.

Now let’s add in the click events and keyboard shortcuts for everything in the templates.

For the Archive button, like the Mark Read button, we’ll want it to work in both the archived and unarchived states, and to show different text in each case.

<div class="email-display">
    <div class="toolbar">
        <button @click="toggleArchive">{{email.archived ? 'Move to Inbox (e)' : 'Archive (e)'}}</button>
        <button @click="toggleRead">{{email.read ? 'Mark Unread (r)' : 'Mark Read (r)'}}</button>
        <button @click="goNewer">Newer (k)</button>
        <button @click="goOlder">Older (j)</button>
    </div>

    ...
</div>

Now we’ll define the toggleArchive function. We’ll want it to change the archived state, persist that change to the server, and then close the modal - and we’ll want to do that when clicking the button or hitting the ‘e’ key.

Most of that functionality is similar to what we did for Mark Read, with one exception.

export default {
setup(props, {emit}){
let email = props.email;
let toggleRead = () => {
email.read = !email.read
axios.put(`http://localhost:3000/emails/${email.id}`, email)
}
let toggleArchive = () => {
email.archived = !email.archived
axios.put(`http://localhost:3000/emails/${email.id}`, email)
// How to close the modal?
}

useKeydown([
{key: 'r', fn: toggleRead},
{key: 'e', fn: toggleArchive},
])

return {
format,
marked,
toggleRead,
toggleArchive,
}
}
//...
}

We want to close the modal… but that’s controlled on the MailTable component, with the openedEmail variable.

Looking ahead, we can see that the Newer Email and Older Email buttons will also require changing the openedEmail variable, and will require access to the list of emails as well.

There are several ways we could deal with this. One is to pass down several events for changing the status (closeModal, newerEmail, olderEmail). Another is to pass down one event (changeOpenedEmail) as well as the list of emails, then do the calculations on the MailView component. Those both have their advantages and disadvantages.

The way we’ll choose, however, is to pass down a flexible event. We’ll see what that looks like in the next lesson.

For the ending code for this lesson, switch to branch: https://github.com/Code-Pop/build-gmail-clone-with-vue-3/tree/video-9-end

Jeffrey teaches an 8-week beginning Vue course with guaranteed results. Built on top of the VueMastery curriculum, with extra hands-on assignments and personal attention. You can find it here.