How I've built my website

Introduction

Hello you 👋.

A few days ago, I published a new version of my portfolio: the one on which you are currently reading this article. I never imagined that I would receive so many good feedbacks on twitter! Thanks to everyone who left me a comment, it made me extremely happy ☀️.

I promised it in the comments: I'm writing this article to explain how I created this website. I'll talk about both the design, and the technical part. With one exception, there is really nothing complicated: it took me about 30 hours from start to finish 🌱.

So hang on and let's get started!

Creation process

I'll confess right away: I didn't make any mockups 🙈. I often work without mockups when I build small projects, and I decided to do the same for my portfolio.

My goal was clear: I wanted to make something simple, uncluttered, and easily customizable. I tried to make a mix between my two main projects: Gumaffiliates and Uneed. I took the background of Gumaffiliates, the cards filtering system of Uneed, and the cards design of another tiny project that I had started a few weeks before. I was also inspired by https://deximal.com/ and the beautiful designs of Paperpillar: you must see their work!

And as many of you pointed out, I was also inspired by Nev Flynn's portfolio, which I recommend you check out! I want to thank him again in this article, because my website probably wouldn't have looked like this without him. 🙏

Technical part

Many of you have asked me on Linkedin and Twitter what tools I have used.

I used the exact same stack as for almost all my other projects: Nuxt and Tailwind! The design and functionality are really nothing special, except for the placement of the cards, which adapts to the screen size and is fully customizable. So that's what I'm going to talk about! 😋

When I started the development, I thought it would be easy: a flex or grid container, and that's it. But responsive turned out to be a bit more complicated than that! I wanted each card to be able to be placed exactly as I wanted it for each screen size. Each card could also have a different size and design. And finally, when changing the page, I wanted the cards to place themselves in the right position in a fluid way.

It was a lot of stuff, and I had to restart from scratch a few times because I didn't think of everything from the beginning. 😅

The next part is a bit technical. If you're not a developer, you'll probably want to skip to the conclusion!

Firstly, all cards are contained in a grid, which adapts the number of its columns to the size of the screen.

<transition-group
    name="cardTransition"
    class="grid max-w-6xl grid-cols-2 gap-4 px-6 py-6 mx-auto md:grid-cols-3 lg:grid-cols-4">
</transition-group>

Nothing too complicated if you are familiar with the CSS grid property, and TailwindCSS. If you're not, picture a grid, which contains a different number of columns for each screen size.

The <transition-group> tag is specific to vueJS, and allows you to apply a transition to child elements. Click here to read Vue's documentation on this topic.

Click here if you want to see the CSS code for the transition.
.cardTransition-item {
  transition: transform .5s;
}
.cardTransition-enter, .cardTransition-leave-to {
  transform: translateY(50%) scale(50%);
}
.cardTransition-leave-active {
  position: absolute;
  opacity: 0;
}

The interesting things happen inside this <transition-group> tag:

<div
    v-for="{ n, w, h, props } in filteredCards"
    :key="n"
    :class="`col-span-${w} row-span-${h}`"
    class="cardTransition-item"
>
    <component
        :is="`card-${n}`"
        :breakpoint="breakpoint"
        v-bind="props"
        class="w-full h-full"
    />
</div>

This code loops on an array called filteredCard, which contains all the cards to display on the page. Each is an object that contains several properties:

  • n: Its name, a string. Used to know which component to display.
  • w: Its width.
  • h: Its height.
  • props: Its props. Used for example to pass a post object to the blog post cards.

The <component> tag allows you to call a component dynamically by its name, as explained here.

And finally, the breakpoint property that is sent to each card contains the current screen size.

You now know how (wow try to repeat "you now know how wow" very fast 🤯 !!) the cards are dynamically placed on the grid. The code is not very long, but it is very powerful! 🔥

Then there is the way the cards are defined and sorted. Nothing too complicated here: I have a javascript file that contains all my cards defined by page and screen size, which looks like this:

    sm: [
      ...
    ],
    md: [
      ...
    ],
    lg: [
      ...
    ],
    xl: [
      { n: 'about', w: 2, h: 1 },
      { n: 'uneed', w: 1, h: 1 },
      { n: 'darkMode', w: 1, h: 1 },
      { n: 'socials', w: 1, h: 1 },
      { n: 'post', w: 2, h: 1, props: { post: posts[0] } },
      { n: 'gumaffiliates', w: 1, h: 1 },
      { n: 'post', w: 2, h: 1, props: { post: posts[1] } },
      { n: 'post', w: 2, h: 1, props: { post: posts[2] } }
    ]

Pretty long and boring, isn't it? Well this is the best way I've found to handle it 😄. But I'm open to suggestions here!

To sort the cards, it's quite simple: I just get the name of the current page (home, about...), and get the cards that correspond. And voila 🎉!

Conclusion

Finally, this website is not very complicated! If you still have questions or if something is not clear to you, don't hesitate to send me a message on Twitter: I'll be happy to help you.

If you're not a developer but would like to have a website like this, I'm currently thinking about creating a website builder on this topic! Send me a message if you are interested 😄

See you 👋

Contact me

Send me a message to hire me, just to talk or to tell me your best joke

2023 © - Made with a keyboard ⌨️