DEV Community

Aodhan Hamilton
Aodhan Hamilton

Posted on • Edited on

I was afraid of TS, now my blog is written in it and I love it.

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 .
Enter fullscreen mode Exit fullscreen mode

Go ahead and select yes for using TypeScript & ESLint
Image description

Now lets add Tailwind

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode

Configure your template paths

//tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

Add the Tailwind directives to your CSS

//globals.css

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

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

//tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/components/*": ["components/*"],
      "@/types/*": ["types/*"]
    },
    ... 
}
Enter fullscreen mode Exit fullscreen mode

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

//devto.d.ts

export interface IDevtoPost {
  id: number;
  title: string;
  description: string;
  readable_publish_date: string;
  url: string;
  edited_at: string;
  published_at: string;
}
Enter fullscreen mode Exit fullscreen mode

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

pages/index.tsx

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

Enter fullscreen mode Exit fullscreen mode

Now we'll export a function which will retrieve the data from our api on every request. We'll use axios to help use call our api, so you'll need to install axios before using the following code.

npm install axios
Enter fullscreen mode Exit fullscreen mode
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,
    },
  };
}

...
Enter fullscreen mode Exit fullscreen mode

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

pages/index.tsx

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

...
Enter fullscreen mode Exit fullscreen mode

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

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).

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;
Enter fullscreen mode Exit fullscreen mode

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
<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">
Enter fullscreen mode Exit fullscreen mode

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 CSS media feature, but you can also build sites that support toggling dark mode manually using the ‘class’ strategy.

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

//tailwind.config.js

...
module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {
      scale: {
        110: '1.1',
      },
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

See more in the Tailwind docs
and check out this cheetsheet 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

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} />
))}
</>)
Enter fullscreen mode Exit fullscreen mode

you can view the complete code here
you can also view the final project here

Top comments (0)