back
bolt.new 生成 CMS編集、サーバー保存等 修正 shadcnUI + React
id: 176, 2024-10-15
概要:
生成AI的な、bolt.new使用して。CMS作成後、機能追加等のメモになります。
- データ(配列データ)、サーバー保存の追加になります。
[ 公開日: 2024/10/14 ]
構成
- bolt.new
- shadcn/ui
- Express.js
- esbuild
- typescript
関連
作成したコード
https://github.com/kuc-arc-f/bolt_4example/tree/main/cms2
dev-start
bun run build
bun run dev
- APIエンドポイントに、POST通信
- cms2/src/routes/cmsData.ts
- https://github.com/kuc-arc-f/bolt_4example/blob/main/cms2/src/routes/cmsData.ts
....
create: function(body: any){
try {
if(!body){
throw new Error("nothing, body");
}
console.log(body);
const now = new Date();
const myUUID = uuidv4();
let row = {
id: myUUID,
title: body.title,
content: body.content,
createdAt: now.toISOString(),
}
this.items.push(row);
return this.items;
} catch (error) {
console.error(error);
throw new Error("error, create");
}
},
- TOP画面
- cms2/src/App.tsx
- https://github.com/kuc-arc-f/bolt_4example/blob/main/cms2/src/App.tsx
....
return (
<div className="container mx-auto p-4">
<h1 className="text-3xl font-bold mb-6">CMS Article Management</h1>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<Card>
<CardHeader>
<CardTitle>{editingId !== null ? "Edit Article" : "Add New Article"}</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-4">
<Input
type="text"
placeholder="Article Title"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
<Tabs defaultValue="edit" className="w-full">
<TabsList>
<TabsTrigger value="edit">Edit</TabsTrigger>
<TabsTrigger value="preview">Preview</TabsTrigger>
</TabsList>
<TabsContent value="edit">
<Textarea
placeholder="Article Content (Markdown supported)"
value={content}
onChange={(e) => setContent(e.target.value)}
required
rows={10}
/>
</TabsContent>
<TabsContent value="preview">
<div className="prose dark:prose-invert max-w-none">
<ReactMarkdown>{content}</ReactMarkdown>
</div>
</TabsContent>
</Tabs>
<Button type="submit">
{editingId !== null ? "Update Article" : "Add Article"}
</Button>
</form>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Article List</CardTitle>
<div className="relative">
<Search className="absolute left-2 top-1/2 transform -translate-y-1/2 text-gray-400" />
<Input
type="text"
placeholder="Search articles..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-8"
/>
</div>
</CardHeader>
<CardContent>
<ScrollArea className="h-[500px] pr-4">
{filteredArticles.map(article => (
<div key={article.id} className="mb-4 p-4 border rounded">
<h3 className="text-xl font-semibold mb-2">{article.title}</h3>
<div className="prose dark:prose-invert max-w-none text-sm text-gray-600 mb-2">
<ReactMarkdown>
{article.content.length > 150
? `${article.content.slice(0, 150)}...`
: article.content}
</ReactMarkdown>
</div>
<div className="flex space-x-2">
<Button variant="outline" size="sm" onClick={() => handleEdit(article)}>
<Edit className="w-4 h-4 mr-2" /> Edit
</Button>
<Button variant="destructive" size="sm" onClick={() => {
if (window.confirm("Delete OK?")) {
handleDelete(article.id)
}
}}>
<Trash2 className="w-4 h-4 mr-2" /> Delete
</Button>
</div>
</div>
))}
</ScrollArea>
</CardContent>
</Card>
</div>
</div>
);