Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions fullstack/leones_blog_fullstack/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
5 changes: 5 additions & 0 deletions fullstack/leones_blog_fullstack/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->
1 change: 1 addition & 0 deletions fullstack/leones_blog_fullstack/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
36 changes: 36 additions & 0 deletions fullstack/leones_blog_fullstack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
25 changes: 25 additions & 0 deletions fullstack/leones_blog_fullstack/app/api/posts/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { posts } from "@/data/posts";
import { NextResponse } from "next/server";

interface Params {
params: Promise<{
id: string;
}>;
}

// Get specific post by id
export async function GET(request: Request, { params }: Params) {
const { id } = await params;

const post = posts.find((p) => p.id === Number(id));

if (!post) {
return NextResponse.json({ message: "Post not found" }, { status: 404 });
}

return NextResponse.json({
success: true,
message: "Fetched data successfully",
post,
});
}
11 changes: 11 additions & 0 deletions fullstack/leones_blog_fullstack/app/api/posts/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { posts } from "@/data/posts";
import { NextResponse } from "next/server";

// Get all posts
export async function GET() {
return NextResponse.json({
success: true,
message: "Fetched data successfully",
posts,
});
}
Binary file added fullstack/leones_blog_fullstack/app/favicon.ico
Binary file not shown.
26 changes: 26 additions & 0 deletions fullstack/leones_blog_fullstack/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@import "tailwindcss";

:root {
--background: #ffffff;
--foreground: #171717;
}

@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}

@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}

body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}
36 changes: 36 additions & 0 deletions fullstack/leones_blog_fullstack/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";

const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});

const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html
lang="en"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col">
{/* this is all the pages display */}
{children}
</body>
</html>
);
}
82 changes: 82 additions & 0 deletions fullstack/leones_blog_fullstack/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"use client";

import { useState, useEffect } from "react";
import Link from "next/link";
import { getAllPosts } from "@/lib/api";
import type { Posts } from "@/data/posts";

export default function Home() {
const [posts, setPosts] = useState<Posts[]>([]);

//fetching all the posts
useEffect(() => {
const fetchPosts = async () => {
try {
const res = await getAllPosts();
if (!res.data.success) {
throw new Error("Error Fetching Posts");
}
console.log(res.data.message);
setPosts(res.data.posts);
} catch (error) {
console.error(error);
setPosts([]);
}
};

fetchPosts();
}, []);

return (
<div className="min-h-screen bg-zinc-100 dark:bg-zinc-950 text-zinc-900 dark:text-zinc-100">
<main className="max-w-4xl mx-auto px-6 py-16">
{/* Header */}
<div className="mb-10 text-center">
<h1 className="text-4xl font-bold tracking-tight">My Blog</h1>
<p className="mt-2 text-zinc-500 dark:text-zinc-400">
Thoughts, tutorials, and updates
</p>
</div>

{/* Posts */}
<div className="grid gap-6">
{posts.map((post) => (
<article
key={post.id}
className="group rounded-2xl border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 p-6 shadow-sm hover:shadow-md transition-shadow"
>
{/* Title */}
<h2 className="text-xl font-semibold group-hover:text-blue-500 transition-colors">
{post.title}
</h2>

{/* Excerpt */}
<p className="mt-2 text-sm leading-relaxed text-zinc-600 dark:text-zinc-400">
{post.excerpt}
</p>

{/* Footer */}
<div className="mt-4 flex items-center justify-between">
<span className="text-xs text-zinc-400">Post #{post.id}</span>

<Link
href={`/posts/${post.id}`}
className="text-sm font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
>
Read more →
</Link>
</div>
</article>
))}
</div>

{/* Empty state */}
{posts.length === 0 && (
<div className="mt-16 text-center text-zinc-500">
No posts available.
</div>
)}
</main>
</div>
);
}
80 changes: 80 additions & 0 deletions fullstack/leones_blog_fullstack/app/posts/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"use client";

import { useEffect, useState } from "react";
import { useParams } from "next/navigation";
import Link from "next/link";
import { getPostById } from "@/lib/api";
import type { Posts } from "@/data/posts";

const Page = () => {
const params = useParams();
const id = Number(params.id);

const [post, setPost] = useState<Posts | null>(null);

useEffect(() => {
const fetchPost = async () => {
const res = await getPostById(id);
if (!res.data.success) {
throw new Error("Error Fetching specific post");
}
setPost(res.data.post);
};

if (id) fetchPost();
}, [id]);

if (!post) {
return (
<div className="min-h-screen flex items-center justify-center bg-zinc-50 dark:bg-zinc-950 text-zinc-500">
Loading article...
</div>
);
}

return (
<div className="min-h-screen bg-zinc-50 dark:bg-zinc-950 text-zinc-900 dark:text-zinc-100">
<main className="max-w-3xl mx-auto px-6 py-16">
{/* Back button */}
<div className="mb-6">
<Link
href="/"
className="inline-flex items-center text-sm text-zinc-600 dark:text-zinc-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
>
← Back to Home
</Link>
</div>

{/* Article container */}
<article className="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-2xl shadow-sm p-8 md:p-12">
{/* Header */}
<header className="mb-10">
<p className="text-sm text-zinc-500">{post.date}</p>

<h1 className="mt-3 text-3xl md:text-4xl font-bold leading-tight">
{post.title}
</h1>

<p className="mt-4 text-zinc-600 dark:text-zinc-400 leading-relaxed">
{post.excerpt}
</p>
</header>

{/* Content */}
<section className="prose prose-zinc dark:prose-invert max-w-none">
<p className="text-base leading-7 whitespace-pre-line">
{post.content}
</p>
</section>

{/* Footer */}
<footer className="mt-12 pt-6 border-t border-zinc-200 dark:border-zinc-800 text-sm text-zinc-500">
<p>Thanks for reading.</p>
</footer>
</article>
</main>
</div>
);
};

export default Page;
Loading