Documentation
Welcome to my documentation page. Here, you'll find reusable code snippets and explanations for various projects and technologies I work with.
My Code Library
import { TypeFetchedProduct } from '@/actions/Products'
import Image from 'next/image'
import Link from 'next/link'
import React from 'react'
export default function Product({product}:{product:TypeFetchedProduct}) {
return (
<Link href={"/"} className='flex items-center gap-3 hover:bg-blue-100 rounded-md px-4 py-2 transition-all hover:-translate-y-1 duration-500'>
<Image
src={product.imageUrl}
width={500}
height={500}
alt={product.name}
className='w-16 h-16 rounded-lg'
/>
<div>
<h2 className='text-blue-700'>{product.imageUrl}</h2>
<div className="flex items-center justify-between">
<p><span>Price:</span>${product.price}</p>
<p><span>Stock:</span>{product.stock}items</p>
</div>
</div>
</Link>
)
}
import React from 'react'
import Product from './Product'
import { TypeFetchedProduct } from '@/actions/Products'
export default function ProductList({ products }: { products: TypeFetchedProduct[] }) {
return (
<div className='space-y-3'>
{
products.map((product)=>{
return(
<Product key={product.id} product={product}/>
)
})
}
</div>
)
}
import React from 'react'
import Header from './Header'
import ProductList from './ProductList'
import ProductDetail from './ProductDetail'
import { TypeFetchedProduct } from '@/actions/Products'
export default function StorePage({receivedProducts}:{receivedProducts:TypeFetchedProduct[]}) {
return (
<div className='min-h-screen bg-gradient-to-r from-blue-600 to-blue-950 py-8 px-8'>
<div className="rounded-lg bg-blue-100 min-h-screen">
<Header/>
<main className='grid grid-cols-12 bg-gray-50 min-h-screen'>
<div className='col-span-4 pt-3'>
<ProductList products={receivedProducts}/>
</div>
<div className='col-span-8 bg-gray-100'>
<ProductDetail/>
</div>
</main>
</div>
</div>
)
}
import { getProducts } from '@/actions/Products'
import StorePage from '@/components/StorePage'
import React from 'react'
export default async function page() {
const fetchedProducts = (await getProducts()) || []
return (
<div>
{/* Show something incase there are no products */}
{
fetchedProducts && fetchedProducts.length>0?(<StorePage receivedProducts={fetchedProducts}/>):(<div><h2>No Products</h2></div>)
}
</div>
)
}
"use server"
// Then lastly we have to define the types for the data we are fetching.
//Right now it has any which is dangerous
//Defining the types for that data is so good because it is going to help us all around.
export interface TypeFetchedProduct{
id:string,
imageUrl:string,
stock:number,
name:string,
price:number,
}
const API = "https://inventory-app-ten-gilt.vercel.app/api/v1/products"
export async function getProducts(){
try {
//send a response
const response = await fetch(API)
//the result obtained, convert it into json
const result = await response.json()
//return the result which has been converted
// const fetchedProducts = result.data;
//but just above the data is too much and we don't want all that data to come just a few.
//so here we only get that particular thing we want from the data.
const fetchedProducts = result.data.map((fetchedProduct:any)=>{
return{
id:fetchedProduct.id,
imageUrl:fetchedProduct.productThumbnail,
stock:fetchedProduct.stockQty,
name:fetchedProduct.name,
price:fetchedProduct.productPrice,
}
})
return fetchedProducts as TypeFetchedProduct[]
// return result
} catch (error) {
console.log(error)
return[]
}
}
"use server"
const API = "https://inventory-app-ten-gilt.vercel.app/api/v1/products"
export async function getProducts(){
try {
//send a response
const response = await fetch(API)
//the result obtained, convert it into json
const result = await response.json()
//return the result which has been converted
return result
} catch (error) {
console.log(error)
return[]
}
}
import Image from 'next/image'
import React from 'react'
import { Bookmark } from 'lucide-react'
import { Button } from './ui/button'
export default function ProductDetail() {
return (
<div className='relative'>
<Image
src={"data:image/jpeg;base64,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"}
width={500}
height={500}
alt="image"
className='w-full h-[400px] object-cover'
/>
<h1 className="line-clamp-2 scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl absolute top-[45%] max-w-3xl bg-gradient-to-r from-blue-950 to-blue-500 left-[50%] -translate-x-1/2 text-white px-3 py-1 rounded-md">
Lenovo Thinkpad E14, Intel Core I5-1135g7, 8gb Ram, 256gb Ssd Black
</h1>
<p className='px-4 py-4'>The Lenovo ThinkPad E14 is a business-oriented laptop that combines solid performance with reliability. It features an Intel Core i5 processor, offering a good balance of speed and power efficiency for everyday tasks like office work, web browsing, and multimedia.</p>
<div className="flex py-4 px-4 w-full justify-between">
<div className="flex items-center justify-center gap-8">
<p><span className='text-blue-700'>Brand:</span>Hp</p>
<p><span className='text-blue-700'>Stock:</span>32items</p>
</div>
<div className='px-4 '>
<Button>
<Bookmark/>
Bookmark
</Button>
</div>
</div>
</div>
)
}
import Image from 'next/image'
import Link from 'next/link'
import React from 'react'
export default function Product() {
return (
<Link href={"/"} className='flex items-center gap-3 hover:bg-blue-100 rounded-md px-4 py-2 transition-all hover:-translate-y-1 duration-500'>
<Image
src={"data:image/jpeg;base64,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"}
width={500}
height={500}
alt="image"
className='w-16 h-16 rounded-lg'
/>
<div>
<h2 className='text-blue-700'>HP Spectre X360 Laptop 14-ef2017nia 9t729ea - 1TB SSD - 8GBRAM</h2>
<div className="flex items-center justify-between">
<p><span>Brand:</span>Hp</p>
<p><span>Stock:</span>32items</p>
</div>
</div>
</Link>
)
}
import React from 'react'
import Product from './Product'
export default function ProductList() {
return (
<div className='space-y-3'>
<Product/>
<Product/>
<Product/>
<Product/>
<Product/>
</div>
)
}
import React from 'react'
import Header from './Header'
import ProductList from './ProductList'
export default function StorePage() {
return (
<div className='min-h-screen bg-gradient-to-r from-blue-600 to-blue-950 py-8 px-8'>
<div className="rounded-lg bg-blue-100 min-h-screen">
<Header/>
<main className='grid grid-cols-12 bg-gray-50 min-h-screen'>
<div className='col-span-4 pt-3'>
<ProductList/>
</div>
<div className='col-span-8 bg-gray-100'>
Product detailed page
</div>
</main>
</div>
</div>
)
}
<Image
src={"data:image/jpeg;base64,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"}
width={500}
height={500}
alt="image"
className='w-56 h-56'
/>
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**',
},
],
},
};
export default nextConfig;
Eg: (Group1) In brackets -> Services(Folder)-> page.tsx , Contact(Folder)-> page.tsx , Layout.tsx
Layout.tsx
import React from 'react'
export default function GroupOnelayout({children}:{children:any}) {
return (
<div>
<h1>This is Group 1 layout.</h1>
{children}
</div>
)
}
products
page.tsx
{/* Products */}
<a href="/product/1?page=5" className="text-blue-600">Product 1</a>
[id]
page.tsx
http://localhost:3000/product/2?page=5
import React from 'react'
export default async function page({
params,
searchParams,
}: {
params: Promise<{ slug: string, id:string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const id = (await params).id
const page = (await searchParams).page
return (
<div>
<h2>This is a detailed Page.</h2>
Page - {id}
SearchParam - {page}
{/* http://localhost:3000/product/5 -> dynamic param */}
{/* http://localhost:3000/product/5?page=3 -> search param */}
</div>
)
}
This is a detailed Page.
Page - 2SearchParam - 5
import React from 'react'
export default async function page({
params,
}: {
params: Promise<{ slug: string , id:string}>
}) {
const id = (await params).id
return (
<div>
<h2>This is a detailed Page.</h2>
Page - {id}
</div>
)
}
import React from 'react'
export default function error() {
return (
<div>
You have got an error.
</div>
)
}
import React from 'react'
export default function NotFound() {
return (
<div>
This page does not exist.
</div>
)
}
'use client'
import React from 'react'
import Image from 'next/image'
import Link from 'next/link'
import { motion } from 'framer-motion'
interface Project {
title: string
description: string
image: string
link: string
}
const projects: Project[] = [
{
title: "Sefbuy",
description: "SEFBUY is an Ecommerce website designed to provide a seamless shopping experience for customers.",
image: "/project1.png?height=300&width=500",
link: "https://sefbuy.com/"
},
{
title: "Lamudi",
description: "Lamudi is a leading real estate platform connecting buyers and sellers across Uganda.",
image: "/project2.png?height=300&width=500",
link: "https://www.lamudi.co.ug/Lamudi/Index.aspx"
},
{
title: "Gaba Hope For Kids",
description: "This is a Charity Organization supporting unprivileged children with Education, Healthcare and Empowerment in Uganda.",
image: "/project3.png?height=300&width=500",
link: "https://www.gabahopeforkids.org/"
}
]
const BreathingBackground = () => (
<div className="absolute inset-0 z-0">
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="grid" width="50" height="50" patternUnits="userSpaceOnUse">
<path d="M 50 0 L 0 0 0 50" fill="none" stroke="rgba(255,255,255,0.5)" strokeWidth="1"/>
</pattern>
</defs>
<motion.rect
width="100%"
height="100%"
fill="url(#grid)"
animate={{
scale: [1, 1.05, 1],
opacity: [0.3, 0.5, 0.3],
}}
transition={{
duration: 5,
repeat: Infinity,
ease: "easeInOut"
}}
/>
</svg>
</div>
)
const AnimatedSection = motion.section
export default function LatestProjects({projectData}: {projectData: Project[]}) {
return (
<AnimatedSection className="relative overflow-hidden">
<BreathingBackground />
<div className="latest-container relative z-10">
<h2 className="text-4xl font-semibold text-center mb-4 text-gray-800 dark:text-white name-header">Latest Projects</h2>
<div className="latest-card-container">
{projectData.map((project, index) => (
<motion.div
key={index}
initial={{ opacity: 0, y: 50 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.2 }}
className="bg-white dark:bg-gray-800 rounded-xl shadow-xl overflow-hidden transform hover:scale-105 transition duration-300"
>
<div className="relative h-64 w-full image-container">
<Image
src={project.image}
alt={project.title}
layout="fill"
objectFit="cover"
className="transition-transform duration-300 hover:scale-110 inner-image"
/>
</div>
<div className="p-6">
<h3 className="text-2xl font-semibold mb-3 text-gray-800 dark:text-white">{project.title}</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">{project.description}</p>
<Link href={project.link} className="inline-block bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded transition duration-300">
View Project
</Link>
</div>
</motion.div>
))}
</div>
<div className="w-[100%] h-[10vh] mt-3 flex items-center justify-center">
<button className='bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-lg transition duration-300 text-sm'>
<Link href="/projects">
View All Projects
</Link>
</button>
</div>
</div>
</AnimatedSection>
)
}
import { fetchProject } from '@/actions/Project'
import LatestProjects from '@/components/LatestProjects'
import Link from 'next/link'
import React from 'react'
export default async function page() {
const dbProjects = await fetchProject() || []
return (
<div className='p-5 mt-[72px]'>
<div className='w-full p-3 flex'>
<Link href="/project/new" className='px-3 py-4 bg-blue-500 text-white rounded-[10px] mt-4 font-bold'>
Create New Project
</Link>
</div>
<LatestProjects projectData={dbProjects}/>
</div>
)
}
export async function fetchProject(){
try {
const fetchedProject = await db.project.findMany({
orderBy:{
createdAt:"desc"
}
})
return fetchedProject
} catch (error) {
console.log(error)
}
}
"use server"
import { ProjectProps } from "@/components/Forms/CreateNewProjectForm";
import { db } from "@/prisma/db";
import { revalidatePath } from "next/cache";
export async function createNewProject(data:ProjectProps){
try {
const createdNewProject = await db.project.create({
data
})
revalidatePath("/project")
return createdNewProject
} catch (error) {
console.log(error)
}
}
"use client";
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
import { useRouter } from "next/navigation";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import { createNewProject } from "@/actions/Project";
import Image from "next/image";
import { UploadButton } from "@/utils/uploadthing";
export type ProjectProps = {
image :string;
title: string;
description: string;
link:string;
slug: string;
}
export default function CreateNewProjectForm() {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<ProjectProps>();
const [formError, setFormError] = useState("");
const [loading, setLoading] = useState(false);
const[imageUrl,setImageUrl] = useState("/emptyImage.png")
const router = useRouter();
async function saveData(data: ProjectProps) {
data.slug = data.title.toLowerCase().split(" ").join("-");
data.image = imageUrl;
try {
setLoading(true)
await createNewProject(data)
toast.success("Project created successfully.")
router.push("/project")
router.refresh()
reset()
} catch (error) {
toast.error("Failed to create the project.")
console.log(error)
} finally {
setLoading(false)
}
}
return (
<section className="p-5 mt-[72px]">
<Card className="w-full max-w-2xl mx-auto bg-gradient-to-br from-blue-500 to-blue-900 shadow-xl">
<CardHeader className="text-white">
<CardTitle className="text-2xl font-bold text-center mb-2">New Project</CardTitle>
</CardHeader>
<CardContent className="bg-white bg-opacity-90 rounded-b-lg">
<form className="space-y-6" onSubmit={handleSubmit(saveData)}>
<div className="space-y-2">
<Label htmlFor="title" className="text-gray-700">Project Title</Label>
<Input
type="text"
id="title"
{...register("title", { required: "Title is required" })}
placeholder="Enter project title"
className="bg-white"
/>
{errors.title && (
<p className="text-sm text-red-500">{errors.title.message}</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="description" className="text-gray-700">Description</Label>
<Textarea
id="description"
rows={4}
{...register("description", {
required: "Description is required",
})}
placeholder="Enter a brief description of the project"
className="bg-white"
/>
{errors.description && (
<p className="text-sm text-red-500">{errors.description.message}</p>
)}
</div>
{formError && <p className="text-sm text-red-500">{formError}</p>}
<div className="space-y-2">
<Label htmlFor="link" className="text-gray-700">Link for your Project</Label>
<Input
type="text"
id="link"
{...register("link", { required: "Link for your project is required" })}
placeholder="Enter your Project link"
className="bg-white"
/>
{errors.title && (
<p className="text-sm text-red-500">{errors.link?.message}</p>
)}
</div>
<div className="space-y-2 ">
<Label htmlFor="title" className="text-gray-700">Project Image</Label>
<div className="w-full min-h-[40vh] bg-slate-300 rounded-[10px]">
<div className="w-full h-[30vh] flex items-center justify-center ">
<Image
src={imageUrl}
width={512}
height={512}
alt="Image name"
className="max-h-[100%] max-w-[40%]"
/>
</div>
<div className="w-full min h-[15vh] flex items-center justify-center ">
<UploadButton
endpoint="imageUploader"
onClientUploadComplete={(res) => {
// Do something with the response
console.log("Files: ", res);
setImageUrl(res[0].url)
// alert("Upload Completed");
}}
onUploadError={(error: Error) => {
// Do something with the error.
alert(`ERROR! ${error.message}`);
}}
/>
</div>
</div>
</div>
<Button
type="submit"
disabled={loading}
className="w-full bg-blue-600 hover:bg-blue-700 text-white"
>
{loading ? "Creating New Project..." : "Create New Project"}
</Button>
</form>
</CardContent>
</Card>
</section>
);
}
import CreateNewProjectForm from '@/components/Forms/CreateNewProjectForm'
import React from 'react'
export default function page() {
return (
<div>
<CreateNewProjectForm/>
</div>
)
}
Download Git -> Which gives us Gitbash, Git Graphical User Interface(GUI), Git Command Line Interface(CMD)
Commands
1. ls -> list all the items in the current directory.
2. clear -> wipes clean the entire gitbash terminal.
3. ls -l -> Gives you a fully detailed analysis of all the folders in the
current directory.
4. ls -a -> Shows any possible hidden files in the current directory.
5. mkdir -> Create a new directory eg mkdir songs, creates new folder
called songs.
6. rm -r -> Delete a directory or a folder eg rm -r songs
7. rm -rf -> Forceful delete of a directory or a folder eg rm -rf songs
8. cd -> Change the directory eg cd movies/ , change and enter the
directory or folder.
9. code . -> Open Vscode
10. touch -> Create a new file eg touch index.html
11. cat -> Gives a detailed analysis of the contents inside a file eg
cat index.html
12. rm -> delete a file eg rm index.html
13. rm -f -> forceful delete a file eg rm -f index.html
14. mv -> Renames files or folders eg mv index.html services.html, renames
index.html to services.html
15. pwd -> print current directory
16. cd.. -> Go backwards
"use client"
import React, { useState } from "react";
import Link from "next/link";
import { CodeSnippet } from "@prisma/client";
import CodeSnippetCard from "./CodeSnippet";
export default function CodeLibrary({codeData}: {codeData: CodeSnippet[]}) {
const [search, setSearch] = useState("");
const handleCopy = (code: string) => {
navigator.clipboard.writeText(code);
};
const filteredSnippets = codeData.filter((snippet) =>
snippet.title.toLowerCase().includes(search.toLowerCase())
);
return (
<div className="min-h-screen bg-blue-950 flex flex-col items-center w-full rounded-[5px]">
<h1 className="lg:text-3xl md:text-2xl sm:text-2xl text-2xl font-bold text-white mb-6 mt-6">My Code Library</h1>
{/* search bar */}
<div className="w-full p-[0.5rem] flex items-center justify-center">
<input
type="text"
placeholder="Search Code Snippets..."
value={search}
onChange={(e) => setSearch(e.target.value)}
className=" px-4 py-2 rounded-[20px] w-full max-w-3xl bg-white text-blue-950 font-bold placeholder-gray-500 focus:outline-none focus:ring focus:ring-blue-500"
/>
</div>
<div className="w-full p-[0.5rem] flex items-center justify-start">
<Link href="/new" className="bg-blue-900 mb-2 text-white border-white rounded-[10px] border-b-[1px] border-l-[1px] p-2">
<button>
<p>Create New Snippet</p>
</button>
</Link>
</div>
<div className="code-snippet-container">
{filteredSnippets.map((snippet, index) => (
<CodeSnippetCard
key={index}
title={snippet.title}
code={snippet.code}
description={snippet.description}
onCopy={() => handleCopy(snippet.code)}
/>
))}
{filteredSnippets.length === 0 && (
<p className="text-gray-500 text-center">No snippets found.</p>
)}
</div>
</div>
);
}
import CodeLibrary from '@/components/CodeLibrary'
import { fetchCode } from '../../actions/CodeSnippet'
export default async function Docs() {
const code = await fetchCode() || []
// console.log(code)
return (
<CodeLibrary codeData={code}/>
)
}
import { db } from "@/prisma/db";
export async function fetchCode(){
try {
const fetchedCode = await db.codeSnippet.findMany({
orderBy:{
createdAt:"desc"
}
})
return fetchedCode
} catch (error) {
console.log(error)
}
}
import { CodeSnippetProps } from "@/components/CreateNewCodeSnippetForm";
import { db } from "@/prisma/db";
import { revalidatePath } from "next/cache";
export async function createCode(data:CodeSnippetProps){
// console.log(data)
//We create the data to be shown in the database.
try {
const createdCode = await db.codeSnippet.create({
data
})
// console.log(createdCode)
//Then we return to be able to use this data anywhere else eg to fetch the data on the ui.
revalidatePath("/docs")
return createdCode
} catch (error) {
console.log(error)
}
}
"use client";
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
import { useRouter } from "next/navigation";
import { createCode } from "@/actions/CodeSnippet";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
export type CodeSnippetProps = {
title: string;
code: string;
description: string;
slug: string;
};
export default function CreateNewCodeSnippetForm() {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<CodeSnippetProps>();
const [formError, setFormError] = useState("");
const [loading, setLoading] = useState(false);
const router = useRouter();
async function saveData(data: CodeSnippetProps) {
data.slug = data.title.toLowerCase().split(" ").join("-");
try {
setLoading(true)
await createCode(data)
toast.success("Codesnippet created successfully.")
router.push("/docs")
router.refresh()
reset()
} catch (error) {
toast.error("Failed to create the code snippet.")
console.log(error)
} finally {
setLoading(false)
}
}
return (
<Card className="w-full max-w-2xl mx-auto bg-gradient-to-br from-blue-500 to-blue-900 shadow-xl">
<CardHeader className="text-white">
<CardTitle className="text-2xl font-bold text-center mb-2">Create New Code Snippet</CardTitle>
</CardHeader>
<CardContent className="bg-white bg-opacity-90 rounded-b-lg">
<form className="space-y-6" onSubmit={handleSubmit(saveData)}>
<div className="space-y-2">
<Label htmlFor="title" className="text-gray-700">Snippet Title</Label>
<Input
type="text"
id="title"
{...register("title", { required: "Title is required" })}
placeholder="Enter snippet title"
className="bg-white"
/>
{errors.title && (
<p className="text-sm text-red-500">{errors.title.message}</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="code" className="text-gray-700">Code</Label>
<Textarea
id="code"
rows={6}
{...register("code", { required: "Code is required" })}
placeholder="Enter your code here"
className="font-mono bg-white"
/>
{errors.code && <p className="text-sm text-red-500">{errors.code.message}</p>}
</div>
<div className="space-y-2">
<Label htmlFor="description" className="text-gray-700">Description</Label>
<Textarea
id="description"
rows={4}
{...register("description", {
required: "Description is required",
})}
placeholder="Enter a brief description of the code snippet"
className="bg-white"
/>
{errors.description && (
<p className="text-sm text-red-500">{errors.description.message}</p>
)}
</div>
{formError && <p className="text-sm text-red-500">{formError}</p>}
<Button
type="submit"
disabled={loading}
className="w-full bg-blue-600 hover:bg-blue-700 text-white"
>
{loading ? "Creating Snippet..." : "Create Code Snippet"}
</Button>
</form>
</CardContent>
</Card>
);
}
"scripts": {
"postinstall": "prisma generate",
"preview": "next build && next start"
}
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
model CodeSnippet {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
code String
description String
slug String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
import { PrismaClient } from "@prisma/client";
declare global {
var prisma: PrismaClient | undefined;
}
export const db = globalThis.prisma || new PrismaClient();
if (process.env.NODE_ENV !== "production") globalThis.prisma = db;
DATABASE_URL="mongodb+srv://clancyro1789:VD62uLe4VVYZeTsr@cluster0.7rqx7.mongodb.net/(any new db name)"