DEV Community

Cover image for How to Build a File Explorer using Xata and Vue.js
Moronfolu Olufunke
Moronfolu Olufunke

Posted on

How to Build a File Explorer using Xata and Vue.js

In our fast-paced digital age, where data rules supreme, having a robust and user-friendly file explorer is no longer a luxury but a necessity. Whether you are a developer seeking to streamline your file management tasks or a business owner looking to provide your users with an intuitive file navigation experience, building a File Explorer is a powerful solution. In this ever-evolving tech landscape, harnessing the right tools and frameworks is critical to creating efficient and responsive applications.

Enter Xata and Vue.js – a dynamic duo that promises to revolutionize how you approach file management. Xata, a modern, lightweight database designed for developers, and Vue.js, the progressive JavaScript framework known for its flexibility, combine seamlessly to help you craft a feature-rich File Explorer that is easy to develop and delightful to use.

Let us unlock the potential of Xata and Vue.js as we explore the fusion of Xata and Vue.js in building our own File Explorer that caters to our every need.

GitHub

Check out the complete source code here.

Netlify

We can access the live demo here.

Prerequisite

Understanding this article requires the following:

  • Installation of Node.js
  • Basic knowledge of JavaScript
  • Creating a free account with Xata

Creating a Vue app

We can create a new Vue app using the npm create vue@latest command.
Scaffolding the project would provide a list of options from which we can select the best fit for the project.

Styling

The CSS framework we will use in this project is Tachyons CSS, which we will install by running the command below in the terminal.

npm i tachyons
Enter fullscreen mode Exit fullscreen mode

Afterward, we will make it globally available for usage in the project by adding the line below in our src/main.js:

import 'tachyons/css/tachyons.css';
Enter fullscreen mode Exit fullscreen mode

Installing dependencies

We will need some vital dependencies to supercharge our file explorer application. We will install them accordingly using the command below:

npm install --save axios vue-axios @kyvg/vue3-notification vue-pdf-embed
Enter fullscreen mode Exit fullscreen mode

From the above command, we installed the following packages in our application:

  1. axios: This is a popular JavaScript library for making HTTP requests from the browser. It allows Vue.js applications to interact with APIs and fetch data from external sources
  2. vue-axios: This is a package that provides integration between Axios and Vue.js. It makes it easier to use Axios in Vue components.
  3. @kyvg/vue3-notification: This package is a Vue 3 notification plugin that shows notifications or alerts to the user in Vue applications. It is a handy tool for informing users about various events or updates.
  4. vue-pdf-embed: This package embeds PDF files into Vue.js application. It allows displaying PDF documents within Vue applications, making it useful for a File Explorer where users might want to preview or interact with PDF files.

To use these new dependencies in our application, we will edit our src/main.js like so:

import Notifications from "@kyvg/vue3-notification";
import axios from "axios";
import VueAxios from "vue-axios";
app.use(VueAxios, axios);
app.use(Notifications);
Enter fullscreen mode Exit fullscreen mode

Setting up the Xata database

We will harness the full potential of Xata as we build out our project. To kick things off, we will either log into our existing Xata account or create a new one. Once inside our Xata account, we will navigate to the database section and establish a fresh database tailored to our project's needs. In our specific case, we have aptly named our database file-explorer to align with the project's core objectives.

Once our database is in place, our next step involves crafting the essential tables and their corresponding records. We require two distinct tables within our project's scope: the 'users' and 'files' tables. The 'users' table serves as the repository for user information, while the 'files' table is designated to house detailed data about the files we intend to store within the Xata platform.

The media below shows we would create a ‘users’ table in Xata. The same process applies to creating the 'files' table.

creating users table

The ‘users’ table encompasses records such as usernames, email addresses, and passwords. To add these records to the table, we will follow the process in the media below:
adding records to the users table

We will also create the relevant records for the files table as shown below:
adding records to the files table

Links and relationships in Xata

