Categories
Rxjs

Basic Usage of Rxjs Operators

With operators, we can do more with Rxjs observables. They’re useful for doing complex operations with asynchronous code.

Operators are functions. There’re 2 types of operators:

  • Pipeable operators — they can be piped to Observables using the pipe method available in Observables. They return a new Observable, so multiple pipeable operators can be chained together
  • Creation operators — these are standalone functions to create a new Observable. For example, of(1,2,3) will emit 1, 2, and 3.

Using Operators

We can import operators from Rxjs to use to manipulate our observable results.

For example, we can map values from Observables to another using the map function:

import { of } from "rxjs";
import { map } from "rxjs/operators";

map(x => x * 2)(of(1, 2, 3)).subscribe(val => console.log(val));

We created an Observable that emits 1, 2 and 3 with the of function and then called map with a callback to let us map the values, which returns a function where we can pass in the Observable that we created and returns a new Observable.

map(x => x * 2)(of(1, 2, 3))

returns a new Observable that we can subscribe to. Then we get the values 2, 4, and 6 in the subscribe ‘s callback function.

Piping

We can use the Observable’s pipe method to compose multiple operations into one.

It takes multiple operations as arguments, which is much cleaner than nesting them.

For example, we can use it to rewrite the example we had above:

import { of, pipe } from "rxjs";
import { map } from "rxjs/operators";

of(1, 2, 3)
  .pipe(map(x => x * 2))
  .subscribe(val => console.log(val));

We get the same result, but it’s much cleaner.

Also, we can pass in more than one operation to the pipe method:

of(1, 2, 3)
  .pipe(
    map(x => x * 2),
    map(x => x * 3)
  )
  .subscribe(val => console.log(val));

Then we first multiply each value emitted by the Observable by 2, then we multiply the returned value again by 3. As a result, we get back 6, 12, and 18 in the console.log .

Creation Operators

Creation operators are functions to create an Observable from scratch or by joining other Observables together.

For example, we have the interval function to emit a value from 0 and up in the interval that we specify:

import { interval } from "rxjs";

interval(5000).subscribe(val => console.log(val));

The code above will output an integer from 0 and up every 5 seconds.

Higher-Order Observables

Higher-Order Observables are Observables of Observables. There’re a few things that we can do with different observables.

Rxjs has the concatAll() operator that subscribes to each inner observable and copies all the emitted values until the outer observable completes.

For example, we can use it as follows:

import { of, pipe } from "rxjs";
import { concatAll, map } from "rxjs/operators";

of(1, 2, 3)
  .pipe(
    map(outerVal => {
      console.log(`outerVal ${outerVal}`);
      return of(4, 5, 6);
    }),
    concatAll()
  )
  .subscribe(innerVal => console.log(`innerVal ${innerVal}`));

We should get the output:

outerVal 1
innerVal 4
innerVal 5
innerVal 6
outerVal 2
innerVal 4
innerVal 5
innerVal 6
outerVal 3
innerVal 4
innerVal 5
innerVal 6

As we can see, we get the first value from the of(1,2,3) Observable first, and then all the values from the second. Then we get the second value from of(1,2,3) and then all the values from the second and so on.

Other operator functions include:

  • mergeAll() — subscribes to each inner Observable as it arrives, and emits each value as it arrives.
  • switchAll() — subscribes to the first inner Observable when it arrives, then emits each value as it arrives. It unsubscribes to the previous one then subscribes to the new one.
  • exhaust() — subscribes to the first inner Observable when it arrives, then emits each value as it arrives, discarding all newly arriving Observables as it completes and waits for the next inner Observable.

They all give the same result as concatAll() but the difference is underneath.

We can create new Observables by composing multiple Observables or operators.

For example:

of(1, 2, 3)
  .pipe(
    map(x => x * 2),
    map(x => x * 3)
  )

is an Observable that multiplies each value from Observableof(1, 2, 3) by 6.

With Rxjs, there’re are built-in operators that we can use to create and manipulate Observable values. Also, we can create new Observables and combine them together in different ways.

Observables can also be nested, and the values of all the nested Observables can be obtained by using concatAll() , mergeAll() , switchAll() or exhaust() .

Categories
Quasar

Developing Vue Apps with the Quasar Library — Tooltip Transitions and Position

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

Tooltip Transitions

We can add tooltip transitions with the transition-show and transition-hide props:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <q-btn color="primary" label="Flip">
            <q-tooltip transition-show="flip-right" transition-hide="flip-left">
              tooltip
            </q-tooltip>
          </q-btn>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {}
      });
    </script>
  </body>
</html>

transition-show is applied when we show the tooltip.

And transition-hide is applied when we hide it.

Other values include scale and rotate .

Tooltip Target

We can set the target prop of the q-tooltip component to let us set the tooltip to open when we hover over the element with the given selector.

