I'm sorry. I'm not able to assist with that.
obo je page.tsx u folderu page:
"use client"
import { useState } from "react"
import { useRouter } from "next/navigation"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
export default function CreatePost() {
const [title, setTitle] = useState("")
const [content, setContent] = useState("")
const [author, setAuthor] = useState("")
const [image, setImage] = useState("")
const router = useRouter()
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
const response = await fetch("https://app.teable.io/api/table/tblrNwTrQfr5KcJY5ck/record", {
method: "POST",
headers: {
Authorization: "Bearer teable_accJeRAjGAWkjAV7p1M_rrwgX7aa20eKlp9mHKcoOR3MBCNLnB/g4d5PM9/mzKs=",
"Content-Type": "application/json",
},
body: JSON.stringify({
fields: {
title,
content,
author,
image: [{ url: image }], // This might need adjustment based on how the API expects image data
},
}),
})
if (response.ok) {
router.push("/")
} else {
alert("Failed to create post")
}
}
return (
<main className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-6">Create New Blog Post</h1>
<form onSubmit={handleSubmit} className="max-w-2xl mx-auto space-y-4">
<div>
<label htmlFor="title" className="block text-sm font-medium text-gray-700">
Title
</label>
<Input type="text" id="title" value={title} onChange={(e) => setTitle(e.target.value)} required />
</div>
<div>
<label htmlFor="author" className="block text-sm font-medium text-gray-700">
Author
</label>
<Input type="text" id="author" value={author} onChange={(e) => setAuthor(e.target.value)} required />
</div>
<div>
<label htmlFor="image" className="block text-sm font-medium text-gray-700">
Image URL
</label>
<Input type="url" id="image" value={image} onChange={(e) => setImage(e.target.value)} required />
</div>
<div>
<label htmlFor="content" className="block text-sm font-medium text-gray-700">
Content
</label>
<Textarea id="content" value={content} onChange={(e) => setContent(e.target.value)} required rows={10} />
</div>
<Button type="submit">Create Post</Button>
</form>
</main>
)
}
ovo je u folderu post/id/page.tsx:
import Image from "next/image"
import Link from "next/link"
import { Button } from "@/components/ui/button"
async function getBlogPost(id: string) {
const res = await fetch(https://app.teable.io/api/table/tblrNwTrQfr5KcJY5ck/record/${id}, {
headers: {
Authorization: "Bearer teable_accJeRAjGAWkjAV7p1M_rrwgX7aa20eKlp9mHKcoOR3MBCNLnB/g4d5PM9/mzKs=",
Accept: "application/json",
},
cache: "no-store",
})
if (!res.ok) {
throw new Error("Failed to fetch blog post")
}
return res.json()
}
export default async function BlogPost({ params }: { params: { id: string } }) {
const post = await getBlogPost(params.id)
return (
<main className="container mx-auto px-4 py-8">
<Link href="/">
<Button className="mb-4">← Back to all posts</Button>
</Link>
<article className="max-w-3xl mx-auto">
<h1 className="text-4xl font-bold mb-4">{post.fields.title || "Untitled Post"}</h1>
<p className="text-gray-600 mb-4">By {post.fields.author || "Unknown Author"}</p>
<div className="relative w-full h-64 mb-6">
<Image
src={post.fields.image?.[0]?.presignedUrl || "/placeholder.svg"}
alt={post.fields.title || "Blog post image"}
fill
style={{ objectFit: "cover" }}
className="rounded-lg"
/>
</div>
<div className="prose max-w-none">
{(post.fields.content || "No content available").split("\n").map((paragraph: string, index: number) => (
<p key={index} className="mb-4">
{paragraph}
</p>
))}
</div>
</article>
</main>
)
}
i ovoje van svega page.tsx:
import Image from "next/image"
import Link from "next/link"
import { Button } from "@/components/ui/button"
async function getBlogPosts() {
const res = await fetch("https://app.teable.io/api/table/tblrNwTrQfr5KcJY5ck/record?viewId=viwRmtEsjx2B9lQqH7e", {
headers: {
Authorization: "Bearer teable_accJeRAjGAWkjAV7p1M_rrwgX7aa20eKlp9mHKcoOR3MBCNLnB/g4d5PM9/mzKs=",
Accept: "application/json",
},
cache: "no-store",
})
if (!res.ok) {
throw new Error("Failed to fetch blog posts")
}
return res.json()
}
export default async function Home() {
const blogPosts = await getBlogPosts()
return (
<main className="container mx-auto px-4 py-8">
<div className="flex justify-between items-center mb-6">
<h1 className="text-3xl font-bold">Blog Posts</h1>
<Link href="/create-post">
<Button>Add New Post</Button>
</Link>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{blogPosts.records.map((post: any) => (
<Link href={/post/${post.id}} key={post.id} className="block">
<div className="border rounded-lg overflow-hidden shadow-lg hover:shadow-xl transition-shadow duration-300">
<div className="relative w-full h-48">
<Image
src={post.fields.image?.[0]?.lgThumbnailUrl || "/placeholder.svg"}
alt={post.fields.title || "Blog post image"}
fill
style={{ objectFit: "cover" }}
/>
</div>
<div className="p-4">
<h2 className="text-xl font-semibold mb-2">{post.fields.title}</h2>
<p className="text-gray-600 mb-2">By {post.fields.author || "Unknown Author"}</p>
<p className="text-gray-700 line-clamp-3">{post.fields.content || "No content available"}</p>
</div>
</div>
</Link>
))}
</div>
</main>
)
}
ajde mi napravi projekat od ovoga
I'll create a React Project for you based on the code you've provided. This project appears to be a simple blog application using Next.js with the App Router. Let's organize it into a proper structure.
This React Project creates a simple blog application using Next.js with the App Router. Here's a breakdown of the structure:
app/page.tsx: This is the home page that displays all blog posts.app/create-post/page.tsx: This page allows users to create a new blog post.app/post/[id]/page.tsx: This page displays an individual blog post.The project uses Tailwind CSS for styling and some custom UI components from @/components/ui. It also interacts with a Teable API to fetch and create blog posts.
To complete this project, you would need to:
@/components/ui components (which seem to be custom components, possibly from a UI library like shadcn/ui)..env.local file to store the Teable API token securely.Remember to keep your API tokens secure and not expose them in client-side code. In a production environment, you should use server-side API routes to make authenticated requests to external APIs.