When we upload a file, we want to associate the file with the user responsible for the upload. To do this, Xata provides a record type of link, which allows us to set up relationships between entities (tables). In other words, we can link the 'users' table to the 'files' table in a one-to-many relationship.

We will have a target table and a source table for this to happen. In our case, the 'files' table will be the source, and the 'users' table will be the target. This arrangement means we target a single user within the 'users' table from the 'files' table.

Here is how we can create a new record in the files table called user and give it a type of 'link to table':

creating records with the 'link to table' file type

Setting up Xata in our Vue application

To incorporate Xata into our project, we will follow these installation steps:

Install Xata SDK

We will run the following command in the command line interface:

npx xata
Enter fullscreen mode Exit fullscreen mode

Initialize Xata

Now, we can initialize Xata for use within the application with this command:

xata init
Enter fullscreen mode Exit fullscreen mode

Configuration Options

Xata will present us with various configuration options to choose from. After making our selections, Xata will generate essential files, including .xatrc and .env.

Edit API Key

To ensure our Vue application can access the Xata environment, we will need to modify the Xata API key within the Vue app like so:

VITE_XATA_API_KEY="add your api key"
Enter fullscreen mode Exit fullscreen mode

We can now modify the xata.js file to use this intialised VITE_XATA_API_KEY like so:

const defaultOptions = {
  enableBrowser: true,
  apiKey: import.meta.env.VITE_XATA_API_KEY,
  databaseURL:
    "https://...",
};
Enter fullscreen mode Exit fullscreen mode

We would have seamlessly integrated Xata into our project by following the steps above.

Creating the landing page

First, we will create a basic homepage and progressively enhance it as functionality requires. To do this, we will create a file in views/HomeView.vue and add the code block below:

<template>
  <header class="vh-100 bg-light-pink dt w-100 helvetica">
    <div class="background-container dtc v-mid cover ph3 ph4-m ph5-l">
      <div class="flex justify-around">
        <div>
          <h1 class="f2 f-subheadline-l measure lh-title nb1 fw9 white">
            Xata File Explorer
          </h1>
          <h2 class="f6 fw6 white">
            Storing and managing files made easy with Xata (File Attachments)
          </h2>
        </div>
      </div>
    </div>
  </header>
