Frontend.mu Nuxt & Tailwind Workshop

Welcome to Nuxt Workshop by frontend.mu

This is a workshop to learn Nuxt.js

Join our discord channel for two way comms!

  1. Go on GitHub and login with your account

  2. Click here and fork the repository.

  3. Getting access to the editor

    Question: Do you have git and NodeJS installed on your machine?

    If yes

    On your fork, click on the "code" button(usually green), clone the repository on your machine

    If no

    On your fork, click on the "code" button(usually green), and select Codespaces.

    Click on "create codespace on main" to get your own cloud ide

    This is VS Code running in the cloud! 😎

    This might take a moment, depending on your connection speed.

  4. Start the project in dev mode

    You can now start the project in dev mode by running the following command in the terminal

    npm run dev

    Note that if you cloned the project, you might need to run `npm install` first

  5. Open the project in a new tab

    Open port 3000 to view the running project in a new tab

    If you see the green messsage, Congratulations! 🎉

    If you don't see it, call an instructor to assist you

  6. Let's create a component in Nuxt!

    Create a 'components' folder

    Add a new file `Container.vue`

    Add the following code to the file

      
        <template>
          <div class="container mx-auto">
            Hello from Container.vue
          </div>
        </template>
      
    
  7. Let's use some tailwind classes to build a simple layout

    Let's create a simple layout using tailwind classes

    Use the following classes to create a simple layout

      
      <template>
        <div class="container mx-auto">
          <div class="grid grid-cols-2 gap-4">
            <div class="bg-gray-200 p-4">
              <h2>Hello from Container.vue</h2>
            </div>
            <div class="bg-gray-200 p-4">
              <h2>Hello from Container.vue</h2>
            </div>
          </div>
        </div>
      </template>
    
    
  8. Let's fetch some data

    Endpoint: https://github.com/MrSunshyne/mauritius-dataset-electricity/blob/main/data/power-outages.latest.json

      
    const API_ENDPOINT = 'https://raw.githubusercontent.com/MrSunshyne/mauritius-dataset-electricity/main/data/power-outages.json'
    
    async function fetchJson(url = API_ENDPOINT) {
      try {
        const response = await fetch(url)
        return response.json()
      }
      catch (error) {
        throw new Error(`Error fetching JSON: ${error}`)
      }
    }
      
    
  9. Let's loop on the data

    Display all the outages for today on the page by accessing the correct key

    // In the script tag
    const outages = await fetchJson()
    const { today } = outages
    for (const outage of today) {
      console.log(outage)
    }
    
    // In the template tag
    <ul>
      <li v-for="outage of today" :key="outage.id">
        <pre>{{ outage }}</pre>  
      </li> 
    </ul>
    
  10. Let's create a card component or pick from the list

    Card One

    Flic en Flac
    indicator here

    Poste De Police, Loday Lane, Flic En Flac Road, Residence Des Peupliers Et Residence Gold Coast

    8 HOURS AGO FROM 08:30 TO 15:30

    Power will resume in 34m 6s

    Card two

    Flic en Flac
    indicator here

    Le Village De Caroline Dans Le Périmètre De La Route Royale, Avenue Descombe, Avenue Gandhi, Avenue Allaman, Filling Engen Et Shell, Petit Bois, Chemin Balance, Morc. Caunhye

    Power will resume in 34m 6s

    8 HOURS AGO
    FROM 08:30 TO 15:30

    Card three

    indicator here

    Flic en Flacq

    8 hours ago, From 08:30 to 15:30

    Power will resume in 34m 6s

    Le Village De Caroline Dans Le Périmètre De La Route Royale, Avenue Descombe, Avenue Gandhi, Avenue Allaman, Filling Engen Et Shell, Petit Bois, Chemin Balance, Morc. Caunhye, Residence EDC, Chemin La Pompe, Morc. Sohawon, Morc.

    Card four

    Flic en Flacq

    8 hours ago, From 08:30 to 15:30

    Power will resume in 34m 6s

    indicator here

    Le Village De Caroline Dans Le Périmètre De La Route Royale, Avenue Descombe, Avenue Gandhi, Avenue Allaman, Filling Engen Et Shell, Petit Bois, Chemin Balance, Morc. Caunhye, Residence EDC, Chemin La Pompe, Morc. Sohawon, Morc.

  11. Let's pass data into the cards as props

    Here we will learn about props and how to pass them

    We will pass the `Street Name, District, Date From, Date To` into the card and customize the content to show our data

    // index.vue In the template tag
    <ul class="grid gap-y-12 max-w-screen-md mx-auto">
      <li v-for="(outage, index) in today" :key="index">
        <Outage :outage="outage" />
      </li>
    </ul>
    
    // components/Outage.vue Create the script tag (setup lang="ts")
    import { useTimeAgo } from "@vueuse/core"
    
    // todo: move to types.ts (?)
    enum District {
      blackriver,
      flacq,
      grandport,
      moka,
      pamplemousses,
      plainewilhems,
      portlouis,
      rivieredurempart,
      savanne,
      rodrigues,
    }
    
    // todo: move to types.ts (?)
    interface Record {
      date: string
      locality: string
      streets: string
      district: District
      from: Date
      to: Date
      id: string
    }
    
    type Props = {
      outage: Record
    }
    
    const props = defineProps<Props>()
    
    
    // components/Outage.vue Update the template
     <div
        class="flex flex-col justify-between bg-blue-950 text-white p-4 rounded-md w-full"
      >
      <div class="flex justify-between w-full">
        <div class="text-xl font-bold">{{ props.outage.locality }}</div>
        <div class="w-6">
          <!-- todo: have the candle <IconCandle /> -->
          🕯️
        </div>
      </div>
    
      <div class="flex justify-between items-end">
        <div class="space-y-2">
          <p class="font-light max-w-3xl">
            {{ props.outage.streets }}
          </p>
          <div class="text-sm">
            {{ props.outage.date }}
          </div>
        </div>
      </div>
    </div>
    
  12. Let's add some logic to check if power is off already or not

    // components/Outage.vue Apend to the script tag contents
    ...
    const state = computed(() => {
      let on = "upcoming"
    
      const from = new Date(props.outage.from)
      const to = new Date(props.outage.to)
    
      const now = new Date()
    
      if (now.getTime() > from.getTime()) {
        on = "ongoing"
      }
    
      if (now.getTime() > to.getTime()) {
        on = "past"
      }
    
      return on
    })
    
    const outageMessage = computed(() => {
      if (state.value === "ongoing") {
        return "will resume in"
      } else if (state.value === "upcoming") {
        return "will cut in"
      } else {
        return "has resumed"
      }
    })
    
    // components/Outage.vue Apend to the template tag contents 
    // after <div class="text-sm"> {{ props.outage.date }} </div> </div>
    
    <div class="inline md:block">Power {{ outageMessage }}</div>
    <div
      class="inline md:block"
      v-if="!['ongoing', 'upcoming'].includes(state)"
    >
      {{ useTimeAgo(outage.from, { showSecond: true }) }}
    </div>
    <div class="inline md:block" v-else>
      {{ useTimeAgo(outage.from) }}
    </div>
    
    
  13. Pick some on/off indicators from this list

    FingerprintOff

    FingerprintOn

    RoundBulbOff

    RoundBulbOn