Using v0 by Vercel
My First try at creating a Web App, its pretty cool what you can do with the power of AI. This was unheard of around a couple of years ago.
By just typing a simple prompt you can create your ideas into reality.
Imagine just by saying to a computer what you want your app to be it can generate it in just a couple of seconds. You can also make edits on the fly to refine and perfect your designs. Its just awesome.
here is a link to what I have just created using this amazing tool.
https://b_C60UnkL5Fdv.v0.build/
Here is the code for this web app:
'use client'
import { useState, useRef } from 'react'
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Maximize2, Minimize2, Upload, ZoomIn, ZoomOut } from 'lucide-react'
export default function Component() {
const [banner, setBanner] = useState('/placeholder.svg?height=200&width=1280')
const [avatar, setAvatar] = useState('/placeholder.svg?height=80&width=80')
const [watermark, setWatermark] = useState('/placeholder.svg?height=40&width=40')
const [channelName, setChannelName] = useState('Channel Name')
const [isFullScreen, setIsFullScreen] = useState(false)
const [activeDevice, setActiveDevice] = useState('mobile')
const [zoomLevel, setZoomLevel] = useState(1)
const bannerInputRef = useRef(null)
const avatarInputRef = useRef(null)
const watermarkInputRef = useRef(null)
const handleImageUpload = (event, setter) => {
const file = event.target.files[0]
if (file) {
const reader = new FileReader()
reader.onload = (e) => setter(e.target.result)
reader.readAsDataURL(file)
}
}
const toggleFullScreen = () => {
setIsFullScreen(!isFullScreen)
}
const handleZoomIn = () => {
setZoomLevel(prevZoom => Math.min(prevZoom + 0.1, 2))
}
const handleZoomOut = () => {
setZoomLevel(prevZoom => Math.max(prevZoom - 0.1, 0.5))
}
const DevicePreview = ({ device }) => {
const sizes = {
mobile: 'w-64',
tablet: 'w-[768px]',
desktop: 'w-[1024px]',
hdtv: 'w-[1920px]'
}
return (
<div classname="{`mx-auto" ${sizes[device]} overflow-hidden bg-[#0f0f0f] shadow-lg relative border-4 border-gray-700`}>
<div classname="relative">
<img src="{banner}" alt="Channel Banner" classname="w-full h-32 object-cover" />
<img src="{avatar}" alt="Channel Avatar" classname="absolute bottom-0 left-4 transform translate-y-1/2 w-16 h-16 rounded-full border-4 border-[#0f0f0f]" />
<img src="{watermark}" alt="Watermark" classname="absolute top-2 right-2 w-8 h-8" />
</div>
<div classname="p-4">
<h2 classname="text-xl font-bold text-white">{channelName}</h2>
<p classname="text-sm text-gray-400">1M subscribers</p>
</div>
<div classname="px-4 pb-4 grid grid-cols-2 gap-4">
<div classname="space-y-2">
<img src="/placeholder.svg?height=120&width=210" alt="Video Thumbnail" classname="w-full aspect-video object-cover rounded" />
<h3 classname="text-sm font-semibold text-white">Video Title 1</h3>
<p classname="text-xs text-gray-400">10K views • 2 days ago</p>
</div>
<div classname="space-y-2">
<img src="/placeholder.svg?height=120&width=210" alt="Video Thumbnail" classname="w-full aspect-video object-cover rounded" />
<h3 classname="text-sm font-semibold text-white">Video Title 2</h3>
<p classname="text-xs text-gray-400">8K views • 3 days ago</p>
</div>
<div classname="space-y-2">
<img src="/placeholder.svg?height=120&width=210" alt="Video Thumbnail" classname="w-full aspect-video object-cover rounded" />
<h3 classname="text-sm font-semibold text-white">Video Title 3</h3>
<p classname="text-xs text-gray-400">15K views • 1 week ago</p>
</div>
<div classname="space-y-2">
<img src="/placeholder.svg?height=120&width=210" alt="Video Thumbnail" classname="w-full aspect-video object-cover rounded" />
<h3 classname="text-sm font-semibold text-white">Video Title 4</h3>
<p classname="text-xs text-gray-400">5K views • 2 weeks ago</p>
</div>
</div>
</div>
)
}
return (
<div classname="{`min-h-screen" ${isfullscreen ? 'fixed inset-0 z-50' : ''} bg-gray-800 text-gray-100`}>
<div classname="container mx-auto p-4">
<h1 classname="text-2xl font-bold mb-4">YouTube Channel Mockup</h1>
<div classname="{`grid" ${isfullscreen ? '' : 'grid-cols-1 lg:grid-cols-3'} gap-4`}>
{!isFullScreen && (
<div classname="lg:col-span-1">
<h2 classname="text-xl font-semibold mb-4">Upload Channel Assets</h2>
<div classname="space-y-4">
<div>
<label htmlfor="banner" classname="block mb-2">Banner Image</label>
<button
onclick="{()" > bannerInputRef.current.click()}
variant="outline"
className="w-full lg:w-3/4 bg-gray-700 text-gray-300 hover:bg-gray-600"
>
<upload classname="mr-2 h-4 w-4" /> Choose Banner
</button>
<input
id="banner"
ref="{bannerInputRef}" type="file"
accept="image/*"
onchange="{(e)" > handleImageUpload(e, setBanner)}
className="hidden"
/>
</div>
<div>
<label htmlfor="avatar" classname="block mb-2">Channel Avatar</label>
<button
onclick="{()" > avatarInputRef.current.click()}
variant="outline"
className="w-full lg:w-3/4 bg-gray-700 text-gray-300 hover:bg-gray-600"
>
<upload classname="mr-2 h-4 w-4" /> Choose Avatar
</button>
<input
id="avatar"
ref="{avatarInputRef}" type="file"
accept="image/*"
onchange="{(e)" > handleImageUpload(e, setAvatar)}
className="hidden"
/>
</div>
<div>
<label htmlfor="watermark" classname="block mb-2">Watermark</label>
<button
onclick="{()" > watermarkInputRef.current.click()}
variant="outline"
className="w-full lg:w-3/4 bg-gray-700 text-gray-300 hover:bg-gray-600"
>
<upload classname="mr-2 h-4 w-4" /> Choose Watermark
</button>
<input
id="watermark"
ref="{watermarkInputRef}" type="file"
accept="image/*"
onchange="{(e)" > handleImageUpload(e, setWatermark)}
className="hidden"
/>
</div>
<div>
<label htmlfor="channelName" classname="block mb-2">Channel Name</label>
<input
id="channelName"
value="{channelName}" onchange="{(e)" > setChannelName(e.target.value)}
placeholder="Enter channel name"
className="w-full lg:w-3/4 px-3 py-2 bg-gray-700 text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
</div>
</div>
)}
<div classname="{`${isFullScreen" ? '' : 'lg:col-span-2'} bg-gray-200 p-4 rounded-lg relative`}>
<div classname="flex justify-between items-center mb-4">
<h2 classname="text-xl font-semibold text-gray-800">Device Preview</h2>
<div classname="flex space-x-2">
<button onclick="{handleZoomOut}" variant="outline" size="icon" classname="bg-gray-300 text-gray-800 hover:bg-gray-400">
<zoomout classname="h-4 w-4" />
</button>
<button onclick="{handleZoomIn}" variant="outline" size="icon" classname="bg-gray-300 text-gray-800 hover:bg-gray-400">
<zoomin classname="h-4 w-4" />
</button>
<button onclick="{toggleFullScreen}" variant="outline" size="icon" classname="bg-gray-300 text-gray-800 hover:bg-gray-400">
{isFullScreen ? <minimize2 classname="h-4 w-4" /> : <maximize2 classname="h-4 w-4" />}
</button>
</div>
</div>
<div classname="h-px bg-gray-300 mb-4"></div>
<tabs value="{activeDevice}" onvaluechange="{setActiveDevice}" classname="w-full">
<tabslist classname="grid w-full grid-cols-4 bg-gray-300">
<tabstrigger value="mobile" classname="data-[state=active]:bg-gray-100 text-gray-800">Mobile</tabstrigger>
<tabstrigger value="tablet" classname="data-[state=active]:bg-gray-100 text-gray-800">Tablet</tabstrigger>
<tabstrigger value="desktop" classname="data-[state=active]:bg-gray-100 text-gray-800">Desktop</tabstrigger>
<tabstrigger value="hdtv" classname="data-[state=active]:bg-gray-100 text-gray-800">HD TV</tabstrigger>
</tabslist>
<tabscontent value="{activeDevice}" classname="overflow-x-auto mt-4">
<div style="{{" transform: `scale(${zoomlevel})`, transformorigin: 'top left', transition: 'transform 0.3s ease-in-out' }}>
<devicepreview device="{activeDevice}" />
</div>
</tabscontent>
</tabs>
<div classname="absolute bottom-8 left-8 w-48 h-36 bg-gray-800 rounded overflow-hidden shadow-lg border-2 border-gray-600">
<div classname="relative w-full h-full">
<div classname="absolute inset-0 bg-gradient-to-r from-blue-500 to-purple-500 animate-gradient"></div>
<img src="{watermark}" alt="Watermark Preview" classname="absolute bottom-2 right-2 w-8 h-8 opacity-75" />
</div>
</div>
</div>
</div>
</div>
</div>
)
}
This is a working Progress and I hope to add in more features and enhancements.
Hopefully this can become a fully pledge web app in a couple of days, and maybe even a mobile app in the future.
V0 uses a credit system wherein you are given a set number of message that you can send to there ai chat bot, the higher the plan you choose the more messages and the higher the priority you are in there system.
Visit there pricing are to learn more https://v0.dev/pricing