</template>
<style>
  .background-container {
    background-image: url("../assets/tamanna-rumee-QR56LDZADZ4-unsplash.jpg");
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

Now, when users open the link to the application, the landing page shows the below:

landing page

Building the Signup Page

To enable user registration for our application, a signup page is essential. We will create a new file called components/Signup.vue to achieve this. Then, we will populate it with the following code:

<template>
  <form
    @submit.prevent="signUp"
    class="ba b--white dark-pink bw4 bg-black br2 mw6 center pv2 ph4 shadow-5 f6">
    <h2 class="ttc tc">Sign Up</h2>
    <label for="name" class="db mb2">Username</label>
    <input
      id="username"
      v-model="username"
      name="username"
      type="text"
      class="db mb3 w-100 br2 pa2 ba bw1 b--black"
      placeholder="John Doe" />
    <label for="email" class="db mb2">Email</label>
    <input
      id="email"
      v-model="email"
      name="email"
      type="email"
      class="db mb3 w-100 br2 pa2 ba bw1 b--black"
      placeholder="example@email.com" />
    <label for="password" class="db mb2">Password</label>
    <input
      id="password"
      v-model="password"
      name="password"
      type="password"
      class="db mb3 w-100 br2 pa2 ba bw1 b--black"
      placeholder="••••••••" />
    <button
      type="submit"
      class="center db pv2 ph3 mb3 tracked bg-black ba br3 white hover-black hover-bg-dark-pink bg-animate pointer f7">
      Sign up
    </button>
    <p class="f7">
      Already have an account?
      <a @click="switchToSignin" class="white pointer b">Sign in</a>
    </p>
  </form>
</template>
Enter fullscreen mode Exit fullscreen mode

With the above, we have effectively established the user interface for our Signup page. Our next focus will be on implementing the essential functionality for authentication and authorization.

We will leverage Xata to achieve our authentication objectives. To integrate Xata into our SignupView, let us start by adding the following code to the components/Signup.vue file:

<script>
  import { getXataClient } from "@/xata";
  export default {
    name: "Signup",
    data: () => ({
      username: "",
      email: "",
      password: "",
    }),
    methods: {
      switchToSignin() {
        this.$emit("user-has-account", true);
      },
      async signUp() {
        const xata = getXataClient();
        const user = await xata.db.users.filter("email", this.email).getFirst();
        if (!user) {
          await xata.db.users
            .create({
              username: this.username,
              password: this.password,
              email: this.email,
            })
            .then((res) => {
              this.$router.push({
                name: "dashboard",
                params: { username: res.username },
                query: { user: res },
              });
              this.$notify({
                type: "success",
                text: "Account creation successful!",
              });
            });
        }
      },
    },
  };
</script>
Enter fullscreen mode Exit fullscreen mode

The code block provided above allowed us to accomplish the following:

  • Imported the Xata client, establishing the connection necessary for interacting with our database
  • Implemented a mechanism to check for the existence of a user. Our code creates a new user profile if the current user doesn't exist
  • Upon successfully creating a user account, the user is seamlessly redirected to the dashboard (which we will create later). Here, the users can access the functionality required to manage their files efficiently

Building the sign-in page

In addition to user registration, providing a seamless sign-in experience for individuals who already possess an account is essential. We will generate a new file named Signin.vue to achieve this. Within this file, we will insert the code below:

<template>
  <form
    class="ba f6 b--white bw4 bg-black dark-pink br2 center pa3 shadow-5"
    @submit.prevent="signIn">
    <h2 class="ttc tc">Sign In</h2>
    <label for="email" class="db mb2">Email</label>
    <input
      id="email"
      v-model="email"
      name="email"
      type="email"
      class="db mb3 w-100 br2 pa2 ba bw1 b--black"
      placeholder="example@email.com" />
    <label for="password" class="db mb2">Password</label>
    <input
      id="password"
      v-model="password"
      name="password"
      type="password"
      class="db mb3 w-100 br2 pa2 ba bw1 b--black"
      placeholder="••••••••" />
    <button
      type="submit"
      class="f7 center db pv2 ph3 mb3 tracked bg-black ba br3 white pointer hover-black hover-bg-dark-pink bg-animate pointer">
      Sign in
    </button>
    <p>
      Don't have an account?
      <a @click="goToSignUp" class="white b f7 pointer">Sign up</a>
    </p>
  </form>
</template>
Enter fullscreen mode Exit fullscreen mode

The code provided above furnishes us with the foundation for our sign-in interface. However, we must incorporate some key functionalities to ensure it function as intended.
To achieve this, let us add the following code to the <script></script> section of the SigninView.vue file:

<script>
  import { getXataClient } from "@/xata";
  export default {
    name: "Signin",
    data: () => ({
      email: "",
      password: "",
    }),
    methods: {
      goToSignUp() {
        this.$emit("go-to-sign-up");
      },
      async signIn() {
        const xata = getXataClient();
        const user = await xata.db.users.filter("email", this.email).getFirst();
        if (!this.email || !this.password) {
          this.$notify({ type: "error", text: "Please fill all empty fields" });
        } else if (
          this.email !== user.email ||
          this.password !== user.password
        ) {
          this.$notify({ type: "error", text: "Incorrect credentials" });
          this.email = "";
          this.password = "";
        } else {
          this.$router.push({
            name: "dashboard",
            params: { id: user.id },
          });
          this.$notify({ type: "success", text: "Login successful!" });
        }
      },
    },
  };
</script>
Enter fullscreen mode Exit fullscreen mode

The code block above does the following:

  • Imported the Xata client, establishing the connection needed to interact with our database
  • Our code checks if the user has provided an email and a password. If either of these is missing, it returns the relevant error message
  • Implemented a verification step by comparing the entered email and password with the corresponding records stored in the database
  • Upon successful validation, the user is seamlessly redirected to the dashboard. Here, they gain access to the functionality required for managing files effortlessly

To view the sign-in and signup components, we will import them into the views/HomeView.vue, like so:

<template>
  <header class="vh-100 bg-light-pink dt w-100 helvetica">
    <div class="background-container dtc v-mid cover ph3 ph4-m ph5-l">
      <div class="flex justify-around">
        <!-- main code -->
        <div class="mv2">
          <div v-if="userHasAccount">
            <Signin @go-to-sign-up="switchToSignUp" />
          </div>
          <div v-else>
            <Signup @user-has-account="handleUserHasAccount" />
          </div>
        </div>
      </div>
    </div>
  </header>
</template>
<script>
  import Signin from "@/components/Signin.vue";
  import Signup from "@/components/Signup.vue";
  export default {
    components: {
      Signin,
      Signup,
    },
    data() {
      return {
        userHasAccount: false,
      };
    },
    methods: {
      handleUserHasAccount(value) {
        this.userHasAccount = value;
      },
      switchToSignUp() {
        this.userHasAccount = false;
      },
    },
  };
</script>
Enter fullscreen mode Exit fullscreen mode

The code block above does the following:

  • Imported the two child components, Signin and Signup, which handle the sign-in and signup functionality
  • The data property initialises the component's userHasAccountdata property as false. This property controls whether the sign-in or signup form should be displayed
  • handleUserHasAccount(value): This method updates the userHasAccount property based on whether the user has an account. It is called when the Signup component emits the user-has-account event
  • switchToSignUp(): This method sets userHasAccount to false, switching the view to the signup form

At this point, our interface should look like the below:

landing page with sign-in and sign-up interface

Adding upload mechanism

Designing the Upload User Interface
To streamline the process of uploading files, we will create a new file named, components/Uploader.vue, and then we will add the following code block into the file:

<template>
  <div class="flex flex-column flex-row-ns pa3 calisto bg-black-05">
    <div class="w-100 ph3">
      <form enctype="multipart/form-data" v-if="isInitial || isSaving">
        <h2>Upload File</h2>
        <div
          class="b--dashed bw1 b--light-purple pa3 hover-bg-black-10 bg-animate pointer relative h4">
          <input
            type="file"
            accept="image/*,application/pdf"
            class="input-file absolute w-100 h4 pointer o-0" />
          <p  class="tc f4">
            Drag your file here to begin<br />
            or click to browse
          </p>
        </div>
      </form>
    </div>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

We achieved the following from the above:

  • Implemented a <form> element with the enctype="multipart/form-data" attribute, facilitating file uploads
  • Incorporated an input field with the file type attribute, allowing file uploads and restricting the input to accept only pdf and image files using the accept="image/*,application/pdf" attribute

Now, our upload interface should look like the below:

uploader interface

Adding an upload service

To handle the file upload to be displayed in the UI, we will create a utils/file-upload.service.js and add the code block below:

function upload(formData) {
  const photos = formData.getAll('photos');
  const promises = photos.map((x) => getImage(x)
  .then(img => ({
    id: img,
    originalName: x.name,
    fileName: x.name,
    url: img
  })));
  return Promise.all(promises);
}
function getImage(file) {
  return new Promise((resolve, reject) => {
    const fReader = new FileReader();
    const img = document.createElement('img');
    fReader.onload = () => {
      img.src = fReader.result;
      resolve(getBase64Image(img));
    }
    fReader.readAsDataURL(file);
  })
}
function getBase64Image(img) {
  const canvas = document.createElement('canvas');
  canvas.width = img.width;
  canvas.height = img.height;
  const ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);
  const dataURL = img.src;
  return dataURL;
}
export { upload }
Enter fullscreen mode Exit fullscreen mode

