DEV Community

Cover image for Creating a new portfolio with Svelte!
Lucas Lima do Nascimento
Lucas Lima do Nascimento

Posted on

Creating a new portfolio with Svelte!

Hello again!
For my first Svelte project, I decided to create a new portfolio with Svelte, since I didn't like my old portfolio that much.

First of all, here you can check it live:
My New Portfolio

So, for our project checklist, we have:

  • Homepage with PDF Resume download and links to other pages
  • Projects page with a Swiper of my projects
  • Bio page with my education info and more
  • 404 page
  • And all of that communicating with my CMS, for a non hard-coded content!

So, starting up, I created a new project using Vite, as you can see here.

After that, I quickly designed and coded the home page, which was simply an avatar, some text and a few buttons.
Homepage

Which is resembled by this code:

<div class="container">
  <div class="photo">
    <div class="picture">
      <a href="/sobre">
        <img src={avatar} alt="Minha foto" />
      </a>
      <a style="color: #ff3e00;border:none!important;" href="/sobre">
        <h1 class="title">Lucas Lima (LL)</h1>
      </a>
    </div>
    <div class="text">
        <h1>Boas vindas, aventureiro(a).</h1>
        <h1>Seja bem-vindo(a) ao meu portfólio!</h1>
    </div>
    <div class="grid-btn-container">
      <div class="btn">
        <a href="/projetos"><Button text={"Me leve aos projetos!"} /></a>
      </div>
      <div class="btn">
        <a><Button text={"Me dá logo um PDF!"} /></a
        >
      </div>
    </div>
  </div>
</div>

Enter fullscreen mode Exit fullscreen mode

And for that cool typewriting effect, I used the Typewriter package.

 <Typewriter cursor="#ff3e00" interval={60} cascade>
    <h1>Boas vindas, aventureiro(a).</h1>
    <h1>Seja bem-vindo(a) ao meu portfólio!</h1>
 </Typewriter>

Enter fullscreen mode Exit fullscreen mode

So, after that homepage was setup, it was time to create the routing! I started by searching into this repo for anything that could be useful and there I found tinro, which is like the easiest routing mechanism I could find for Svelte.

Then, I created the routes file, which resulted in something like this:

<script>
  import { Route } from "tinro";
  import Home from "./pages/Home.svelte";
</script>

<main>
  <Route path="/">
    <Home />
  </Route>
  <Route fallback redirect="/404" />
</main>

Enter fullscreen mode Exit fullscreen mode

That tinro is so small yet so powerful that I even created our fallback with redirect to the /404 route (which is not yet implemented) with just one line of code.

After that, I created components for the other pages and finalized the routing system.

<script>
  import { Route } from "tinro";
  import Projetos from "./pages/Projetos.svelte";
  import Sobre from "./pages/Sobre.svelte";
  import Home from "./pages/Home.svelte";
  import NotFound from "./pages/NotFound.svelte";
</script>

<main>
  <Route path="/">
    <Home />
  </Route>
  <Route path="/projetos">
    <Projetos />
  </Route>
  <Route path="/sobre">
    <Sobre />
  </Route>
  <Route path="/404">
    <NotFound />
  </Route>
  <Route fallback redirect="/404" />
</main>


Enter fullscreen mode Exit fullscreen mode

So here we have our full routing done, we have our Home, Projects, About and a 404 page with fallback and redirection, all that with just a few lines of code!

Since tinro uses the <a> tag of HTML to create our routes, sometimes (like in the case of our download button) we have a link, but it's not meant to take the user to some route, instead, it's responsible for downloading a file, for example. In this cases, we need to add the tinro-ignore flag inside our <a> tag for it to work properly!

Then, it was just a matter of creating the other pages, and all of them have some fetch inside them that looks something like this:

<script>
  import { onMount } from "svelte";
  let projects = [];
  onMount(async () => {
    await fetch(
      `link_for_our_cool_api`
    )
      .then((r) => r.json())
      .then((data) => {
        projects = data;
      });
  });
</script>
Enter fullscreen mode Exit fullscreen mode

And it's really cool that Svelte provides us with a simple mechanism to see if the component has loaded or not, in a way that we can easily handle loading and fallback components, like in this example:


      {#each education as { schoolName, courseName, date }}
        <div class="text-container">
          <h4 class="wordwrap"><strong>{courseName}</strong></h4>
          <h5 class="wordwrap">{schoolName}</h5>
          <h5 class="wordwrap">{date}</h5>
        </div>
      {:else}
        <div>
          <Icon />
        </div>
      {/each}


Enter fullscreen mode Exit fullscreen mode

In this case, it tries to render that text-container div for each education inside an array, but, if it can't, it fallbacks into the else, which renders our fallback loading component (in this case, <Icon/>).

And, I thinks it's worth mentioning that, for the projects page, I used the amazing Swiper Lib, which is insanely powerful and customizable!

Here is how that turned out:
Swiper
Which resembles something in these lines of code:

<Swiper
  modules={[Mousewheel, Pagination, Navigation]}
  mousewheel
  pagination={{
    type: "progressbar",
  }}
  loop={true}
  grabCursor
  navigation={!detectMob()}
>
</Swiper>

Enter fullscreen mode Exit fullscreen mode

And other pre-built component that I used and I think it's worth mentioning is the Accordion that exists in Carbon Components for Svelte. It's really pretty and works great too!

Accordion

And last, but not least, the 404 page! Which is simply our Icon component with some text informing the user and a button for the HomePage!


<div class="container">
  <Icon loading={false} />
  <h1>Opa forasteiro(a)... Vai com calma!</h1>
  <h5>Página não encontrada :/</h5>
  <div>
    <a href="/">
      <Button text="Voltar para o início!" />
    </a>
  </div>
</div>


Enter fullscreen mode Exit fullscreen mode

That's it! I hope with that I was able to cover the basics of my new portfolio with CMS integration and Svelte!
That's all folks! Thanks for reading ;D

Latest comments (0)