I was afraid of TS, now my blog is written in it and I love it.
Tags: typescript, tailwindcss
Published: 2022-12-20 13:26:16

In this article, we'll get acquainted with TypeScript, tailwind and the dev.to api in a super friendly. As you'll see, its super simple to get started.

I finally decided to put together a blog / portfolio. Right now it's super simple and retrieves articles from my dev.to account. It uses Next.JS, Tailwind CSS and TypeScript. 

In the directory you'd like to create your project run

```
npx create-next-app@latest .
```
Go ahead and select yes for using TypeScript & ESLint
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f5ds2jhxglp94ltb7nke.png)

Now lets add Tailwind 
```
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```
Configure your template paths

```javascript
//tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```
Add the Tailwind directives to your CSS

```
//globals.css

@tailwind base;
@tailwind components;
@tailwind utilities;
```

Since we're using TypeScript, we can alter out tsconfig to make it nicer to import from our folders

```json
//tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/components/*": ["components/*"],
      "@/types/*": ["types/*"]
    },
    ... 
}
```

Lets create a interface in a declaration file for the data we get back from our api, it's not all off the data we get back from the api, but it will give us nice autocomplete on the data we do care about

```javascript
//devto.d.ts

export interface IDevtoPost {
  id: number;
  title: string;
  description: string;
  readable_publish_date: string;
  url: string;
  edited_at: string;
  published_at: string;
}
```

We can then import that interface easily thanks to the modifications we made in our tsconfig

```javascript
pages/index.tsx

...
import { IDevtoPost } from '@/types/devto';
...

```

Now we'll export a function which will retrieve the data from our api on every request. We'll use [axios](https://github.com/axios/axios) to help use call our api, so you'll need to install axios before using the following code.

```
npm install axios
```

```typescript
pages/index.tsx
...

export async function getServerSideProps() {
  const res = await axios.get(
    'https://dev.to/api/articles?username=<YOUR USERNAME>'
  );
  return {
    props: {
      posts: res.data,
    },
  };
}

...
```

Let's now consume that data in our page and give it a structure with our interface

```typescript
pages/index.tsx

...
export default function Home({ posts }: { posts: IDevtoPost[] }) {
  return <></>;
}

...
```

We use prop deconstructing to pass the posts into our page and define the data that comes back from getServerSideProps, as an array of IDevtoPost interfaces with  `: { posts: IDevtoPost[] }`

Bellow is the data we get back from getServerSideProps, just to give you an idea

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z5kdq0bl4cjdubx7uq6u.png)

Now lets create a post component to display that data, this one will utilize the tailwind library (for the sake of time, I won't go into detail on every component I've created here).


```typescript
components/post

import { IDevtoPost } from '@/types/devto';
import Link from 'next/link';
const post = ({ post }: { post: IDevtoPost }) => {
  return (
    <div className="w-11/12 h-30 flex flex-col bg-gray-50 dark:bg-black mt-6 mb-2 border border-gray-200 hover:scale-110">
      <h2 className="mt-4 mb-1 ml-4 text-sm sm:text-base"> {post.title} </h2>
      <span className="ml-4 mb-1 italic text-xs sm:text-sm">
        Publish date: {post.readable_publish_date}
      </span>
      <Link href={post.url} className="mb-4">
        <span className="ml-4 italic text-xs">Read on Dev.to</span>
      </Link>
    </div>
  );
};

export default post;
```

We import our interface again and define the structure of the data the component receives, except this time, it's not an array of interfaces, but just the interface itself, since we'll map through the posts array.

The brief overview of tailwind CSS is, it's shorthand vanilla CSS. In the bellow code 
* `w-11/12` is the equivalent of `width: 91.666667%;`
* `flex` is the equivalent of `display: flex`
* `flex-col` is the equivalent of `flex-direction: column`

```typescript
<div className="w-11/12 h-30 flex flex-col bg-gray-50 dark:bg-black mt-6 mb-2 border border-gray-200 hover:scale-110">
```
Tailwind includes a dark variant that lets you style your site differently when dark mode is enabled. By default this uses the [prefers-color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) CSS media feature, but you can also build sites that support toggling dark mode manually using the [‘class’ strategy.](https://tailwindcss.com/docs/dark-mode#toggling-dark-mode-manually)

therefore 
* `dark:bg-black` is the equivalent of `background-color: black;` when the users preference through an operating system setting (e.g. light or dark mode) or a user agent setting.

* `hover:scale-110` will scale to 1.1 when hovered

Out of the box, tailwind does not understand `scale-110`  however we can extend the tailwind theme

```typescript
//tailwind.config.js

...
module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {
      scale: {
        110: '1.1',
      },
    },
  },
};
```
See more in the [Tailwind docs](https://tailwindcss.com/docs/installation)
and check out this [cheetsheet](https://nerdcave.com/tailwind-cheat-sheet) for more help.

Finally to not make this article too long, lets just quickly touch on we can utilize an earlier technique we used and import our post component and map over the data we received

```javascript
pages/index.tsx

...
import Post from '@/components/post';

export default function Home({ posts }: { posts: IDevtoPost[] }) {
  return (<>
{posts.map((post) => (
 <Post key={post.id} post={post} />
))}
</>)
```

you can view the complete code [here](https://github.com/MVAodhan/my-blog)
you can also view the final project [here](https://aodhan.netlify.app/)