The code above reads the image we will upload, draws it into a canvas, and then converts it to a Base64 string.

Uploading the file to Xata

To upload the file to Xata, we will edit the components/Uploader.vue to the below:

In the code block above, we achieved the following:

  • Represented various component states during file uploading using STATUS_INITIAL, STATUS_SAVING, STATUS_SUCCESS, and STATUS_FAILED definitions, which we initialised in the corresponding computed properties - isInitial, isSaving, isSuccess, and isFailed
  • File Upload Section:
    • This section contains a form (<form>) with enctype="multipart/form-data" for file upload
    • It displays an "Upload File" heading and a drag-and-drop or file input field that allows users to select files
    • Depending on the component's state, it shows messages like "Drag your file here to begin" or "Adding file..." to provide user feedback
    • When a file is successfully added, it displays a success message and an option to upload another file and previews the uploaded file just by the side
      • If the uploaded file is an image, then the <img /> element will have its :src attribute populated with the right URL
      • However, if the file is a pdf, the earlier installed vue-pdf-embed package has its :source filled with the right pdf URL to show the document
  • Component Data:
    • The component manages various data properties, including uploadError, currentStatus, fileDataObject, fileURL, and fileName, to track the state and information related to the file uploads and processing
  • Methods:
    • reset(): Resets the form and component's state to its initial state - STATUS_INITIAL
    • save(formData): Initiate the file uploadFileToXata() to foster uploading to Xata by using the upload service
    • filesChange(fieldName, fileList): Handles changes in the selected files and prepares a formData object for upload
    • prepareFormData(): Processes uploaded file data to create an object with metadata, base64 content, name, and URL for the uploaded image
    • uploadFileToXata(): Uploads the processed file data to a database using the Xata client. The xata.db.files.create({ … }) takes in the user object, which is necessary to link the file we will upload to the user who uploads it

