Now you can begin building the first screen of your app: the CardOfTheDay view.

Build up a data structure

There's little point in building a mobile app if it's not going to display data. For this app, we're going to include a pre-built data structure with all the meanings of the cards, and display them in various ways throughout the app.

Our data structure will include some information we won't use in this app, but if you decide to extend your app later, it might come in useful.

About the Tarot

This workshop isn't designed to teach about Tarot card reading, but it's kind of useful and fun to know how it works, generally speaking. A Tarot reader asks the person whose cards are being read (called the Querant) to think about a specific question that she or he wants answered. Then the reader shuffles the cards and lays them out in various configurations. Each card has a meaning according to its position during the reading. For our purposes, we will lay out a simple "Past, Present, and Future" card stack on the third screen that we build. For the screen that you're building now, a random card is selected that would give a basic reading for a daily question. This is the Card of the Day.

Create a new folder in the app root called data and a file called cards.js in that folder. In that file, paste the JSON structure from this file.

Take a look at your data, and see if you can figure out what the cards signify.

The Tarot is divided into two major groups: the Major Arcana and the Minor Arcana. In our data, that's designated as type. Major cards are the cards that don't have suits associated to them, for example the Empress is a Major card, and a Queen is a Minor card, because there are four queens: Queens of Cups, Pentacles, Wands and Swords. There are also Number cards, like "One of Swords"; these are also minor. All cards have two meanings: Up and Reversed. It all depends how they come up in the sort!

Build the basic layout

You'll display a randomly-selected card when this screen is built. Start by creating a Grid Layout:

In the <template> of CardOfTheDay.vue, delete all the code between the opening and closing <template> tags. Paste in the following markup:

<GridLayout rows="auto,auto" verticalAlignment="top">
    <Label row="0" text="Card of the Day" class="title med" />
</GridLayout>

Now, add a second, nested GridLayout under the Title Label:

<GridLayout row="1" rows="2*,*,3*,3*" class="card">
    <Label row="0" textWrap="true" class="card-title" text="My Card" />
</GridLayout>

Finally, add some styles to this file for use in the card by overwriting the <styles> tags with the following:

<style>
    .meaning {
        font-size: 16;
        color: #131636;
        text-align: center;
        margin: 0 20;
    }
    .status {
        color: #323340;
        opacity: .5;
        font-size: 14;
    }
</style>

Notice that we just hard-coded a card title. It may look ok, but we want to display data. So let's import our Tarot data structure.

Import the data

In the <script> block, import the card data that you just added, right under the opening <script> tag:

import {
        Cards
    } from "../data/cards";

Then, set up your data structure to be used in this screen. In the data() method, add some properties to be displayed:

data() {
    return {
        name: "",
        meaning: "",
        emoji: "",
        emoji1: "",
        emoji2: "",
        icon: "emoji",
        cards: Cards,
        major: true,
	reversed: false
    };
},

Why all the blank values? Well, when the Vue instance is created, its reactivity system starts watching for changes to the properties on its data object. If a property like name doesn't exist initially, Vue won't notice when we load a new card's name, and it won't be rendered on the screen.

Now, we need to populate the Card of the Day with some randomly-selected data point from the cards.js file.

Create a shuffle capability

You'll need a way to shuffle both the card data and again to determine whether the chosen card is up or reversed.

Create a computed property called randomNumber() that will shuffle a deck of 72 cards, and choose a random number for us. Also, create a computed property called shuffle() that will return choose either up or reversed card meanings.

Making sure there's a comma under the closing parenthesis in the data() object, add a new computed property with the following methods:

computed: {
    shuffle() {
        return Math.floor(Math.random() * 2);
    },
    randomNumber() {
        return Math.round(Math.random() * 72);
    }
},

Remember, computed properties are cached, so it's good to use them here as we don't want the Card of the Day to change each time we flip between screens.

Now, we need to use these computations to shuffle some cards.