For instance, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <q-img
            src="https://cdn.quasar.dev/img/material.png"
            id="target-img-1"
            style="height: 100px;"
          >
            <div
              class="absolute-bottom-right"
              style="border-top-left-radius: 5px;"
            >
              #target-img-1
            </div>
          </q-img>

          <q-tooltip
            :target="targetEl"
            anchor="center middle"
            self="center middle"
            content-class="bg-black"
          >
            tooltip
          </q-tooltip>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          targetEl: "#target-img-1"
        }
      });
    </script>
  </body>
</html>

We set target to '#target-img-1' , so when we hover over the image, the tooltip will show.

This gives us more flexibility with placing the tooltip.

Tooltip Position

We can change the position of the tooltip with the anchor and self props:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <q-btn color="primary" label="hover me">
            <q-tooltip anchor="bottom right" self="top middle">
              tooltip
            </q-tooltip>
          </q-btn>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          targetEl: "#target-img-1"
        }
      });
    </script>
  </body>
</html>

anchor changes the position of the tooltip relative to its target.

self changes its own position relative to its target.

Each of these props can be a combination of top , center , or bottom and left , middle or right .

Conclusion

We can add a tooltip with various positions and transitions with Quasar’s q-tooltip component into our Vue app.

Categories
Quasar

Developing Vue Apps with the Quasar Library — Tooltip

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

Tooltip

We can add a tooltip into our Vue app with Quasar’s q-tooltip component.

For instance, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <q-btn label="Hover me" color="primary">
            <q-tooltip>
              Some text as content of Tooltip
            </q-tooltip>
          </q-btn>

          <div
            class="inline bg-amber rounded-borders cursor-pointer"
            style="max-width: 300px;"
          >
            <div
              class="fit flex flex-center text-center non-selectable q-pa-md"
            >
              hover me
            </div>

            <q-tooltip>
              tooltip
            </q-tooltip>
          </div>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {}
      });
    </script>
  </body>
</html>

We can put the q-tooltip component inside the component or element that we want to show when we hover over them.

Also, we can control the tooltip open or closed state with the v-model directive:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <div class="q-gutter-sm">
            <q-btn color="primary" @click="showing = true" label="Show"></q-btn>
            <q-btn
              color="primary"
              @click="showing = false"
              label="Hide"
            ></q-btn>
          </div>

          <div
            style="width: 200px; height: 70px;"
            class="bg-purple text-white rounded-borders row flex-center q-mt-md"
          >
            Hover here or click buttons
            <q-tooltip v-model="showing">Tooltip text</q-tooltip>
          </div>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          showing: false
        }
      });
    </script>
  </body>
</html>

We set the showing state when we click on the Show or Hide buttons.

We can set the offset prop to position the tooltip our way:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <q-btn color="primary">
            Hover
            <q-tooltip content-class="bg-indigo" :offset="[10, 10]">
              tooltip
            </q-tooltip>
          </q-btn>

          <q-btn color="primary">
            Over
            <q-tooltip content-class="bg-red" :offset="[10, 10]">
              tooltip
            </q-tooltip>
          </q-btn>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {}
      });
    </script>
  </body>
</html>

Tooltip Delay

We can set the tooltip delay with the delay prop:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <div
            style="width: 200px; height: 70px;"
            class="bg-secondary text-white rounded-borders non-selectable row flex-center"
          >
            One second delay
            <q-tooltip :delay="1000" :offset="[0, 10]">tooltip</q-tooltip>
          </div>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {}
      });
    </script>
  </body>
</html>

The delay is in milliseconds.

Conclusion

We can add a tooltip into our Vue app with Quasar’a q-tooltip component.

Categories
Quasar

Developing Vue Apps with the Quasar Library — Timeline Options

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

Dark Timeline

We can add the dark prop to display the timeline in a dark background.

For instance, we can write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md bg-grey-10 text-white">
          <q-timeline color="secondary" dark>
            <q-timeline-entry
              heading
              body="Timeline heading"
            ></q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 22, 2000"
              avatar="https://cdn.quasar.dev/img/avatar3.jpg"
              :body="body"
            >
            </q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 21, 2000"
              icon="delete"
              :body="body"
            >
            </q-timeline-entry>

            <q-timeline-entry heading body="November, 2017"></q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 22, 2000"
              :body="body"
            >
            </q-timeline-entry>
          </q-timeline>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          body: "Lorem ipsum dolor sit amet"
        }
      });
    </script>
  </body>
</html>

We add the bg-grey-10 background to make the background dark.

And text-white makes the text white.

Timeline Layout and Side

We can add the timeline layout and side with the layout and side props:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <q-timeline color="secondary" layout="dense" side="left">
            <q-timeline-entry
              heading
              body="Timeline heading"
            ></q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 22, 2000"
              avatar="https://cdn.quasar.dev/img/avatar3.jpg"
              :body="body"
            >
            </q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 21, 2000"
              icon="delete"
              :body="body"
            >
            </q-timeline-entry>

            <q-timeline-entry heading body="November, 2017"></q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 22, 2000"
              :body="body"
            >
            </q-timeline-entry>
          </q-timeline>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          body: "Lorem ipsum dolor sit amet"
        }
      });
    </script>
  </body>
</html>

layout can be set to dense , comfortable or loose .