At this stage, our user interface will look like this:

file upload to xata

Listing uploaded files

We have done a great job by allowing the user upload their files to Xata database. But our file explorer will not be enough if the users cannot view these files and download them if need be. To allow the user view all the files we have uploaded, we will create a new file called, components/Filelist.vue. In this newly created file, we will add the code below:

<template>
  <main class="flex flex-wrap items-center justify-between">
    <div v-if="files">
      <section
        class="w-33-l w-50-m w-100 h-50"
        v-for="file in files"
        :key="file.id">
        <div
          class="link dt bb b--black-10 pb2 mt2 blue pointer flex items-center">
          <div class="dtc w3">
            <div v-if="file.file.mediaType.toLowerCase().includes('image')">
              <img :src="file.file.url" alt="Uploaded Image" />
            </div>
            <div v-else-if="file.file.mediaType.toLowerCase().includes('pdf')">
              <img
                src="../assets//pdf-placeholder.png"
                alt="pdf placeholder Image" />
            </div>
          </div>
          <div class="dtc v-top pl2">
            <h1 class="f6 f5-ns fw6 lh-title black mv0">File Name:</h1>
            <h2 class="f7 fw4 mt2 mb0 black-60">{{ file.file.name }}</h2>
            <a
              class="bg-purple dib mv2 f7 pa1 br2 pointer black"
              @click="viewFile(file)"
              >View File</a
            >
          </div>
        </div>
      </section>
    </div>
    <div v-else class="tc f4">No files uploaded yet</div>
  </main>
</template>
<script>
  import { getXataClient } from "@/xata";
  const xata = getXataClient();
  export default {
    data() {
      return {
        files: [],
      };
    },
    components: {
      VuePdfEmbed,
    },
    mounted() {
      this.getFilesFromXata();
    },
    methods: {
      async getFilesFromXata() {
        const userId = this.$route.params.id;
        this.files = await xata.db.files
          .filter({ "user.id": userId })
          .getMany();
      },
    },
  };
</script>
Enter fullscreen mode Exit fullscreen mode

