DEV Community

Spencer Tower
Spencer Tower

Posted on • Updated on

How ChatGPT Helped Me Build a Hacker News Clone - pt. 3

This continues my previous post using ChatGPT, Next.js, React, Typescript, and Tailwind CSS to create a Hacker News clone based on the following video: Building Hacker News with AI, describe a UI and AI builds it for us

In this post I will be prompting ChatGPT for the listing component of the homepage.


Prompt and Results:

Prompt to ChatGPT:

"I am building a Hacker News clone using Next.js, Tailwind CSS, React, and TypeScript. Only the UI. I need to create the listing component for displaying a list of news articles. Each article listing should include:

- Article number
- Article title
- Article URL in parentheses to the right of the title
- An upvote icon to the left of the article (between the list number and the article title)
- Under the article title: ""
- Number of points the article has received
- Author's name as a link, prefixed with "by "
- Number of hours ago the article was posted, formatted as "X hours ago" and clickable
- "hide" as a clickable link
- Number of comments, formatted as "X comments", as a link
- Example format: 160 points by author 2 hours ago | hide | 62 comments

Overall Color Scheme:
- The article title is solid black.
- The article number, URL, upvote icon, and content under the title are all light gray"

Result:

Listing Component Screenshot - ChatGPT Code

Code Generated for the Article Listing Component:

type Article = {
 number: number;
 title: "string;"
 url: string;
 points: number;
 author: string;
 timePosted: number;
 comments: number;
};


const ArticleList: React.FC<{ articles: Article[] }> = ({ articles }) => {
 return (
   <div className="space-y-4">
     {articles.map((article, index) => (
       <div key={index} className="flex flex-col space-y-1">
         <div className="flex items-center text-gray-500">
           <span className="mr-2">{article.number}.</span>
           <span className="mr-2"></span>
           <a href={article.url} className="text-black font-bold hover:underline">
             {article.title}
           </a>
           <span className="ml-2 text-gray-500">({article.url})</span>
         </div>
         <div className="text-gray-500">
           <span>{article.points} points</span>
           <span> by <a href={`/user/${article.author}`} className="hover:underline">{article.author}</a></span>
           <span> {article.timePosted} hours ago</span>
           <span> | <a href="#" className="hover:underline">hide</a></span>
           <span> | <a href={`/item/${article.number}`} className="hover:underline">{article.comments} comments</a></span>
         </div>
       </div>
     ))}
   </div>
 );
};
Enter fullscreen mode Exit fullscreen mode

Code to be integrated into page.tsx:

const articles = [
 {
   number: 1,
   title: "'Example Article 1',"
   url: 'https://example.com',
   points: 160,
   author: 'author1',
   timePosted: 2,
   comments: 62,
 },
 {
   number: 2,
   title: "'Example Article 2',"
   url: 'https://example2.com',
   points: 120,
   author: 'author2',
   timePosted: 5,
   comments: 45,
 },
 // Add more articles as needed
];


const HomePage: React.FC = () => {
 return (
   <div className="container mx-auto p-4">
     <ArticleList articles={articles} />
   </div>
 );
};

Enter fullscreen mode Exit fullscreen mode

I was also provided with an SVG option for the upvote icon as an alternative to <span className="mr-2">▲</span>:

<svg className="w-4 h-4 text-gray-500 mr-2" viewBox="0 0 24 24" fill="currentColor">
  <path d="M12 2l9 18H3z" />
</svg>
Enter fullscreen mode Exit fullscreen mode

Comments:
There are a few adjustments to make. Some of the spacing between the links is off. The title link underlines on hover. The "X hours ago" link, indicating how long ago the article was posted, is not clickable.

In my prompt to ChatGPT I did not mention that this code would be added to an existing app - something I may want to do in the future. It may also be helpful to provide code from the app so that the AI can adapt it's output. Despite this, the code did not require any initial edits integrate and run with the rest of the app.


Edits and Improvements:

Updated version of ArticleList.tsx:

const ArticleList: React.FC<{ articles: Article[] }> = ({ articles }) => {
 return (
   <div className="space-y-2 py-2 px-1 text-stardust">
     {articles.map((article, index) => (
       <div key={index} className="flex flex-col space-y-1">
         <div className="flex items-center">
           <span className="mr-2">{article.number}.</span>
           <Link href={`/vote/${article.number}`} ><svg className="w-4 h-4  mr-2" viewBox="0 0 24 24" fill="currentColor">
             <path d="M12 2l9 18H3z" />
           </svg></Link>
           <Link href={article.url} className="text-black text-base">
             {article.title}
           </Link>
           <span className="ml-2 "><Link href={`/from/${article.url}`} className="hover:underline">({article.url})</Link></span>
         </div>
         <div className=" pl-12 text-xs">
           <span >{article.points} points </span>
           <span> by <Link href={`/user/${article.author}`} className="hover:underline">{article.author}</Link></span>
           <span> <Link href={`/item/${article.number}`} className="hover:underline">{article.comments} hours ago</Link></span>
           <span> | <Link href="#" className="hover:underline">hide</Link></span>
           <span> | <Link href={`/item/${article.number}`} className="hover:underline">{article.comments} comments</Link></span>
         </div>
       </div>
     ))}
     <div>
       <Link href="#" className="pl-12 text-base">More</Link>
     </div>
   </div>
 );
};
Enter fullscreen mode Exit fullscreen mode

Updated version of page.tsx:

const Home: React.FC = () => {
   return (
       <div>
           <Head>
               <title>Hacker News Clone</title>
               <meta
                   name="description"
                   content="A Hacker News clone built with Next.js, TypeScript, and Tailwind CSS"
               />
               <link rel="icon" href="/favicon.ico" />
           </Head>
           <div className="px-36 py-2 font-sans text-sm">
               <div className="bg-stone-100">
                   <Header />
                   <ArticleList articles={articles} />
               </div>
           </div>
       </div>
   );
};

Enter fullscreen mode Exit fullscreen mode

I also added customized background and text colors to the tailwind config file:

colors: {
     'springwood': '#f6f6ef',
     'stardust': '#999999',
     },
Enter fullscreen mode Exit fullscreen mode

Result:

Listing Component Screenshot - Updated Code

A quick summary of changes made:

  • Tailwind adjustments - updated the text colors, font sizes, added padding and edited spacing between links
  • Swapped the upvote icon out for the suggested SVG to have a more customizable option, and made it clickable
  • Modularized article listing dummy data
  • Added a "More" link (I forgot to add this to the prompt)
  • Replaced <a> tags with the Next.js <Link> tag - one thing I have noticed is that ChatGPT does not readily generate <Link> tags for NextJS projects unless specified to do so

The next and final step is to add the header and make any final adjustments to the clone.

How ChatGPT Helped Me Build a Hacker News Clone - pt. 4

Top comments (0)