😺
v0でポートフォリオサイトを超々爆速開発した話
今までに作ってきたものを、まとめようと思い簡単なポートフォリオサイトを作ってみました。
使用したツールと技術
- デザイン: Vercel v0
- CMS: microCMS
- フロントエンドフレームワーク: Next.js(app router)
- デプロイ先: Vercel
完成したサイト
デザイン
デザインに自信がなくあまり時間をかけたくなかったので、v0で自動生成されたUIをベースに制作しました。
v0に「ブログ付きのポートフォリオサイト」とプロンプトを投げるだけで
ポートフォリオ一瞬で完成しちゃってビビりました。
そしてこれが無料でエクスポートできるので感無量です。
compornent.tsx
/**
* v0 by Vercel.
* @see https://v0.dev/t/qLlKDcfvo3m
* Documentation: https://v0.dev/docs#integrating-generated-code-into-your-nextjs-app
*/
import Link from "next/link"
import { Button } from "@/components/ui/button"
export default function Component() {
return (
<div className="flex flex-col min-h-dvh">
<header className="bg-background sticky top-0 z-50 border-b">
<div className="container mx-auto flex h-16 items-center justify-between px-4 md:px-6">
<Link href="#" className="flex items-center gap-2" prefetch={false}>
<MountainIcon className="h-6 w-6" />
<span className="text-lg font-bold">Your Name</span>
</Link>
<nav className="hidden space-x-4 md:flex">
<Link href="#" className="text-muted-foreground hover:text-foreground" prefetch={false}>
Home
</Link>
<Link href="#" className="text-muted-foreground hover:text-foreground" prefetch={false}>
Portfolio
</Link>
<Link href="#" className="text-primary hover:text-primary-foreground" prefetch={false}>
Blog
</Link>
</nav>
<Button variant="outline" size="sm" className="md:hidden">
<MenuIcon className="h-5 w-5" />
<span className="sr-only">Toggle Menu</span>
</Button>
</div>
</header>
<section className="bg-muted py-12 md:py-24">
<div className="container mx-auto flex flex-col items-center gap-6 px-4 md:flex-row md:gap-12">
<img src="/placeholder.svg" alt="Profile" width={300} height={300} className="rounded-full" />
<div className="space-y-4 text-center md:text-left">
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl">Hi, I'm John Doe</h1>
<p className="text-muted-foreground">
I'm a full-stack developer with a passion for creating beautiful and functional web applications.
</p>
<div className="flex justify-center gap-4 md:justify-start">
<Button>Hire Me</Button>
<Button variant="outline">View Portfolio</Button>
</div>
</div>
</div>
</section>
<section className="py-12 md:py-24">
<div className="container mx-auto px-4 md:px-6">
<div className="space-y-6">
<div className="space-y-2">
<h2 className="text-2xl font-bold tracking-tight sm:text-3xl">My Portfolio</h2>
<p className="text-muted-foreground">Check out some of my recent projects.</p>
</div>
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
<Link href="#" className="group" prefetch={false}>
<div className="overflow-hidden rounded-lg">
<img
src="/placeholder.svg"
alt="Project 1"
width={600}
height={400}
className="aspect-video w-full object-cover transition-all duration-300 group-hover:scale-105"
/>
</div>
<div className="mt-4 space-y-2">
<h3 className="text-lg font-semibold group-hover:text-primary">Project 1</h3>
<p className="text-muted-foreground">A brief description of the project.</p>
</div>
</Link>
<Link href="#" className="group" prefetch={false}>
<div className="overflow-hidden rounded-lg">
<img
src="/placeholder.svg"
alt="Project 2"
width={600}
height={400}
className="aspect-video w-full object-cover transition-all duration-300 group-hover:scale-105"
/>
</div>
<div className="mt-4 space-y-2">
<h3 className="text-lg font-semibold group-hover:text-primary">Project 2</h3>
<p className="text-muted-foreground">A brief description of the project.</p>
</div>
</Link>
<Link href="#" className="group" prefetch={false}>
<div className="overflow-hidden rounded-lg">
<img
src="/placeholder.svg"
alt="Project 3"
width={600}
height={400}
className="aspect-video w-full object-cover transition-all duration-300 group-hover:scale-105"
/>
</div>
<div className="mt-4 space-y-2">
<h3 className="text-lg font-semibold group-hover:text-primary">Project 3</h3>
<p className="text-muted-foreground">A brief description of the project.</p>
</div>
</Link>
</div>
</div>
</div>
</section>
<section className="bg-muted py-12 md:py-24">
<div className="container mx-auto px-4 md:px-6">
<div className="space-y-6">
<div className="space-y-2">
<h2 className="text-2xl font-bold tracking-tight sm:text-3xl">Latest from the Blog</h2>
<p className="text-muted-foreground">Read the latest news and updates from my blog.</p>
</div>
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
<Link href="#" className="group" prefetch={false}>
<div className="overflow-hidden rounded-lg">
<img
src="/placeholder.svg"
alt="Blog Post 1"
width={600}
height={400}
className="aspect-video w-full object-cover transition-all duration-300 group-hover:scale-105"
/>
</div>
<div className="mt-4 space-y-2">
<h3 className="text-lg font-semibold group-hover:text-primary">Blog Post 1</h3>
<p className="text-muted-foreground">A brief description of the blog post.</p>
</div>
</Link>
<Link href="#" className="group" prefetch={false}>
<div className="overflow-hidden rounded-lg">
<img
src="/placeholder.svg"
alt="Blog Post 2"
width={600}
height={400}
className="aspect-video w-full object-cover transition-all duration-300 group-hover:scale-105"
/>
</div>
<div className="mt-4 space-y-2">
<h3 className="text-lg font-semibold group-hover:text-primary">Blog Post 2</h3>
<p className="text-muted-foreground">A brief description of the blog post.</p>
</div>
</Link>
<Link href="#" className="group" prefetch={false}>
<div className="overflow-hidden rounded-lg">
<img
src="/placeholder.svg"
alt="Blog Post 3"
width={600}
height={400}
className="aspect-video w-full object-cover transition-all duration-300 group-hover:scale-105"
/>
</div>
<div className="mt-4 space-y-2">
<h3 className="text-lg font-semibold group-hover:text-primary">Blog Post 3</h3>
<p className="text-muted-foreground">A brief description of the blog post.</p>
</div>
</Link>
</div>
</div>
</div>
</section>
<footer className="bg-muted py-6">
<div className="container mx-auto flex flex-col items-center justify-between gap-4 px-4 md:flex-row">
<div className="flex items-center gap-2">
<MountainIcon className="h-6 w-6" />
<span className="text-lg font-bold">Your Name</span>
</div>
<div className="flex items-center gap-4">
<Link href="#" className="text-muted-foreground hover:text-foreground" prefetch={false}>
<TwitterIcon className="h-5 w-5" />
</Link>
<Link href="#" className="text-muted-foreground hover:text-foreground" prefetch={false}>
<LinkedinIcon className="h-5 w-5" />
</Link>
<Link href="#" className="text-muted-foreground hover:text-foreground" prefetch={false}>
<GitlabIcon className="h-5 w-5" />
</Link>
</div>
<p className="text-sm text-muted-foreground">© 2024 Your Name. All rights reserved.</p>
</div>
</footer>
</div>
)
}
function GitlabIcon(props) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m22 13.29-3.33-10a.42.42 0 0 0-.14-.18.38.38 0 0 0-.22-.11.39.39 0 0 0-.23.07.42.42 0 0 0-.14.18l-2.26 6.67H8.32L6.1 3.26a.42.42 0 0 0-.1-.18.38.38 0 0 0-.26-.08.39.39 0 0 0-.23.07.42.42 0 0 0-.14.18L2 13.29a.74.74 0 0 0 .27.83L12 21l9.69-6.88a.71.71 0 0 0 .31-.83Z" />
</svg>
)
}7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z" />
<rect width="4" height="12" x="2" y="9" />
<circle cx="4" cy="4" r="2" />
</svg>
)
...
}
すべてのコードが一つにまとまって出力されるので、これをヘッダー、フッターなどと切り分けて、少しデザインを調節するだけで簡単にサイト制作が終了してしまいます。
なんとここまでかかった時間およそ1時間...
ここで終わるのはもったいないのでブログ機能も付けてみることにしました。
CMSの設定
CMSは無料プランがあり日本語対応しているmicroCMSを導入しました。microCMSは、APIベースでコンテンツを取得するため、カスタマイズ性が高く、Getting Startedの通り実装していればいつの間にか完成していました。
デプロイ
最後に、Vercelを使ってデプロイを行いました。
最後に
合計3時間ぐらいで、そこそこ見栄えがいいサイトを完成させてしまって、かなり感動すると同時に、今までやってきたことは何なんだろうという無力感に襲われました...
これからv0なしでの開発は無理そうです...
Discussion