The code above does the following:

  • Vue.js directives like v-if, v-for, and v-else conditionally render content based on whether there are files to display
  • Iterates through the list of files and displays each file's details, such as its type (image or PDF), name, and an option to view the file
  • The data function initializes the files array, storing the list of files to be displayed
  • In the mounted lifecycle hook, the component calls the getFilesFromXata method to fetch the list of files associated with the user when the component is mounted
  • The getFilesFromXata method retrieves files associated with a specific user using Xata's database query capabilities. It filters files based on the user's ID and populates the files array with the retrieved data

Our interface should appear like below:
Listing uploaded files interface

Viewing file content

The implementation above allows users to see a list of all the files they have uploaded to Xata, but it does not cover viewing the file content. To allow users view the uploaded files, we will create a new component called, Fileviewer.vue and add the code below:

    <template>
      <div class="overlay">
        <!-- Overlay content -->
        <div class="overlay-content">
          <!-- Close button -->
          <span
            class="close-button f3 bg-dark-pink white b h1 w1 br3 pa2 center auto flex items-center dim pointer"
            @click="closeOverlay"
            >X</span
          >
          <div v-if="fileType === 'image'">
            <img :src="fileUrl" alt="File" />
            <img
              @click="downloadImage"
              src="../assets/icon_download.svg"
              class="bg-dark-pink pa2 flex items-center br2 white download-button dim" />
          </div>
          <div v-else-if="fileType === 'pdf'">
            <a ref="downloadLink" @click="downloadPdf(fileUrl)">
              <img
                src="../assets/icon_download.svg"
                class="bg-dark-pink pa2 flex items-center br2 white download-button dim" />
            </a>
            <vue-pdf-embed :source="fileUrl" />
          </div>
        </div>
      </div>
    </template>
    <script>
      import VuePdfEmbed from "vue-pdf-embed";
      export default {
        props: {
          fileUrl: String,
          fileType: String,
        },
        components: {
          VuePdfEmbed,
        },
        methods: {
          closeOverlay() {
            this.$emit("close-overlay");
          },
          downloadImage() {
            this.$emit("download-image");
          },
          async downloadPdf(file) {
            try {
              const response = await this.axios.get(file, {
                responseType: "blob", // Set the response type to 'blob' for binary data
              });
              const blob = new Blob([response.data], { type: "application/pdf" });
              const url = window.URL.createObjectURL(blob);
              const link = document.createElement("a");
              link.href = url;
              link.download = "downloaded.pdf"; // Set the desired file name
              link.click();
              window.URL.revokeObjectURL(url);
            } catch (error) {
              console.error("Error downloading PDF:", error);
            }
          },
        },
      };
    </script>
    <style scoped>
      .overlay {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.8);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 9999;
      }
      .overlay-content {
        background: #fff;
        padding: 20px;
        max-width: 80%;
        max-height: 80%;
        overflow: auto;
      }
      .close-button {
        position: absolute;
        top: 25px;
        right: 30px;
      }
      .download-button {
        position: absolute;
        top: 25px;
        left: 30px;
      }
    </style>