Create a method property with a method called getMyCard(), after the last comma under the computed properties.

methods: {
    getMyCard() {
        const card = this.cards[this.randomNumber];
        this.name = card.name;
    }
},

In this method, we simply loop through our cards data, using the computed property randomNumber to select a number between 0-72, and then returning a card name. You can't see it yet, though, because we haven't called the method and we haven't built the UI. So let's do that.

In the markup at the top, replace the card name with bound data. The shortcut to do this is ::

<Label row="0" textWrap="true" class="card-title" :text="name" />

Then, call getMyCard when the page is created by adding a lifecycle hook after the last comma after methods:

created() {
    this.getMyCard();
}

A lifecycle hook allows you to perform certain functions at various points in your app's lifecycle.

By this time, you should be able to see a card name appearing in the Card of the Day card. Now, you need to display an emoji and a meaning for the card.

Enhance the UI

Before we go any further, we need to get all the emoji images for the cards. Download this zip file to your local computer and unzip it.

In the Playground's assets folder, first upload the two arrow images to assets by selecting Upload resources in the menu next to assets.

Then, in assets, select Upload folder and upload the entire emoji folder (42 files) to assets.

The style of this app requires that we use emoji from Microsoft's suite. All these files are available on the Emojipedia, for future reference.

Next, you can add some logic for emoji to be displayed. First build out the getMyCard method to include a way to display emoji. On the line right after this.name = card.name in getMyCard, add some logic to handle major vs minor arcana cards (minor cards need to include their suit, which means they need a second emoji, like Knight of Wands (👱‍ 🏒)):

if (card.type != 'major') {
	this.major = false;
	this.emoji1 = '~/assets/emoji/' + card.value + '.png';
	this.emoji2 = '~/assets/emoji/' + card.suit + '.png';
} else {
	this.major = true;
	this.emoji = '~/assets/emoji/' + card.value + '.png';
}

We also need to display whether the card is up or reversed, so add this if statement under the block you just pasted:

if (this.shuffle == 0) {
	this.meaning = card.meaning_up;
	this.icon = 'emoji';
} else {
	this.meaning = card.meaning_rev;
	this.reversed = true;
	this.icon = 'emoji reversed';
}

Build the UI's markup by adding some nested layouts under the name Label.

First, add a StackLayout under <Label row="0" textWrap="true" class="card-title" :text="name" />:

<StackLayout
	v-if="reversed"
	row="1"
	style="margin:5"
	verticalAlignment="top"
	horizontalAlignment="center"
	orientation="horizontal"
>
	<Label class="fa status" text.decode="&#xf021;" />
	<Label class="status" text=" REVERSED" />
</StackLayout>

This label may not appear if the card selected by your app is not reversed. If it is, however, a small text with a reversed icon and the words REVERSED will show.

Next, add an emoji image and another StackLayout:

<Image row="2" v-if="major" :class="icon" :src="emoji" />
<StackLayout row="2" v-if="!major" horizontalAlignment="center" orientation="horizontal">
	<Image style="margin:5" v-if="!major" :class="icon" :src="emoji1" />
	<Image style="margin:5" v-if="!major" :class="icon" :src="emoji2" />
</StackLayout>

This markup functions by means of v-if: if the card is a minor card, two emoji will show; otherwise, only one will show.

Test your layout by refreshing the app. The easiest way to do this is to make small changes to the template markup, like add a carriage return and save. The app should refresh on your device.

The last thing to do is to add the meaning of the card under the closing </StackLayout> tag. Add one more line:

<Label row="3" class="meaning" textWrap="true" :text="meaning" />

Refresh your app a few times! Note how the emoji reverse when the card is reversed, and the meaning changes accordingly. Really sweet!

Make sure to click Save in the Playground to save a version of your app! Don't lose your work!

🏆 Congratulations, you have built your first screen! On to the Card Meaning screen!