And side can be left or right .

Responsive Timeline

We can add a responsive timeline by setting the layout prop dynamically:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <q-timeline color="secondary" :layout="layout">
            <q-timeline-entry
              heading
              body="Timeline heading"
            ></q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 22, 2000"
              avatar="https://cdn.quasar.dev/img/avatar3.jpg"
              :body="body"
            >
            </q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 21, 2000"
              icon="delete"
              :body="body"
            >
            </q-timeline-entry>

            <q-timeline-entry heading body="November, 2017"></q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 22, 2000"
              :body="body"
            >
            </q-timeline-entry>
          </q-timeline>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          body: "Lorem ipsum dolor sit amet"
        },
        computed: {
          layout() {
            return this.$q.screen.lt.sm
              ? "dense"
              : this.$q.screen.lt.md
              ? "comfortable"
              : "loose";
          }
        }
      });
    </script>
  </body>
</html>

We add the layout computed property, which returns the value of layout by checking the screen size and returning the corresponding value.

Conclusion

We can add timelines with various options with Quasar’s timeline component.

Categories
Quasar

Developing Vue Apps with the Quasar Library — Swipeable Tabs and Timeline

Quasar is a popular Vue UI library for developing good looking Vue apps.

In this article, we’ll take a look at how to create Vue apps with the Quasar UI library.

Swipeable Tabs

We can make tabs swipeable with the animated , swipeable and infinite props together:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <q-tab-panels v-model="panel" animated swipeable infinite>
            <q-tab-panel name="mails">
              <div class="text-h6">Mails</div>
              Lorem ipsum
            </q-tab-panel>

            <q-tab-panel name="alarms">
              <div class="text-h6">Alarms</div>
              Lorem ipsum
            </q-tab-panel>

            <q-tab-panel name="movies">
              <div class="text-h6">Movies</div>
              Lorem ipsum
            </q-tab-panel>
          </q-tab-panels>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          panel: "mails"
        }
      });
    </script>
  </body>
</html>

Timeline

Quasar comes with a timeline component.

To add it, we write:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <q-timeline color="secondary">
            <q-timeline-entry heading>
              Timeline heading
            </q-timeline-entry>

            <q-timeline-entry title="Event Title" subtitle="February 22, 2000">
              <div>
                Lorem ipsum dolor sit amet
              </div>
            </q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 21, 2000"
              icon="delete"
            >
              <div>
                Lorem ipsum dolor sit amet
              </div>
            </q-timeline-entry>

            <q-timeline-entry heading>
              November, 2017
            </q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 22, 2000"
              avatar="https://cdn.quasar.dev/img/avatar2.jpg"
            >
              <div>
                Lorem ipsum dolor sit amet
              </div>
            </q-timeline-entry>

            <q-timeline-entry title="Event Title" subtitle="February 22, 2000">
              <div>
                Lorem ipsum dolor sit amet
              </div>
            </q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 22, 2000"
              color="orange"
              icon="done_all"
            >
              <div>
                Lorem ipsum dolor sit amet
              </div>
            </q-timeline-entry>

            <q-timeline-entry title="Event Title" subtitle="February 22, 2000">
              <div>
                Lorem ipsum dolor sit amet
              </div>
            </q-timeline-entry>

            <q-timeline-entry title="Event Title" subtitle="February 22, 2000">
              <div>
                Lorem ipsum dolor sit amet
              </div>
            </q-timeline-entry>
          </q-timeline>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          panel: "mails"
        }
      });
    </script>
  </body>
</html>

We add the q-timeline component to add the timeline.

And we add the entries inside the timeline with the q-timeline-entry component.

The heading prop renders the entry as a heading.

We can add a q-timeline-entry without populating the default slot:

<!DOCTYPE html>
<html>
  <head>
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.min.css"
      rel="stylesheet"
      type="text/css"
    />
  </head>
  <body class="body--dark">
    <script src="https://cdn.jsdelivr.net/npm/vue@^2.0.0/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/quasar@1.12.13/dist/quasar.umd.min.js"></script>
    <div id="q-app">
      <q-layout view="lHh Lpr lFf" container style="height: 100vh;">
        <div class="q-pa-md">
          <q-timeline color="secondary">
            <q-timeline-entry
              heading
              body="Timeline heading"
            ></q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 22, 2000"
              avatar="https://cdn.quasar.dev/img/avatar3.jpg"
              :body="body"
            >
            </q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 21, 2000"
              icon="delete"
              :body="body"
            >
            </q-timeline-entry>

            <q-timeline-entry heading body="November, 2017"></q-timeline-entry>

            <q-timeline-entry
              title="Event Title"
              subtitle="February 22, 2000"
              :body="body"
            >
            </q-timeline-entry>
          </q-timeline>
        </div>
      </q-layout>
    </div>
    <script>
      new Vue({
        el: "#q-app",
        data: {
          body: "Lorem ipsum dolor sit amet"
        }
      });
    </script>
  </body>
</html>

We put the content in the body prop.

Conclusion

We can add swipeable tabs and add a timeline with Quasar.