Enter fullscreen mode Exit fullscreen mode
  • An "X" button for closing the overlay (the closeOverlay method is called on click)
  • fileType prop (either 'image' or 'pdf') displays an image or a PDF viewer component
  • It imports the VuePdfEmbed component for displaying PDFs
  • The component receives two props: fileUrl (the file URL to display or download) and fileType (indicating whether it's an image or PDF)
  • closeOverlay(): This method emits the "close-overlay" event to signal that the overlay should be closed
  • downloadImage(): This method emits the "download-image" event to trigger image download
  • downloadPdf(file): This method handles PDF download. It uses Axios to fetch the PDF file as binary data, creates a Blob from the response, and generates a downloadable link for the user. If an error occurs during the download process, it's logged to the console

In the Filelist.vue component, we will import the Fileviewer.vue and add the necessary methods like so:

<template>
  <main class="flex flex-wrap items-center justify-between">
    <div v-if="files">
      <section
        class="w-33-l w-50-m w-100 h-50"
        v-for="file in files"
        :key="file.id">
        <div
          class="link dt bb b--black-10 pb2 mt2 blue pointer flex items-center">
          <div class="dtc w3">
            <!-- codes -->
          </div>
          <div class="dtc v-top pl2">
            <!-- codes -->
            <file-viewer
              v-if="showOverlay"
              ref="goat"
              :fileUrl="overlayFileUrl"
              :fileType="overlayFileType"
              @close-overlay="closeOverlay"
              @download-image="downloadImage"></file-viewer>
          </div>
        </div>
      </section>
    </div>
  </main>
</template>
<script>
  import { transformImage } from "@xata.io/client";
  import { getXataClient } from "@/xata";
  import Fileviewer from "@/components/Fileviewer.vue";
  const xata = getXataClient();
  export default {
    data() {
      return {
        showOverlay: false,
        overlayFileUrl: "",
        overlayFileType: "",
      };
    },
    components: {
      Fileviewer,
    },
    mounted() {
      this.getFilesFromXata();
    },
    methods: {
    // other methods
      viewFile(file) {
        this.overlayFileUrl = file.file.url;
        file.file.mediaType.toLowerCase().includes("image")
          ? (this.overlayFileType = "image")
          : (this.overlayFileType = "pdf");
        this.showOverlay = true;
      },
      closeOverlay() {
        this.showOverlay = false;
      },
      downloadImage() {
        const imageToDownload = transformImage(this.overlayFileUrl, {
          download: "image",
          format: "jpeg",
        });
        window.open(imageToDownload, "_blank");
      },
    },
  };
</script>
Enter fullscreen mode Exit fullscreen mode

We achieved the following using the code block above:

  • Imported transformImage from "@xata.io/client" and getXataClient from "@/xata"
  • viewFile(file): When a user clicks on a file, this method is called. It sets the overlayFileUrl to the URL of the clicked file, determines the file type (image or PDF) based on its media type, and sets showOverlay to true to display the overlay
  • closeOverlay(): This method is called when the user wants to close the overlay. It sets showOverlay to false, hiding the overlay
  • downloadImage(): This method is called when the user wants to download an image. It transforms the image using Xata's transformImage function, then opens a new browser window to download the transformed image

We should have our UI looking like this at this stage:

interface for file viewing

Now we will create a new file called, views/DashboardView.vue which will be our dashboard. In this file, we will import the components/Uploader.vue and the components/Filelist.vue file, like so:

<template>
  <div class="bg-light-purple vh-100 dt w-100 helvetica pv2 ph3">
    <div class="flex justify-between items-center">
      <h1 class="ttc">Xata File Explorer</h1>
      <span class="b db underline-hover pointer" @click="signOut"
        >Sign out</span
      >
    </div>
    <Uploader />
  </div>
</template>
<script>
  import Uploader from "@/components/Uploader.vue";
  export default {
    components: {
      Uploader,
    },
    methods: {
      signOut() {
        this.$router.push({ name: "home" });
        this.$route.params.id = "";
        this.$notify({ type: "success", text: "User logged out!" });
      },
    },
  };
</script>
Enter fullscreen mode Exit fullscreen mode

In the code above, we achieved the following:

  • Created a new file called views/DashboardView.vue
  • Imported the Upload component
  • Created a signOut method that logs users out

At this point, our file explorer application built with Xata should look like the below:

the complete file explorer application

Conclusion

In this article, we talked about building a File Explorer using Xata. This project exemplifies the capabilities of Xata and Vue.js and the amazing tools we can build from combining these two tools together or individually. The File Explorer we built is the beginning of what we can achieve.

Resources

Here are some additional resources that will be helpful when working with Xata:

Top comments (2)

Collapse
 
gbetibienvenu profile image
gbetibienvenu • Edited

Wow .....Brovo .... in fact i fall in love with the code and the documentation straight away 🙌🙌🙌

Collapse
 
moerayo profile image
Moronfolu Olufunke

Thanks for the feedback. I am glad you found it helpful.