├── .env.example ├── .eslintrc.json ├── .gitignore ├── README.md ├── actions └── subscibers.ts ├── app ├── [...slug] │ └── page.tsx ├── api │ ├── guess │ │ └── route.ts │ ├── hello │ │ └── route.ts │ ├── increment │ │ └── route.ts │ └── subscribed │ │ └── route.ts ├── dx │ └── page.tsx ├── favicon.ico ├── globals.css ├── layout.tsx ├── page.tsx └── posts │ ├── [...slug] │ └── page.tsx │ └── page.tsx ├── components.json ├── components ├── analytics.tsx ├── animated-tooltip.tsx ├── bg-dx.tsx ├── callout.tsx ├── dx-header.tsx ├── form-intake.tsx ├── hacky-button.tsx ├── hero-section │ └── index.tsx ├── icons.tsx ├── join-section.tsx ├── lamp.tsx ├── mdx-card.tsx ├── mdx-components.tsx ├── mdx-tabs.tsx ├── mode-toggle.tsx ├── particles.tsx ├── scrollablepic.tsx ├── theme-provider.tsx ├── trendy.tsx ├── ui │ ├── Spotlight.tsx │ ├── background-beam.tsx │ ├── bg-box.tsx │ ├── blog-header.tsx │ ├── border-btn.tsx │ ├── button-std.tsx │ ├── button.tsx │ ├── card-binary-view.tsx │ ├── card-binary.tsx │ ├── feeder.tsx │ ├── floating-navbar.tsx │ ├── input.tsx │ ├── label.tsx │ ├── nav-menu.tsx │ ├── scollablepicview.tsx │ ├── separator.tsx │ ├── static-nav.tsx │ ├── tabs.tsx │ ├── text-gen.tsx │ ├── toast.tsx │ ├── toaster.tsx │ ├── twickled-line.tsx │ ├── twickled-view.tsx │ └── use-toast.ts └── views.tsx ├── content ├── authors │ └── kinfish.mdx ├── pages │ └── about.mdx └── posts │ ├── ai-in-startup.mdx │ ├── hacking-meeting.mdx │ ├── is-bun-dropin-replacement.mdx │ ├── my-interview-xp.mdx │ ├── rsc-mental-models-and-new-react-era.mdx │ └── top-frontend-toos-for-shipping-amazing-web.mdx ├── contentlayer.config.js ├── db ├── actions │ ├── index.ts │ └── save.ts ├── index.tsx ├── migrations │ ├── 0000_dear_squirrel_girl.sql │ └── meta │ │ ├── 0000_snapshot.json │ │ └── _journal.json └── schema.ts ├── drizzle.config.ts ├── lib ├── email-helper.ts ├── locals.ts ├── mdx-helper.ts ├── useMouse.tsx └── utils.ts ├── next.config.js ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public ├── assets │ └── fonts │ │ ├── CalSans-SemiBold.ttf │ │ ├── cd-semi.otf │ │ ├── jakarta.ttf │ │ └── product-font.ttf ├── blog-post-1.jpg ├── blog-post-2.jpg ├── blog-post-3.jpg ├── blog-post-4.jpg ├── images │ ├── blogs │ │ ├── ace.png │ │ ├── ai-2.png │ │ ├── ai.jpg │ │ ├── bun.png │ │ ├── daisy.png │ │ ├── flowbite.png │ │ ├── hacking-meeting.webp │ │ ├── hover.png │ │ ├── hyper.png │ │ ├── interview.webp │ │ ├── nextui.jpg │ │ ├── park-ui.png │ │ ├── preline.png │ │ ├── react.webp │ │ ├── shadcn.png │ │ ├── tailwindui.png │ │ ├── v0.png │ │ ├── xp.jpeg │ │ └── zoom1.jpg │ └── kinfe.jpeg ├── next.svg └── vercel.svg ├── site └── nav.tsx ├── tailwind.config.js ├── tsconfig.json └── turbo.json /.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL=postgres://postgres.[PROJECT_ID]:[YOUR-PASSWORD]@aws-0-us-west-1.pooler.supabase.com:5432/postgres 2 | UPSTASH_REDIS_REST_URL="https://us1-.....upstash.io" 3 | UPSTASH_REDIS_REST_TOKEN="" 4 | 5 | # A credentials for nodemailer from email and email password that you can generate from - https://myaccount.google.com/u/{your_google_id}/apppasswords 6 | USER_EMAIL='' 7 | EMAIL_PASSWORD='' 8 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | 9 | .vscode 10 | # testing 11 | /coverage 12 | 13 | # next.js 14 | /.next/ 15 | /out/ 16 | 17 | # production 18 | /build 19 | 20 | # misc 21 | .DS_Store 22 | *.pem 23 | 24 | # debug 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | # local env files 30 | .env*.local 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | .contentlayer 39 | 40 | 41 | .env 42 | .turbo 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KINFiSH lacks dumping 2 | 3 | All in one! 4 | 5 | 6 | 7 | ## Tech Stack 8 | 9 | - **Framework:** [Next.js](https://nextjs.org) 10 | - **Styling:** [Tailwind CSS](https://tailwindcss.com) 11 | - **User Management:** [Clerk](https://clerk.com) 12 | - **ORM:** [Drizzle ORM](https://orm.drizzle.team) 13 | - **UI Components:** [shadcn/ui](https://ui.shadcn.com) 14 | - **Email:** [React Email](https://react.email) 15 | - **Content Management:** [Contentlayer](https://www.contentlayer.dev) 16 | - **File Uploads:** [uploadthing](https://uploadthing.com) 17 | ## Running Locally 18 | 19 | 1. Clone the repository 20 | 21 | ```bash 22 | git clone https://github.com/Kinfe123/kinfish-dumpy.git 23 | ``` 24 | 25 | 2. Change the dir 26 | 27 | ```bash 28 | cd kinfish-dumpy 29 | ``` 30 | 31 | 3. Install dependencies using pnpm 32 | 33 | ```bash 34 | pnpm install 35 | ``` 36 | 37 | 4. Copy the `.env.example` to `.env` and update the variables. 38 | 39 | ```bash 40 | cp .env.example .env 41 | ``` 42 | 43 | 5. Start the development server 44 | 45 | ```bash 46 | pnpm run dev 47 | ``` 48 | 49 | 50 | 51 | ## How do I deploy this? 52 | 53 | Follow the deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information. 54 | 55 | ## Contributing 56 | 57 | Contributions are welcome! Please open an issue if you have any questions or suggestions. Your contributions will be acknowledged. See the [contributing guide](./CONTRIBUTING.md) for more information. 58 | 59 | That's why this existed but i am using turbo just in case :) 60 | -------------------------------------------------------------------------------- /actions/subscibers.ts: -------------------------------------------------------------------------------- 1 | "use server"; 2 | 3 | import { db } from "@/db"; 4 | import { subscribers } from "@/db/schema"; 5 | 6 | export async function getSubscriberEmals() { 7 | const req = await db.select().from(subscribers); 8 | const subEmails = req.map((r) => r.email) 9 | 10 | return subEmails; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /app/[...slug]/page.tsx: -------------------------------------------------------------------------------- 1 | import { notFound } from "next/navigation" 2 | import { Metadata } from "next" 3 | import { allPages } from "contentlayer/generated" 4 | 5 | import { Mdx } from "@/components/mdx-components" 6 | 7 | interface PageProps { 8 | params: { 9 | slug: string[] 10 | } 11 | } 12 | 13 | async function getPageFromParams(params: PageProps["params"]) { 14 | const slug = params?.slug?.join("/") 15 | const page = allPages.find((page) => page.slugAsParams === slug) 16 | 17 | if (!page) { 18 | null 19 | } 20 | 21 | return page 22 | } 23 | 24 | export async function generateMetadata({ 25 | params, 26 | }: PageProps): Promise { 27 | const page = await getPageFromParams(params) 28 | 29 | if (!page) { 30 | return {} 31 | } 32 | 33 | return { 34 | title: page.title, 35 | description: page.description, 36 | } 37 | } 38 | 39 | export async function generateStaticParams(): Promise { 40 | return allPages.map((page) => ({ 41 | slug: page.slugAsParams.split("/"), 42 | })) 43 | } 44 | 45 | export default async function PagePage({ params }: PageProps) { 46 | const page = await getPageFromParams(params) 47 | 48 | if (!page) { 49 | notFound() 50 | } 51 | 52 | return ( 53 |
54 |

{page.title}

55 | {page.description &&

{page.description}

} 56 |
57 | 58 |
59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /app/api/guess/route.ts: -------------------------------------------------------------------------------- 1 | import { db } from "@/db" 2 | import { guesser } from "@/db/schema" 3 | export async function POST(req: Request) { 4 | 5 | const body = await req.json() 6 | const {name , phone , guess} = body 7 | if(name && phone && guess) { 8 | const req = await db.insert(guesser).values({name: name , phone:phone , guess:guess}) 9 | console.log(req , ' the req') 10 | 11 | return new Response('Succesfully guessed' , {status:200}) 12 | 13 | }else { 14 | return new Response('Please provide a valid data' ,{status:404}) 15 | } 16 | } -------------------------------------------------------------------------------- /app/api/hello/route.ts: -------------------------------------------------------------------------------- 1 | export async function GET(request: Request) { 2 | return new Response('Hello, Next.js!') 3 | } 4 | -------------------------------------------------------------------------------- /app/api/increment/route.ts: -------------------------------------------------------------------------------- 1 | import { Redis } from "@upstash/redis"; 2 | 3 | export var config = { 4 | runtime: "edge", 5 | }; 6 | const redis = Redis.fromEnv(); 7 | export async function POST(req: Request) { 8 | const body = await req.json(); 9 | const { slug } = body; 10 | if (!slug) { 11 | return new Response("Slug is not provided", { status: 404 }); 12 | } 13 | const ip = req.headers.get("x-forwarded-for") ?? ""; 14 | const buf = await crypto.subtle.digest( 15 | "SHA-256", 16 | new TextEncoder().encode(ip) 17 | ); 18 | const hash = Array.from(new Uint8Array(buf)) 19 | .map((b) => b.toString(16).padStart(2, "0")) 20 | .join(""); 21 | 22 | const isNew = await redis.set(["deduplicate", hash, slug].join(":"), true, { 23 | nx: true, 24 | ex: 24 * 60 * 60, 25 | }); 26 | if(!isNew){ 27 | return new Response('User has already viewed the page' , {status:202}) 28 | } 29 | const res = await redis.incr(["pageviews", "projects", slug].join(":")); 30 | console.log('The number is : ' , res) 31 | return new Response('The user has successfully added to the viewer list', {status: 200}) 32 | 33 | } 34 | 35 | // export async function GET(req: Request) {} 36 | -------------------------------------------------------------------------------- /app/api/subscribed/route.ts: -------------------------------------------------------------------------------- 1 | import { getSubscriberEmals } from "@/actions/subscibers"; 2 | import { db } from "@/db"; 3 | import { subscribers } from "@/db/schema"; 4 | import { transporter } from "@/lib/email-helper"; 5 | 6 | export async function POST(req: Request) { 7 | try { 8 | const { email } = await req.json(); 9 | 10 | const result = await getSubscriberEmals(); 11 | if (result.includes(email)) { 12 | return new Response("duplicate", { status: 400 }); 13 | } else if (email) { 14 | const req = await db.insert(subscribers).values({ email: email }); 15 | try { 16 | const req2 = await transporter.sendMail({ 17 | from: `KinfeMichael Tariku <${process.env.USER_EMAIL}>`, 18 | to: email, 19 | subject: "Thanks for showing your interest for joining the gang", 20 | text: "Hello there , KinfeMichael here - Thanks for joining the farmer gang , I will keep in touch with you for an updates!... Stay Safe", 21 | }); 22 | const req3 = await transporter.sendMail({ 23 | from: `KinfeMichael Tariku <${process.env.USER_EMAIL}>`, 24 | to: process.env.ADMIN_EMAIL, 25 | subject: "Hey Farmer , We have received a s subsciption email", 26 | text: `Hello there , KinfeMichael here - We have received a new subsciption from email - ${email}`, 27 | }); 28 | return new Response("Everything went fine", { status: 200 }); 29 | } catch (err) { 30 | console.log("The error is ", err); 31 | } 32 | 33 | return new Response("Successfully Subscribed", { status: 200 }); 34 | } else { 35 | return new Response("Please make sure to pass an input", { status: 400 }); 36 | } 37 | } catch (err) { 38 | return new Response("Please try again with valid input", { status: 404 }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/dx/page.tsx: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import DxHeader from "@/components/dx-header"; 3 | import Particles from "@/components/particles"; 4 | import { extractFromLink } from "md-to-jsonify"; 5 | 6 | export const metadata = { 7 | title: "Dx Matters", 8 | }; 9 | const DxPage = async () => { 10 | // const url = 11 | // "https://api.github.com/repos/workos/awesome-developer-experience/git/blobs/fe28415d2d46ac325a12df8292f7cc005aef57ce"; 12 | 13 | // const res = await extractFromLink(url); 14 | // console.log(res); 15 | return ( 16 |
17 | 18 | 19 | 20 |
21 | ); 22 | }; 23 | 24 | export default DxPage; 25 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kinfe123/kinfish-dumpy/d98ecaa67b879c44e5c765eda0b73fe08d067910/app/favicon.ico -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 0 0% 100%; 8 | --foreground: 222.2 84% 4.9%; 9 | 10 | --card: 0 0% 100%; 11 | --card-foreground: 222.2 84% 4.9%; 12 | 13 | --popover: 0 0% 100%; 14 | --popover-foreground: 222.2 84% 4.9%; 15 | 16 | --primary: 222.2 47.4% 11.2%; 17 | --primary-foreground: 210 40% 98%; 18 | 19 | --secondary: 210 40% 96.1%; 20 | --secondary-foreground: 222.2 47.4% 11.2%; 21 | 22 | --muted: 210 40% 96.1%; 23 | --muted-foreground: 215.4 16.3% 46.9%; 24 | 25 | --accent: 210 40% 96.1%; 26 | --accent-foreground: 222.2 47.4% 11.2%; 27 | 28 | --destructive: 0 84.2% 60.2%; 29 | --destructive-foreground: 210 40% 98%; 30 | 31 | --border: 214.3 31.8% 91.4%; 32 | --input: 214.3 31.8% 91.4%; 33 | --ring: 222.2 84% 4.9%; 34 | 35 | --radius: 0.5rem; 36 | } 37 | 38 | .dark { 39 | --background: 222.2 84% 4.9%; 40 | --foreground: 210 40% 98%; 41 | 42 | --card: 222.2 84% 4.9%; 43 | --card-foreground: 210 40% 98%; 44 | 45 | --popover: 222.2 84% 4.9%; 46 | --popover-foreground: 210 40% 98%; 47 | 48 | --primary: 210 40% 98%; 49 | --primary-foreground: 222.2 47.4% 11.2%; 50 | 51 | --secondary: 217.2 32.6% 17.5%; 52 | --secondary-foreground: 210 40% 98%; 53 | 54 | --muted: 217.2 32.6% 17.5%; 55 | --muted-foreground: 215 20.2% 65.1%; 56 | 57 | --accent: 217.2 32.6% 17.5%; 58 | --accent-foreground: 210 40% 98%; 59 | 60 | --destructive: 0 62.8% 30.6%; 61 | --destructive-foreground: 210 40% 98%; 62 | 63 | --border: 217.2 32.6% 17.5%; 64 | --input: 217.2 32.6% 17.5%; 65 | --ring: 212.7 26.8% 83.9%; 66 | } 67 | } 68 | 69 | @layer base { 70 | * { 71 | @apply border-border; 72 | } 73 | body { 74 | @apply bg-background text-foreground; 75 | } 76 | } -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import "./globals.css"; 2 | import { Inter } from "next/font/google"; 3 | import { ThemeProvider } from "@/components/theme-provider"; 4 | import { Analytics } from "@/components/analytics"; 5 | import localFont from "next/font/local"; 6 | import { navItems } from "@/site/nav"; 7 | import FloatingNav from "@/components/ui/floating-navbar"; 8 | import { Toaster } from "@/components/ui/toaster"; 9 | const inter = Inter({ subsets: ["latin"] }); 10 | 11 | export const metadata = { 12 | title: "KiNFiSH - Dumps all over the internet", 13 | description: "a place where farms comes to reality", 14 | }; 15 | 16 | const fontHeading = localFont({ 17 | src: "../public/assets/fonts/CalSans-SemiBold.ttf", 18 | variable: "--font-heading", 19 | }); 20 | const fontHeadingAlt = localFont({ 21 | src: "../public/assets/fonts/cd-semi.otf", 22 | variable: "--font-headingAlt", 23 | }); 24 | 25 | const fontSubHeading = localFont({ 26 | src: "../public/assets/fonts/product-font.ttf", 27 | variable: "--font-subheading", 28 | }); 29 | const fontSubAlt = localFont({ 30 | src: "../public/assets/fonts/jakarta.ttf", 31 | variable: "--font-subalt", 32 | }); 33 | 34 | interface RootLayoutProps { 35 | children: React.ReactNode; 36 | } 37 | 38 | export default function RootLayout({ children }: RootLayoutProps) { 39 | return ( 40 | 41 |
42 | 43 | 48 |
49 |
50 | 51 |
52 |
53 | 54 | 55 |
56 |
{children}
57 |
58 | 59 | 60 |
61 | 62 |
63 | 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | 2 | import HeroSection from "@/components/hero-section"; 3 | import Lamper from "@/components/lamp"; 4 | import Trendy from "@/components/trendy"; 5 | import { BackgroundBeamsDemo } from "@/components/ui/background-beam"; 6 | 7 | 8 | export default function Home() { 9 | return ( 10 |
11 |
12 | 13 | 14 |
15 | 16 |
17 |
18 | 19 |
20 |
21 | 22 |
23 | 24 | {/* */} 25 |
26 |
27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /app/posts/[...slug]/page.tsx: -------------------------------------------------------------------------------- 1 | import { notFound } from "next/navigation"; 2 | import { allAuthors, allPosts } from "contentlayer/generated"; 3 | 4 | import { Metadata } from "next"; 5 | import { Mdx } from "@/components/mdx-components"; 6 | import { ChevronLeft, ChevronLeftCircle, EyeIcon, View } from "lucide-react"; 7 | import Link from "next/link"; 8 | import { cn, formatDate } from "@/lib/utils"; 9 | import { buttonVariants } from "@/components/ui/button"; 10 | import Image from "next/image"; 11 | import Views from "@/components/views"; 12 | import { Redis } from "@upstash/redis"; 13 | import { AnimatedTooltip } from "@/components/animated-tooltip"; 14 | 15 | const redis = Redis.fromEnv(); 16 | interface PostProps { 17 | params: { 18 | slug: string[]; 19 | }; 20 | } 21 | 22 | interface AuthorProps { 23 | id: string; 24 | name: string; 25 | designation: string; 26 | image: string; 27 | } 28 | 29 | export const revalidate = 30; 30 | 31 | async function getPostFromParams(params: PostProps["params"]) { 32 | const slug = params?.slug?.join("/"); 33 | const post = allPosts.find((post) => post.slugAsParams === slug); 34 | 35 | if (!post) { 36 | null; 37 | } 38 | 39 | return post; 40 | } 41 | 42 | export async function generateMetadata({ 43 | params, 44 | }: PostProps): Promise { 45 | const post = await getPostFromParams(params); 46 | 47 | if (!post) { 48 | return {}; 49 | } 50 | const { title, image, description, slug } = post; 51 | return { 52 | title: post.title, 53 | description: post.description, 54 | openGraph: { 55 | title: `${title} - KiNFiSH Blog`, 56 | description, 57 | type: "article", 58 | url: `https://kinfish-dumpy.vercel.app/posts/${slug}`, 59 | images: [ 60 | { 61 | url: image, 62 | }, 63 | ], 64 | }, 65 | twitter: { 66 | card: "summary_large_image", 67 | title, 68 | description, 69 | images: [image], 70 | }, 71 | }; 72 | } 73 | 74 | export default async function PostPage({ params }: PostProps) { 75 | const post = await getPostFromParams(params); 76 | const authors = post!.authors.map((author) => 77 | allAuthors.find(({ slug }) => slug === `/authors/${author}`) 78 | ); 79 | 80 | if (!post) { 81 | notFound(); 82 | } 83 | const views = 84 | (await redis.get(["pageviews", "projects", post.slug].join(":"))) ?? 85 | 0; 86 | 87 | const parseData = () => { 88 | let res: AuthorProps[] = []; 89 | 90 | if (authors) { 91 | authors.map((a) => { 92 | let user = { 93 | id: a!._id ?? "", 94 | name: a!.name ?? "", 95 | designation: a!.description ?? "", 96 | image: a!.avatar ?? "", 97 | }; 98 | res.push(user); 99 | }); 100 | } 101 | return res; 102 | }; 103 | const authorFormat = parseData(); 104 | 105 | return ( 106 |
107 | 108 | 109 |
110 |
111 |
112 |
113 | {/*
*/} 114 |
115 |
116 | 117 |
118 |
119 | {post.date && ( 120 | 127 | )} 128 |

129 | {post.title} 130 |

131 |

{post.description}

132 |
133 | 134 | {authors?.length ? ( 135 |
136 | {authors.map((author) => 137 | author ? ( 138 |
142 | 143 | 148 | 149 |
150 |
151 |

{author.name}

152 |

153 | @{author.twitter} 154 |

155 |
156 | 157 | 158 |
159 | 166 | 167 | See all posts 168 | 169 |
170 |
171 | ) : null 172 | )} 173 |
174 | ) : null} 175 |
176 |
177 | {post.image && ( 178 |
179 | {/* {post.title} */} 187 |
188 | )} 189 | 190 |
191 | 192 | {/*
193 | 194 |
*/} 195 |
196 | 203 | 204 | See all posts 205 | 206 |
207 |
208 | 214 |

Found a typo? Edit this page →

215 | 216 |
217 |
218 |
219 | ); 220 | } 221 | -------------------------------------------------------------------------------- /app/posts/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import Link from "next/link"; 3 | import { allPosts } from "contentlayer/generated"; 4 | import { compareDesc } from "date-fns"; 5 | 6 | import { PostCard } from "@/components/ui/card-binary-view"; 7 | import Spotlight from "@/components/ui/Spotlight"; 8 | import BlogHeader from "@/components/ui/blog-header"; 9 | import { Redis } from "@upstash/redis"; 10 | import { sumNums } from "@/lib/utils"; 11 | import { getViewCount } from "../../lib/mdx-helper"; 12 | 13 | const redis = Redis.fromEnv(); 14 | 15 | export const metadata = { 16 | title: "Blog", 17 | }; 18 | 19 | export default async function BlogPage() { 20 | const posts = allPosts 21 | .filter((post) => post.date) 22 | .sort((a, b) => { 23 | return compareDesc(new Date(a.date), new Date(b.date)); 24 | }); 25 | 26 | const summed = await getViewCount() 27 | 28 | 29 | 30 | 31 | return ( 32 |
33 |
34 | 35 |
36 |
37 | {/*
38 |

39 | What i thought 40 |

41 |

42 | Homemade thought and farms - all the magic 43 |

44 |
*/} 45 | 46 |
47 | 48 |
49 | {posts?.length ? ( 50 |
51 | {posts.map((post, index) => ( 52 | 59 | ))} 60 |
61 | ) : ( 62 |

No posts published.

63 | )} 64 |
65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /components/analytics.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { Analytics as VercelAnalytics } from "@vercel/analytics/react" 4 | 5 | export function Analytics() { 6 | return 7 | } 8 | -------------------------------------------------------------------------------- /components/animated-tooltip.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import Image from "next/image"; 3 | import React, { useState } from "react"; 4 | import { 5 | motion, 6 | useTransform, 7 | AnimatePresence, 8 | useMotionValue, 9 | useSpring, 10 | } from "framer-motion"; 11 | 12 | export const AnimatedTooltip = ({ 13 | items, 14 | }: { 15 | items: { 16 | id: number | string; 17 | name: string; 18 | designation: string; 19 | image: string; 20 | }[]; 21 | }) => { 22 | const [hoveredIndex, setHoveredIndex] = useState(null); 23 | const springConfig = { stiffness: 100, damping: 5 }; 24 | const x = useMotionValue(0); // going to set this value on mouse move 25 | // rotate the tooltip 26 | const rotate = useSpring( 27 | useTransform(x, [-100, 100], [-45, 45]), 28 | springConfig 29 | ); 30 | // translate the tooltip 31 | const translateX = useSpring( 32 | useTransform(x, [-100, 100], [-50, 50]), 33 | springConfig 34 | ); 35 | const handleMouseMove = (event: any) => { 36 | const halfWidth = event.target.offsetWidth / 2; 37 | x.set(event.nativeEvent.offsetX - halfWidth); // set the x value, which is then used in transform and rotate 38 | }; 39 | 40 | return ( 41 | <> 42 | {items.map((item, idx) => ( 43 |
setHoveredIndex(item.id)} 48 | onMouseLeave={() => setHoveredIndex(null)} 49 | > 50 | 51 | {hoveredIndex === item.id && ( 52 | 72 |
73 |
74 |
75 | {item.name} 76 |
77 |
{item.designation}
78 | 79 | )} 80 | 81 | {item.name} 89 |
90 | ))} 91 | 92 | ); 93 | }; 94 | -------------------------------------------------------------------------------- /components/bg-dx.tsx: -------------------------------------------------------------------------------- 1 | const ButtonShadowGradient = () => { 2 | return ( 3 | 7 | ); 8 | }; 9 | 10 | export default ButtonShadowGradient; 11 | -------------------------------------------------------------------------------- /components/callout.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | 3 | interface CalloutProps { 4 | icon?: string; 5 | children?: React.ReactNode; 6 | type?: "default" | "warning" | "danger"; 7 | } 8 | 9 | export function Callout({ children, icon, type = "default", ...props }: CalloutProps) { 10 | return ( 11 |
18 | {icon && {icon}} 19 |
{children}
20 |
21 | ); 22 | } -------------------------------------------------------------------------------- /components/dx-header.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useRef } from "react"; 4 | import Spotlight from "./ui/Spotlight"; 5 | import { motion, useInView } from "framer-motion"; 6 | import Particles from "./particles"; 7 | import ButtonShadowGradient from "./bg-dx"; 8 | const DxHeader = () => { 9 | const FADE_DOWN_ANIMATION_VARIANTS = { 10 | hidden: { opacity: 0, y: -10 }, 11 | show: { opacity: 1, y: 0, transition: { type: "spring" } }, 12 | }; 13 | const ref = useRef(null); 14 | const isInView = useInView(ref); 15 | return ( 16 |
17 |
18 | {/* */} 19 |
20 |
21 | 22 | {/* Radial gradient for the container to give a faded look */} 23 |
24 | 39 |
40 | 41 | 42 | 43 | 44 |
45 | 49 | We really care about{" "} 50 | 51 | DX 52 | 53 | 54 | 55 | 56 | {/* */} 57 | 58 |
59 |
60 |
61 | ); 62 | }; 63 | export default DxHeader; 64 | -------------------------------------------------------------------------------- /components/form-intake.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useState } from "react"; 4 | import { Input } from "@/components/ui/input"; 5 | import { Label } from "@/components/ui/label"; 6 | 7 | // import Background from "../grid-background/background" 8 | import { Icons } from "./icons"; 9 | import { toast } from "@/components/ui/use-toast"; 10 | 11 | export default function FormContact() { 12 | const [name, setName] = useState(""); 13 | const [phone, setPhone] = useState(""); 14 | const [loading, setLoading] = useState(false); 15 | const [guess, setGuess] = useState(""); 16 | // const {toast} = useToast() 17 | 18 | const handleClick = async (e: any) => { 19 | e.preventDefault(); 20 | setLoading(true); 21 | const res = await fetch("/api/guess", { 22 | method: "POST", 23 | body: JSON.stringify({ 24 | name: name, 25 | phone: phone, 26 | guess: guess, 27 | }), 28 | }); 29 | setLoading(false); 30 | if (!res.ok) { 31 | return toast({ 32 | title: "Something went wrong.", 33 | description: "I can't receive your guess. Please try again.", 34 | variant: "destructive", 35 | }); 36 | } else { 37 | 38 | return toast({ 39 | title: "Successfully Sent", 40 | description: `Thanks ${name} for your guess. I will reach out and get back to you if that is a good guess! `, 41 | variant: "default", 42 | }); 43 | } 44 | 45 | // we will be having two calls - 1 for email and 2 for form acceptance or we can merge them together to be deleived as one 46 | }; 47 | 48 | 49 | return ( 50 |
51 | {/* */} 52 | 53 |
54 |
55 | {/*

56 | Contact{" "} 57 | 58 | Us 59 | 60 |

*/} 61 |
65 |
66 | 67 | setName(e.target.value)} 72 | placeholder="Your Telegram username..." 73 | required 74 | /> 75 |
76 |
77 | 78 | setPhone(e.target.value)} 82 | value={phone} 83 | placeholder="Your phone number.." 84 | // type="email" 85 | required 86 | /> 87 |
88 |
89 | 90 | setGuess(e.target.value)} 94 | value={guess} 95 | placeholder="Guess ...." 96 | type="guess" 97 | required 98 | /> 99 |
100 | 101 | 114 |
115 |
116 |
117 |
118 | ); 119 | } 120 | -------------------------------------------------------------------------------- /components/hacky-button.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useRef, useState } from "react"; 4 | // import { FiLock } from "react-icons/fi"; 5 | import {Lock} from 'lucide-react' 6 | import { motion } from "framer-motion"; 7 | 8 | const HackyButton = ({text}: {text:string}) => { 9 | return ( 10 |
11 | 12 |
13 | ); 14 | }; 15 | 16 | const CYCLES_PER_LETTER = 2; 17 | const SHUFFLE_TIME = 50; 18 | 19 | const CHARS = "!@#$%^&*():{};|,.<>/?"; 20 | 21 | 22 | type wordProps = { 23 | word: string 24 | } 25 | export const EncryptButton = (props: wordProps) => { 26 | const TARGET_TEXT = props.word; 27 | const intervalRef = useRef(null); 28 | 29 | const [text, setText] = useState(TARGET_TEXT); 30 | 31 | const scramble = () => { 32 | let pos = 0; 33 | // @ts-ignore 34 | intervalRef.current = setInterval(() => { 35 | const scrambled = TARGET_TEXT.split("") 36 | .map((char, index) => { 37 | if (pos / CYCLES_PER_LETTER > index) { 38 | return char; 39 | } 40 | 41 | const randomCharIndex = Math.floor(Math.random() * CHARS.length); 42 | const randomChar = CHARS[randomCharIndex]; 43 | 44 | return randomChar; 45 | }) 46 | .join(""); 47 | 48 | setText(scrambled); 49 | pos++; 50 | 51 | if (pos >= TARGET_TEXT.length * CYCLES_PER_LETTER) { 52 | stopScramble(); 53 | } 54 | }, SHUFFLE_TIME); 55 | }; 56 | 57 | const stopScramble = () => { 58 | clearInterval(intervalRef.current || undefined); 59 | 60 | setText(TARGET_TEXT); 61 | }; 62 | 63 | return ( 64 | 75 |
76 | 77 | {text} 78 |
79 | 94 |
95 | ); 96 | }; 97 | 98 | export default HackyButton; -------------------------------------------------------------------------------- /components/hero-section/index.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { AnimatePresence, motion, useInView } from "framer-motion"; 4 | import Image from "next/image"; 5 | import Link from "next/link"; 6 | import React from "react"; 7 | import { Button } from "../ui/button"; 8 | import Feeder from "../ui/feeder"; 9 | import Spotlight from "../ui/Spotlight"; 10 | import { Github } from "lucide-react"; 11 | 12 | export default function HeroSection() { 13 | const ref = React.useRef(null); 14 | const isInView = useInView(ref); 15 | 16 | const FADE_DOWN_ANIMATION_VARIANTS = { 17 | hidden: { opacity: 0, y: -10 }, 18 | show: { opacity: 1, y: 0, transition: { type: "spring" } }, 19 | }; 20 | return ( 21 |
22 |
23 | 24 |
25 |
26 | 40 |
41 |
42 |
43 |
44 |
45 |
46 | 47 | 51 | 52 |
53 | Beautifully made thoughts 54 |
55 | 59 | A collection of handmade and crafted thought from KiNFiSH 60 | 61 | 62 | 66 | 67 | 68 | 69 | 70 | 75 | 82 | 83 | 84 | 85 |
86 |
87 | 93 | 94 | 100 | 101 | 102 |
103 |
104 | ); 105 | } 106 | -------------------------------------------------------------------------------- /components/icons.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | AlertTriangle, 3 | ArrowRight, 4 | Check, 5 | ChevronLeft, 6 | ChevronRight, 7 | Command, 8 | CreditCard, 9 | File, 10 | FileText, 11 | HelpCircle, 12 | Image, 13 | Laptop, 14 | Loader2, 15 | LucideProps, 16 | Moon, 17 | MoreVertical, 18 | Pizza, 19 | Plus, 20 | Settings, 21 | SunMedium, 22 | Trash, 23 | Twitter, 24 | User, 25 | X, 26 | // @ts-ignore 27 | type Icon as LucideIcon, 28 | } from "lucide-react" 29 | 30 | export type Icon = LucideIcon 31 | 32 | export const Icons = { 33 | logo: Command, 34 | close: X, 35 | spinner: Loader2, 36 | chevronLeft: ChevronLeft, 37 | chevronRight: ChevronRight, 38 | trash: Trash, 39 | post: FileText, 40 | page: File, 41 | media: Image, 42 | settings: Settings, 43 | billing: CreditCard, 44 | ellipsis: MoreVertical, 45 | add: Plus, 46 | warning: AlertTriangle, 47 | user: User, 48 | arrowRight: ArrowRight, 49 | help: HelpCircle, 50 | pizza: Pizza, 51 | sun: SunMedium, 52 | moon: Moon, 53 | laptop: Laptop, 54 | gitHub: ({ ...props }: LucideProps) => ( 55 | 70 | ), 71 | twitter: Twitter, 72 | check: Check, 73 | } -------------------------------------------------------------------------------- /components/join-section.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | import { BackgroundBeams } from "@/components/ui/background-beam"; 4 | import BorderBtn from "./ui/border-btn"; 5 | import { BoxesCore } from "./ui/bg-box"; 6 | 7 | export function BackgroundBeamsDemo() { 8 | return ( 9 |
10 | {/* */} 11 |
12 |

13 | Join the Jema 14 |

15 |

16 |

17 | Welcome to MailJet, the best transactional email service on the web. 18 | We provide reliable, scalable, and customizable email solutions for 19 | your business. Whether you're sending order confirmations, 20 | password reset emails, or promotional campaigns, MailJet has got you 21 | covered. 22 |

23 | 28 | 29 | 30 |
31 | 32 |
33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /components/lamp.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import React from "react"; 4 | import { motion } from "framer-motion"; 5 | import { cn } from "@/lib/utils"; 6 | export default function Lamper() { 7 | return ( 8 | 9 | 19 | Thoughts speaks
on blogs 20 |
21 |
22 | ); 23 | } 24 | 25 | export const LampContainer = ({ 26 | children, 27 | className, 28 | }: { 29 | children: React.ReactNode; 30 | className?: string; 31 | }) => { 32 | return ( 33 |
39 |
40 | 53 |
54 |
55 | 56 | 69 |
70 |
71 | 72 |
73 |
74 |
75 | 85 | 95 | 96 |
97 |
98 | 99 |
100 | {children} 101 |
102 |
103 | ); 104 | }; 105 | -------------------------------------------------------------------------------- /components/mdx-card.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | interface CardProps extends React.HTMLAttributes { 6 | href?: string; 7 | disabled?: boolean; 8 | } 9 | 10 | export function MdxCard({ href, className, children, disabled, ...props }: CardProps) { 11 | return ( 12 |
20 |
21 |
22 | {children} 23 |
24 |
25 | {href && ( 26 | 27 | View 28 | 29 | )} 30 |
31 | ); 32 | } -------------------------------------------------------------------------------- /components/mdx-components.tsx: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import Image from "next/image" 3 | import { useMDXComponent } from "next-contentlayer/hooks" 4 | import { Callout } from "./callout"; 5 | import { MdxTabs , MdxTab } from "./mdx-tabs"; 6 | import { cn } from "@/lib/utils"; 7 | import { MdxCard } from "./mdx-card"; 8 | import FormIntake from "./form-intake"; 9 | import { toast , useToast} from "@/components/ui/use-toast"; 10 | export const components = { 11 | 12 | h1: ({ className, ...props }) => ( 13 |

17 | ), 18 | h2: ({ className, ...props }) => ( 19 |

26 | ), 27 | h3: ({ className, ...props }) => ( 28 |

32 | ), 33 | h4: ({ className, ...props }) => ( 34 |

38 | ), 39 | h5: ({ className, ...props }) => ( 40 |

44 | ), 45 | h6: ({ className, ...props }) => ( 46 |
50 | ), 51 | a: ({ className, ...props }) => ( 52 | 53 | ), 54 | p: ({ className, ...props }) => ( 55 |

56 | ), 57 | ul: ({ className, ...props }) => ( 58 |

    59 | ), 60 | ol: ({ className, ...props }) => ( 61 |
      62 | ), 63 | li: ({ className, ...props }) =>
    1. , 64 | blockquote: ({ className, ...props }) => ( 65 |
      *]:text-muted-foreground", className)} 67 | {...props} 68 | /> 69 | ), 70 | img: ({ className, alt, ...props }: React.ImgHTMLAttributes) => ( 71 | // rome-ignore lint/a11y/useAltText: 72 | {alt} 73 | ), 74 | hr: ({ ...props }) =>
      , 75 | table: ({ className, ...props }: React.HTMLAttributes) => ( 76 |
      77 | 78 | 79 | ), 80 | tr: ({ className, ...props }: React.HTMLAttributes) => ( 81 | 82 | ), 83 | th: ({ className, ...props }) => ( 84 |
      91 | ), 92 | td: ({ className, ...props }) => ( 93 | 100 | ), 101 | pre: ({ className, ...props }) => ( 102 |
      106 |   ),
      107 |   code: ({ className, ...props }) => (
      108 |       
      115 |   ),
      116 |   // Steps,
      117 |   FormIntake,
      118 |   toast,
      119 |   useToast,
      120 |   Tab: MdxTab,
      121 |   Tabs: MdxTabs,
      122 |   Image: Image as any,
      123 |   Callout,
      124 | Card: MdxCard,
      125 | };
      126 | 
      127 | interface MdxProps {
      128 |   code: string
      129 | }
      130 | 
      131 | export function Mdx({ code }: MdxProps) {
      132 |   const Component = useMDXComponent(code)
      133 | 
      134 |   return 
      135 | }
      136 | 
      
      
      --------------------------------------------------------------------------------
      /components/mdx-tabs.tsx:
      --------------------------------------------------------------------------------
       1 | import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
       2 | 
       3 | interface MdxTabProps {
       4 |     children: React.ReactNode;
       5 |     items: string[];
       6 | }
       7 | 
       8 | export const MdxTabs = ({ children, items }: MdxTabProps) => {
       9 |     return (
      10 |         
      11 |             
      12 |                 {items.map((tab) => (
      13 |                     
      14 |                         

      {tab}

      15 |
      16 | ))} 17 |
      18 | {children} 19 |
      20 | ); 21 | }; 22 | 23 | export const MdxTab = ({ 24 | children, 25 | value, 26 | }: { 27 | children: React.ReactNode; 28 | value: string; 29 | }) => { 30 | return {children}; 31 | }; -------------------------------------------------------------------------------- /components/mode-toggle.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useTheme } from "next-themes" 4 | 5 | export function ModeToggle() { 6 | const { setTheme, theme } = useTheme() 7 | 8 | return ( 9 | 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /components/particles.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useRef, useEffect, useState } from "react"; 4 | import { useMousePosition } from "@/lib/useMouse"; 5 | 6 | interface ParticlesProps { 7 | className?: string; 8 | quantity?: number; 9 | staticity?: number; 10 | ease?: number; 11 | refresh?: boolean; 12 | } 13 | 14 | export default function Particles({ 15 | className = "", 16 | quantity = 30, 17 | staticity = 50, 18 | ease = 50, 19 | refresh = false, 20 | }: ParticlesProps) { 21 | const canvasRef = useRef(null); 22 | const canvasContainerRef = useRef(null); 23 | const context = useRef(null); 24 | const circles = useRef([]); 25 | const mousePosition = useMousePosition(); 26 | const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); 27 | const canvasSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 }); 28 | const dpr = typeof window !== "undefined" ? window.devicePixelRatio : 1; 29 | 30 | useEffect(() => { 31 | if (canvasRef.current) { 32 | context.current = canvasRef.current.getContext("2d"); 33 | } 34 | initCanvas(); 35 | animate(); 36 | window.addEventListener("resize", initCanvas); 37 | 38 | return () => { 39 | window.removeEventListener("resize", initCanvas); 40 | }; 41 | }, []); 42 | 43 | useEffect(() => { 44 | onMouseMove(); 45 | }, [mousePosition.x, mousePosition.y]); 46 | 47 | useEffect(() => { 48 | initCanvas(); 49 | }, [refresh]); 50 | 51 | const initCanvas = () => { 52 | resizeCanvas(); 53 | drawParticles(); 54 | }; 55 | 56 | const onMouseMove = () => { 57 | if (canvasRef.current) { 58 | const rect = canvasRef.current.getBoundingClientRect(); 59 | const { w, h } = canvasSize.current; 60 | const x = mousePosition.x - rect.left - w / 2; 61 | const y = mousePosition.y - rect.top - h / 2; 62 | const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2; 63 | if (inside) { 64 | mouse.current.x = x; 65 | mouse.current.y = y; 66 | } 67 | } 68 | }; 69 | 70 | type Circle = { 71 | x: number; 72 | y: number; 73 | translateX: number; 74 | translateY: number; 75 | size: number; 76 | alpha: number; 77 | targetAlpha: number; 78 | dx: number; 79 | dy: number; 80 | magnetism: number; 81 | }; 82 | 83 | const resizeCanvas = () => { 84 | if (canvasContainerRef.current && canvasRef.current && context.current) { 85 | circles.current.length = 0; 86 | canvasSize.current.w = canvasContainerRef.current.offsetWidth; 87 | canvasSize.current.h = canvasContainerRef.current.offsetHeight; 88 | canvasRef.current.width = canvasSize.current.w * dpr; 89 | canvasRef.current.height = canvasSize.current.h * dpr; 90 | canvasRef.current.style.width = `${canvasSize.current.w}px`; 91 | canvasRef.current.style.height = `${canvasSize.current.h}px`; 92 | context.current.scale(dpr, dpr); 93 | } 94 | }; 95 | 96 | const circleParams = (): Circle => { 97 | const x = Math.floor(Math.random() * canvasSize.current.w); 98 | const y = Math.floor(Math.random() * canvasSize.current.h); 99 | const translateX = 0; 100 | const translateY = 0; 101 | const size = Math.floor(Math.random() * 2) + 0.1; 102 | const alpha = 0; 103 | const targetAlpha = parseFloat((Math.random() * 0.6 + 0.1).toFixed(1)); 104 | const dx = (Math.random() - 0.5) * 0.2; 105 | const dy = (Math.random() - 0.5) * 0.2; 106 | const magnetism = 0.1 + Math.random() * 4; 107 | return { 108 | x, 109 | y, 110 | translateX, 111 | translateY, 112 | size, 113 | alpha, 114 | targetAlpha, 115 | dx, 116 | dy, 117 | magnetism, 118 | }; 119 | }; 120 | 121 | const drawCircle = (circle: Circle, update = false) => { 122 | if (context.current) { 123 | const { x, y, translateX, translateY, size, alpha } = circle; 124 | context.current.translate(translateX, translateY); 125 | context.current.beginPath(); 126 | context.current.arc(x, y, size, 0, 2 * Math.PI); 127 | context.current.fillStyle = `rgba(255, 255, 255, ${alpha})`; 128 | context.current.fill(); 129 | context.current.setTransform(dpr, 0, 0, dpr, 0, 0); 130 | 131 | if (!update) { 132 | circles.current.push(circle); 133 | } 134 | } 135 | }; 136 | 137 | const clearContext = () => { 138 | if (context.current) { 139 | context.current.clearRect( 140 | 0, 141 | 0, 142 | canvasSize.current.w, 143 | canvasSize.current.h, 144 | ); 145 | } 146 | }; 147 | 148 | const drawParticles = () => { 149 | clearContext(); 150 | const particleCount = quantity; 151 | for (let i = 0; i < particleCount; i++) { 152 | const circle = circleParams(); 153 | drawCircle(circle); 154 | } 155 | }; 156 | 157 | const remapValue = ( 158 | value: number, 159 | start1: number, 160 | end1: number, 161 | start2: number, 162 | end2: number, 163 | ): number => { 164 | const remapped = 165 | ((value - start1) * (end2 - start2)) / (end1 - start1) + start2; 166 | return remapped > 0 ? remapped : 0; 167 | }; 168 | 169 | const animate = () => { 170 | clearContext(); 171 | circles.current.forEach((circle: Circle, i: number) => { 172 | // Handle the alpha value 173 | const edge = [ 174 | circle.x + circle.translateX - circle.size, // distance from left edge 175 | canvasSize.current.w - circle.x - circle.translateX - circle.size, // distance from right edge 176 | circle.y + circle.translateY - circle.size, // distance from top edge 177 | canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge 178 | ]; 179 | const closestEdge = edge.reduce((a, b) => Math.min(a, b)); 180 | const remapClosestEdge = parseFloat( 181 | remapValue(closestEdge, 0, 20, 0, 1).toFixed(2), 182 | ); 183 | if (remapClosestEdge > 1) { 184 | circle.alpha += 0.02; 185 | if (circle.alpha > circle.targetAlpha) { 186 | circle.alpha = circle.targetAlpha; 187 | } 188 | } else { 189 | circle.alpha = circle.targetAlpha * remapClosestEdge; 190 | } 191 | circle.x += circle.dx; 192 | circle.y += circle.dy; 193 | circle.translateX += 194 | (mouse.current.x / (staticity / circle.magnetism) - circle.translateX) / 195 | ease; 196 | circle.translateY += 197 | (mouse.current.y / (staticity / circle.magnetism) - circle.translateY) / 198 | ease; 199 | // circle gets out of the canvas 200 | if ( 201 | circle.x < -circle.size || 202 | circle.x > canvasSize.current.w + circle.size || 203 | circle.y < -circle.size || 204 | circle.y > canvasSize.current.h + circle.size 205 | ) { 206 | // remove the circle from the array 207 | circles.current.splice(i, 1); 208 | // create a new circle 209 | const newCircle = circleParams(); 210 | drawCircle(newCircle); 211 | // update the circle position 212 | } else { 213 | drawCircle( 214 | { 215 | ...circle, 216 | x: circle.x, 217 | y: circle.y, 218 | translateX: circle.translateX, 219 | translateY: circle.translateY, 220 | alpha: circle.alpha, 221 | }, 222 | true, 223 | ); 224 | } 225 | }); 226 | window.requestAnimationFrame(animate); 227 | }; 228 | 229 | return ( 230 | 233 | ); 234 | } -------------------------------------------------------------------------------- /components/scrollablepic.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useRef } from "react"; 3 | import { useScroll, useTransform, motion } from "framer-motion"; 4 | 5 | export const ContainerScroll = ({ 6 | users, 7 | titleComponent, 8 | }: { 9 | users: { 10 | name: string; 11 | designation: string; 12 | image: string; 13 | badge?: string; 14 | }[]; 15 | titleComponent: string | React.ReactNode; 16 | }) => { 17 | const containerRef = useRef(null); 18 | const { scrollYProgress } = useScroll({ 19 | target: containerRef, 20 | }); 21 | const [isMobile, setIsMobile] = React.useState(false); 22 | 23 | React.useEffect(() => { 24 | const checkMobile = () => { 25 | setIsMobile(window.innerWidth <= 768); 26 | }; 27 | checkMobile(); 28 | window.addEventListener("resize", checkMobile); 29 | return () => { 30 | window.removeEventListener("resize", checkMobile); 31 | }; 32 | }, []); 33 | 34 | const scaleDimensions = () => { 35 | return isMobile ? [0.7, 0.9] : [1.05, 1]; 36 | }; 37 | 38 | const rotate = useTransform(scrollYProgress, [0, 1], [20, 0]); 39 | const scale = useTransform(scrollYProgress, [0, 1], scaleDimensions()); 40 | const translate = useTransform(scrollYProgress, [0, 1], [0, -100]); 41 | 42 | return ( 43 |
      47 |
      53 |
      54 | 60 |
      61 |
      62 | ); 63 | }; 64 | 65 | export const Header = ({ translate, titleComponent }: any) => { 66 | return ( 67 | 73 | {titleComponent} 74 | 75 | ); 76 | }; 77 | 78 | export const Card = ({ 79 | rotate, 80 | scale, 81 | translate, 82 | users, 83 | }: { 84 | rotate: any; 85 | scale: any; 86 | translate: any; 87 | users: { 88 | name: string; 89 | designation: string; 90 | image: string; 91 | badge?: string; 92 | }[]; 93 | }) => { 94 | return ( 95 | 104 |
      105 | {users.map((user, idx: number) => ( 106 | 115 |
      116 | {user.badge} 117 |
      118 | thumbnail 123 |
      124 |

      {user.name}

      125 |

      {user.designation}

      126 |
      127 |
      128 | ))} 129 |
      130 |
      131 | ); 132 | }; 133 | -------------------------------------------------------------------------------- /components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import { ThemeProvider as NextThemesProvider } from "next-themes" 5 | import type { ThemeProviderProps } from "next-themes/dist/types" 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /components/trendy.tsx: -------------------------------------------------------------------------------- 1 | import { allPosts } from "@/.contentlayer/generated"; 2 | import { PostCard } from "./ui/card-binary-view"; 3 | import { compareDesc } from "date-fns"; 4 | import { Separator } from "./ui/separator"; 5 | import { TextGenerateEffect } from "./ui/text-gen"; 6 | 7 | import Link from "next/link"; 8 | import HackyButton from "./hacky-button"; 9 | const Trendy = () => { 10 | const posts = allPosts 11 | .filter((post) => post.date) 12 | .sort((a, b) => { 13 | PostCard; 14 | return compareDesc(new Date(a.date), new Date(b.date)); 15 | }); 16 | 17 | const firstTwo = [posts[0], posts[1]]; 18 | return ( 19 |
      20 |

      21 | 25 |

      26 | 27 | 28 |
      29 |
      30 | {firstTwo?.length ? ( 31 |
      32 | {firstTwo.map((post, index) => ( 33 | 40 | 41 | //
      45 | // {post.image && ( 46 | // {post.title} 54 | // )} 55 | //

      {post.title}

      56 | // {post.description && ( 57 | //

      {post.description}

      58 | // )} 59 | // {post.date && ( 60 | //

      61 | // {formatDate(post.date)} 62 | //

      63 | // )} 64 | // 65 | // View Article 66 | // 67 | //
      68 | ))} 69 |
      70 |
      71 |
      72 |
      73 |
      74 |
      75 |
      76 | ) : ( 77 |

      No posts published.

      78 | )} 79 |
      80 |
      81 | 82 | 83 | {/* */} 107 | 108 |
      109 |
      110 | ); 111 | }; 112 | 113 | export default Trendy; 114 | -------------------------------------------------------------------------------- /components/ui/Spotlight.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { cn } from "@/lib/utils"; 3 | type SpotlightProps = { 4 | className?: string; 5 | fill?: string; 6 | }; 7 | 8 | const Spotlight = ({ className, fill }: SpotlightProps) => { 9 | return ( 10 | 19 | 20 | 29 | 30 | 31 | 40 | 41 | 47 | 51 | 52 | 53 | 54 | ); 55 | }; 56 | 57 | export default Spotlight; 58 | -------------------------------------------------------------------------------- /components/ui/bg-box.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import React from "react"; 4 | import { motion } from "framer-motion"; 5 | import { cn } from "@/lib/utils"; 6 | 7 | export const BoxesCore = ({ className, ...rest }: { className?: string }) => { 8 | const rows = new Array(150).fill(1); 9 | const cols = new Array(100).fill(1); 10 | let colors = [ 11 | "--sky-300", 12 | "--pink-300", 13 | "--green-300", 14 | "--yellow-300", 15 | "--red-300", 16 | "--purple-300", 17 | "--blue-300", 18 | "--indigo-300", 19 | "--violet-300", 20 | ]; 21 | const getRandomColor = () => { 22 | return colors[Math.floor(Math.random() * colors.length)]; 23 | }; 24 | 25 | return ( 26 |
      36 | {rows.map((_, i) => ( 37 | 41 | {cols.map((_, j) => ( 42 | 53 | {j % 2 === 0 && i % 2 === 0 ? ( 54 | 62 | 67 | 68 | ) : null} 69 | 70 | ))} 71 | 72 | ))} 73 |
      74 | ); 75 | }; 76 | 77 | export const Boxes = React.memo(BoxesCore); 78 | -------------------------------------------------------------------------------- /components/ui/blog-header.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { motion, useInView } from "framer-motion"; 4 | import { useRef } from "react"; 5 | import Feeder from "./feeder"; 6 | 7 | const BlogHeader = ({ totalViews }: { totalViews: number }) => { 8 | const ref = useRef(null); 9 | const isInView = useInView(ref); 10 | const FADE_DOWN_ANIMATION_VARIANTS = { 11 | hidden: { opacity: 0, y: -10 }, 12 | show: { opacity: 1, y: 0, transition: { type: "spring" } }, 13 | }; 14 | 15 | return ( 16 |
      17 | 31 | 32 | 36 |
      37 | What i{" "} 38 | thought 39 |
      40 | 44 | A collection of hand made and crafted thought from KiNFiSH 45 | 46 | 47 | 51 |
      52 |
      53 | ); 54 | }; 55 | 56 | export default BlogHeader; 57 | -------------------------------------------------------------------------------- /components/ui/border-btn.tsx: -------------------------------------------------------------------------------- 1 | const BorderBtn = () => { 2 | return ( 3 |
      4 | 10 |
      11 | ); 12 | }; 13 | export default BorderBtn; 14 | -------------------------------------------------------------------------------- /components/ui/button-std.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | 4 | type ButtonStdProps = { 5 | text: string, 6 | route: string 7 | } 8 | const ButtonStd = (props : ButtonStdProps) => { 9 | return ( 10 |
      11 | 12 | 36 | 37 |
      38 | ); 39 | }; 40 | 41 | export default ButtonStd; 42 | -------------------------------------------------------------------------------- /components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", 9 | { 10 | variants: { 11 | variant: { 12 | default: "bg-primary text-primary-foreground hover:bg-primary/90", 13 | destructive: 14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90", 15 | outline: 16 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground", 17 | secondary: 18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80", 19 | ghost: "hover:bg-accent hover:text-accent-foreground", 20 | link: "text-primary underline-offset-4 hover:underline", 21 | }, 22 | size: { 23 | default: "h-10 px-4 py-2", 24 | sm: "h-9 rounded-md px-3", 25 | lg: "h-11 rounded-md px-8", 26 | icon: "h-10 w-10", 27 | }, 28 | }, 29 | defaultVariants: { 30 | variant: "default", 31 | size: "default", 32 | }, 33 | } 34 | ) 35 | 36 | export interface ButtonProps 37 | extends React.ButtonHTMLAttributes, 38 | VariantProps { 39 | asChild?: boolean 40 | } 41 | 42 | const Button = React.forwardRef( 43 | ({ className, variant, size, asChild = false, ...props }, ref) => { 44 | const Comp = asChild ? Slot : "button" 45 | return ( 46 | 51 | ) 52 | } 53 | ) 54 | Button.displayName = "Button" 55 | 56 | export { Button, buttonVariants } 57 | -------------------------------------------------------------------------------- /components/ui/card-binary-view.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { EvervaultCard, Icon } from "../ui/card-binary"; 3 | import { Separator } from "./separator"; 4 | import Link from "next/link"; 5 | import ButtonStd from "./button-std"; 6 | import HackyButton from "../hacky-button"; 7 | 8 | type PostCardProps = { 9 | title: string; 10 | description: string; 11 | slug: string; 12 | date: string; 13 | }; 14 | export function PostCard(props: PostCardProps) { 15 | return ( 16 |
      17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |

      25 | {props.description} 26 |

      27 | {/*

      28 | Watch me hover 29 |

      */} 30 | 31 | 32 |
      33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /components/ui/card-binary.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useMotionValue } from "framer-motion"; 4 | import React, { useState, useEffect } from "react"; 5 | import { useMotionTemplate, motion } from "framer-motion"; 6 | import { cn } from "@/lib/utils"; 7 | 8 | export const EvervaultCard = ({ 9 | text, 10 | className, 11 | }: { 12 | text?: string; 13 | className?: string; 14 | }) => { 15 | let mouseX = useMotionValue(0); 16 | let mouseY = useMotionValue(0); 17 | 18 | const [randomString, setRandomString] = useState(""); 19 | 20 | useEffect(() => { 21 | let str = generateRandomString(1500); 22 | setRandomString(str); 23 | }, []); 24 | 25 | function onMouseMove({ currentTarget, clientX, clientY }: any) { 26 | let { left, top } = currentTarget.getBoundingClientRect(); 27 | mouseX.set(clientX - left); 28 | mouseY.set(clientY - top); 29 | 30 | const str = generateRandomString(1500); 31 | setRandomString(str); 32 | } 33 | 34 | return ( 35 |
      41 |
      45 | 50 |
      51 |
      52 |
      53 | {text} 54 |
      55 |
      56 |
      57 |
      58 | ); 59 | }; 60 | 61 | export function CardPattern({ mouseX, mouseY, randomString }: any) { 62 | let maskImage = useMotionTemplate`radial-gradient(250px at ${mouseX}px ${mouseY}px, white, transparent)`; 63 | let style = { maskImage, WebkitMaskImage: maskImage }; 64 | 65 | return ( 66 |
      67 |
      68 | 72 | 76 |

      77 | {randomString} 78 |

      79 |
      80 |
      81 | ); 82 | } 83 | 84 | const characters = 85 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 86 | export const generateRandomString = (length: number) => { 87 | let result = ""; 88 | for (let i = 0; i < length; i++) { 89 | result += characters.charAt(Math.floor(Math.random() * characters.length)); 90 | } 91 | return result; 92 | }; 93 | 94 | export const Icon = ({ className, ...rest }: any) => { 95 | return ( 96 | 105 | 106 | 107 | ); 108 | }; 109 | -------------------------------------------------------------------------------- /components/ui/feeder.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | 4 | 5 | const Feeder = ({feed}: {feed:string} ) => { 6 | return ( 7 |
      8 | 34 |
      35 | ); 36 | }; 37 | 38 | export default Feeder; -------------------------------------------------------------------------------- /components/ui/floating-navbar.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import { 4 | AnimatePresence, 5 | motion, 6 | useMotionValueEvent, 7 | useScroll, 8 | } from "framer-motion"; 9 | import { cn } from "@/lib/utils"; 10 | import Link from "next/link"; 11 | import { Icon } from "./card-binary"; 12 | const FloatingNav = ({ 13 | navItems, 14 | className, 15 | }: { 16 | navItems: { 17 | name: string; 18 | link: string; 19 | icon?: JSX.Element; 20 | }[]; 21 | className?: string; 22 | }) => { 23 | const { scrollYProgress } = useScroll(); 24 | 25 | const [visible, setVisible] = useState(false); 26 | 27 | useMotionValueEvent(scrollYProgress, "change", (current) => { 28 | let direction = current - scrollYProgress.getPrevious(); 29 | 30 | if (scrollYProgress.get() < 0.05) { 31 | setVisible(true); 32 | } else { 33 | if (direction < 0) { 34 | setVisible(true); 35 | } else { 36 | setVisible(false); 37 | } 38 | } 39 | }); 40 | return ( 41 | 42 |
      43 | 57 | 58 | 59 | 60 | 61 | 62 |
      63 | {navItems.map((navItem: any, idx: number) => ( 64 | 71 | {/* {navItem.icon} */} 72 | {navItem.name} 73 | 74 | ))} 75 | 79 |
      80 |
      81 | {/* */} 82 |
      83 |
      84 | ); 85 | }; 86 | 87 | export default FloatingNav; 88 | -------------------------------------------------------------------------------- /components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ) 21 | } 22 | ) 23 | Input.displayName = "Input" 24 | 25 | export { Input } 26 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /components/ui/nav-menu.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | import { motion } from "framer-motion"; 4 | import Link from "next/link"; 5 | import Image from "next/image"; 6 | 7 | const transition = { 8 | type: "spring", 9 | mass: 0.5, 10 | damping: 11.5, 11 | stiffness: 100, 12 | restDelta: 0.001, 13 | restSpeed: 0.001, 14 | }; 15 | 16 | export const MenuItem = ({ 17 | setActive, 18 | active, 19 | item, 20 | children, 21 | }: { 22 | setActive: (item: string) => void; 23 | active: string | null; 24 | item: string; 25 | children?: React.ReactNode; 26 | }) => { 27 | return ( 28 |
      setActive(item)} className="relative "> 29 | 33 | {item} 34 | 35 | {active !== null && ( 36 | 41 | {active === item && ( 42 |
      43 | 48 | 52 | {children} 53 | 54 | 55 |
      56 | )} 57 |
      58 | )} 59 |
      60 | ); 61 | }; 62 | 63 | export const Menu = ({ 64 | setActive, 65 | children, 66 | }: { 67 | setActive: (item: string | null) => void; 68 | children: React.ReactNode; 69 | }) => { 70 | return ( 71 | 77 | ); 78 | }; 79 | 80 | export const ProductItem = ({ 81 | title, 82 | description, 83 | href, 84 | src, 85 | }: { 86 | title: string; 87 | description: string; 88 | href: string; 89 | src: string; 90 | }) => { 91 | return ( 92 | 93 | {title} 100 |
      101 |

      102 | {title} 103 |

      104 |

      105 | {description} 106 |

      107 |
      108 | 109 | ); 110 | }; 111 | 112 | export const HoveredLink = ({ children, ...rest }: any) => { 113 | return ( 114 | 118 | {children} 119 | 120 | ); 121 | }; 122 | -------------------------------------------------------------------------------- /components/ui/scollablepicview.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React from "react"; 3 | import { ContainerScroll } from "../scrollablepic" 4 | 5 | export function HeroScrollDemo() { 6 | return ( 7 |
      8 | 12 |

      13 | Unleash the power of
      14 | 15 | Scroll Animations 16 | 17 |

      18 | 19 | } 20 | /> 21 |
      22 | ); 23 | } 24 | 25 | export const users = [ 26 | { 27 | name: "Manu Arora", 28 | designation: "Founder, Algochurn", 29 | image: "https://picsum.photos/id/10/300/300", 30 | badge: "Mentor", 31 | }, 32 | { 33 | name: "Sarah Singh", 34 | designation: "Founder, Sarah's Kitchen", 35 | image: "https://picsum.photos/id/11/300/300", 36 | badge: "Mentor", 37 | }, 38 | { 39 | name: "John Doe", 40 | designation: "Software Engineer, Tech Corp", 41 | image: "https://picsum.photos/id/12/300/300", 42 | badge: "Mentor", 43 | }, 44 | { 45 | name: "Jane Smith", 46 | designation: "Product Manager, Innovate Inc", 47 | image: "https://picsum.photos/id/13/300/300", 48 | badge: "Mentor", 49 | }, 50 | { 51 | name: "Robert Johnson", 52 | designation: "Data Scientist, DataWorks", 53 | image: "https://picsum.photos/id/14/300/300", 54 | badge: "Mentor", 55 | }, 56 | { 57 | name: "Emily Davis", 58 | designation: "UX Designer, DesignHub", 59 | image: "https://picsum.photos/id/15/300/300", 60 | badge: "Mentor", 61 | }, 62 | { 63 | name: "Michael Miller", 64 | designation: "CTO, FutureTech", 65 | image: "https://picsum.photos/id/16/300/300", 66 | badge: "Mentor", 67 | }, 68 | { 69 | name: "Sarah Brown", 70 | designation: "CEO, StartUp", 71 | image: "https://picsum.photos/id/17/300/300", 72 | }, 73 | { 74 | name: "James Wilson", 75 | designation: "DevOps Engineer, CloudNet", 76 | image: "https://picsum.photos/id/18/300/300", 77 | badge: "Something", 78 | }, 79 | { 80 | name: "Patricia Moore", 81 | designation: "Marketing Manager, MarketGrowth", 82 | image: "https://picsum.photos/id/19/300/300", 83 | badge: "Mentor", 84 | }, 85 | { 86 | name: "Richard Taylor", 87 | designation: "Frontend Developer, WebSolutions", 88 | image: "https://picsum.photos/id/20/300/300", 89 | }, 90 | { 91 | name: "Linda Anderson", 92 | designation: "Backend Developer, ServerSecure", 93 | image: "https://picsum.photos/id/21/300/300", 94 | }, 95 | { 96 | name: "William Thomas", 97 | designation: "Full Stack Developer, FullStack", 98 | image: "https://picsum.photos/id/22/300/300", 99 | badge: "Badger", 100 | }, 101 | { 102 | name: "Elizabeth Jackson", 103 | designation: "Project Manager, ProManage", 104 | image: "https://picsum.photos/id/23/300/300", 105 | badge: "Mentor", 106 | }, 107 | { 108 | name: "David White", 109 | designation: "Database Administrator, DataSafe", 110 | image: "https://picsum.photos/id/24/300/300", 111 | badge: "Advocate", 112 | }, 113 | { 114 | name: "Jennifer Harris", 115 | designation: "Network Engineer, NetConnect", 116 | image: "https://picsum.photos/id/25/300/300", 117 | }, 118 | { 119 | name: "Charles Clark", 120 | designation: "Security Analyst, SecureIT", 121 | image: "https://picsum.photos/id/26/300/300", 122 | }, 123 | { 124 | name: "Susan Lewis", 125 | designation: "Systems Analyst, SysAnalyse", 126 | image: "https://picsum.photos/id/27/300/300", 127 | }, 128 | { 129 | name: "Joseph Young", 130 | designation: "Mobile Developer, AppDev", 131 | image: "https://picsum.photos/id/28/300/300", 132 | badge: "Mentor", 133 | }, 134 | { 135 | name: "Margaret Hall", 136 | designation: "Quality Assurance, BugFree", 137 | image: "https://picsum.photos/id/29/300/300", 138 | badge: "Developer", 139 | }, 140 | ]; 141 | -------------------------------------------------------------------------------- /components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as SeparatorPrimitive from "@radix-ui/react-separator" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Separator = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >( 12 | ( 13 | { className, orientation = "horizontal", decorative = true, ...props }, 14 | ref 15 | ) => ( 16 | 27 | ) 28 | ) 29 | Separator.displayName = SeparatorPrimitive.Root.displayName 30 | 31 | export { Separator } 32 | -------------------------------------------------------------------------------- /components/ui/static-nav.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import { 4 | AnimatePresence, 5 | motion, 6 | useMotionValueEvent, 7 | useScroll, 8 | } from "framer-motion"; 9 | import { cn } from "@/lib/utils"; 10 | import Link from "next/link"; 11 | const StaticNavBar = ({ 12 | navItems, 13 | className, 14 | }: { 15 | navItems: { 16 | name: string; 17 | link: string; 18 | icon?: JSX.Element; 19 | }[]; 20 | className?: string; 21 | }) => { 22 | const { scrollYProgress } = useScroll(); 23 | 24 | const [visible, setVisible] = useState(false); 25 | 26 | useMotionValueEvent(scrollYProgress, "change", (current) => { 27 | let direction = current - scrollYProgress.getPrevious(); 28 | 29 | if (scrollYProgress.get() < 0.05) { 30 | setVisible(false); 31 | } else { 32 | if (direction < 0) { 33 | setVisible(true); 34 | } else { 35 | setVisible(false); 36 | } 37 | } 38 | }); 39 | return ( 40 | 41 | 58 | {navItems.map((navItem: any, idx: number) => ( 59 | 66 | {/* {navItem.icon} */} 67 | {navItem.name} 68 | 69 | ))} 70 | 74 | 75 | 76 | ); 77 | }; 78 | 79 | export default StaticNavBar 80 | -------------------------------------------------------------------------------- /components/ui/tabs.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as TabsPrimitive from "@radix-ui/react-tabs" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Tabs = TabsPrimitive.Root 9 | 10 | const TabsList = React.forwardRef< 11 | React.ElementRef, 12 | React.ComponentPropsWithoutRef 13 | >(({ className, ...props }, ref) => ( 14 | 22 | )) 23 | TabsList.displayName = TabsPrimitive.List.displayName 24 | 25 | const TabsTrigger = React.forwardRef< 26 | React.ElementRef, 27 | React.ComponentPropsWithoutRef 28 | >(({ className, ...props }, ref) => ( 29 | 37 | )) 38 | TabsTrigger.displayName = TabsPrimitive.Trigger.displayName 39 | 40 | const TabsContent = React.forwardRef< 41 | React.ElementRef, 42 | React.ComponentPropsWithoutRef 43 | >(({ className, ...props }, ref) => ( 44 | 52 | )) 53 | TabsContent.displayName = TabsPrimitive.Content.displayName 54 | 55 | export { Tabs, TabsList, TabsTrigger, TabsContent } 56 | -------------------------------------------------------------------------------- /components/ui/text-gen.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | "use client"; 4 | import { useEffect } from "react"; 5 | import { motion, stagger, useAnimate } from "framer-motion"; 6 | import { cn } from "@/lib/utils"; 7 | 8 | export const TextGenerateEffect = ({ 9 | words, 10 | className, 11 | }: { 12 | words: string; 13 | className?: string; 14 | }) => { 15 | const [scope, animate] = useAnimate(); 16 | let wordsArray = words.split(" "); 17 | useEffect(() => { 18 | animate( 19 | "span", 20 | { 21 | opacity: 1, 22 | }, 23 | { 24 | duration: 2, 25 | delay: stagger(0.2), 26 | } 27 | ); 28 | }, [scope.current]); 29 | 30 | const renderWords = (className: string) => { 31 | return ( 32 | 33 | {wordsArray.map((word, idx) => { 34 | return ( 35 | 39 | {word}{" "} 40 | 41 | ); 42 | })} 43 | 44 | ); 45 | }; 46 | 47 | return ( 48 |
      49 |
      50 |
      51 | {renderWords(className!)} 52 |
      53 |
      54 |
      55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /components/ui/toast.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as ToastPrimitives from "@radix-ui/react-toast" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | import { X } from "lucide-react" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const ToastProvider = ToastPrimitives.Provider 9 | 10 | const ToastViewport = React.forwardRef< 11 | React.ElementRef, 12 | React.ComponentPropsWithoutRef 13 | >(({ className, ...props }, ref) => ( 14 | 22 | )) 23 | ToastViewport.displayName = ToastPrimitives.Viewport.displayName 24 | 25 | const toastVariants = cva( 26 | "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", 27 | { 28 | variants: { 29 | variant: { 30 | default: "border bg-transparent border-2 border-purple-400/5 rounded-2xl text-foreground", 31 | destructive: 32 | "destructive group border-destructive bg-destructive text-destructive-foreground", 33 | }, 34 | }, 35 | defaultVariants: { 36 | variant: "default", 37 | }, 38 | } 39 | ) 40 | 41 | const Toast = React.forwardRef< 42 | React.ElementRef, 43 | React.ComponentPropsWithoutRef & 44 | VariantProps 45 | >(({ className, variant, ...props }, ref) => { 46 | return ( 47 | 52 | ) 53 | }) 54 | Toast.displayName = ToastPrimitives.Root.displayName 55 | 56 | const ToastAction = React.forwardRef< 57 | React.ElementRef, 58 | React.ComponentPropsWithoutRef 59 | >(({ className, ...props }, ref) => ( 60 | 68 | )) 69 | ToastAction.displayName = ToastPrimitives.Action.displayName 70 | 71 | const ToastClose = React.forwardRef< 72 | React.ElementRef, 73 | React.ComponentPropsWithoutRef 74 | >(({ className, ...props }, ref) => ( 75 | 84 | 85 | 86 | )) 87 | ToastClose.displayName = ToastPrimitives.Close.displayName 88 | 89 | const ToastTitle = React.forwardRef< 90 | React.ElementRef, 91 | React.ComponentPropsWithoutRef 92 | >(({ className, ...props }, ref) => ( 93 | 98 | )) 99 | ToastTitle.displayName = ToastPrimitives.Title.displayName 100 | 101 | const ToastDescription = React.forwardRef< 102 | React.ElementRef, 103 | React.ComponentPropsWithoutRef 104 | >(({ className, ...props }, ref) => ( 105 | 110 | )) 111 | ToastDescription.displayName = ToastPrimitives.Description.displayName 112 | 113 | type ToastProps = React.ComponentPropsWithoutRef 114 | 115 | type ToastActionElement = React.ReactElement 116 | 117 | export { 118 | type ToastProps, 119 | type ToastActionElement, 120 | ToastProvider, 121 | ToastViewport, 122 | Toast, 123 | ToastTitle, 124 | ToastDescription, 125 | ToastClose, 126 | ToastAction, 127 | } 128 | -------------------------------------------------------------------------------- /components/ui/toaster.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { 4 | Toast, 5 | ToastClose, 6 | ToastDescription, 7 | ToastProvider, 8 | ToastTitle, 9 | ToastViewport, 10 | } from "@/components/ui/toast" 11 | import { useToast } from "@/components/ui/use-toast" 12 | 13 | export function Toaster() { 14 | const { toasts } = useToast() 15 | 16 | return ( 17 | 18 | {toasts.map(function ({ id, title, description, action, ...props }) { 19 | return ( 20 | 21 |
      22 | {title && {title}} 23 | {description && ( 24 | {description} 25 | )} 26 |
      27 | {action} 28 | 29 |
      30 | ) 31 | })} 32 | 33 |
      34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /components/ui/twickled-line.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { cn } from "@/lib/utils"; 3 | import { motion, MotionValue, useInView } from "framer-motion"; 4 | import React, { useRef } from "react"; 5 | 6 | const transition = { 7 | duration: 0, 8 | ease: "linear", 9 | }; 10 | 11 | export const GoogleGeminiEffect = ({ 12 | pathLengths, 13 | title, 14 | description, 15 | className, 16 | }: { 17 | pathLengths: MotionValue[]; 18 | title?: string; 19 | description?: string; 20 | className?: string; 21 | }) => { 22 | const FADE_DOWN_ANIMATION_VARIANTS = { 23 | hidden: { opacity: 0, y: -10 }, 24 | show: { opacity: 1, y: 0, transition: { type: "spring" } }, 25 | }; 26 | const ref = useRef(null); 27 | const isInView = useInView(ref); 28 | return ( 29 |
      30 | 44 | 48 | {title || `Build with Aceternity UI`} 49 | 50 | 51 |

      52 | {description || 53 | `Scroll this component and see the bottom SVG come to life wow this 54 | works!`} 55 |

      56 |
      57 | 60 |
      61 | 68 | 81 | 94 | 107 | 120 | 133 | 134 | {/* Gaussian blur for the background paths */} 135 | 136 | 144 | 152 | 160 | 168 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 |
      184 | ); 185 | }; 186 | -------------------------------------------------------------------------------- /components/ui/twickled-view.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { useScroll, useTransform } from "framer-motion"; 3 | import React from "react"; 4 | import { GoogleGeminiEffect } from "@/components/ui/twickled-line" 5 | 6 | export default function TwickledDemo() { 7 | const ref = React.useRef(null); 8 | const { scrollYProgress } = useScroll({ 9 | target: ref, 10 | offset: ["start start", "end start"], 11 | }); 12 | 13 | const pathLengthFirst = useTransform(scrollYProgress, [0, 0.8], [0.2, 1.2]); 14 | const pathLengthSecond = useTransform(scrollYProgress, [0, 0.8], [0.15, 1.2]); 15 | const pathLengthThird = useTransform(scrollYProgress, [0, 0.8], [0.1, 1.2]); 16 | const pathLengthFourth = useTransform(scrollYProgress, [0, 0.8], [0.05, 1.2]); 17 | const pathLengthFifth = useTransform(scrollYProgress, [0, 0.8], [0, 1.2]); 18 | 19 | return ( 20 |
      24 | 35 |
      36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /components/ui/use-toast.ts: -------------------------------------------------------------------------------- 1 | // Inspired by react-hot-toast library 2 | // @ts-nocheck 3 | import * as React from "react" 4 | 5 | import type { 6 | ToastActionElement, 7 | ToastProps, 8 | } from "@/components/ui/toast" 9 | 10 | const TOAST_LIMIT = 1 11 | const TOAST_REMOVE_DELAY = 1000000 12 | 13 | type ToasterToast = ToastProps & { 14 | id: string 15 | title?: React.ReactNode 16 | description?: React.ReactNode 17 | action?: ToastActionElement 18 | } 19 | 20 | const actionTypes = { 21 | ADD_TOAST: "ADD_TOAST", 22 | UPDATE_TOAST: "UPDATE_TOAST", 23 | DISMISS_TOAST: "DISMISS_TOAST", 24 | REMOVE_TOAST: "REMOVE_TOAST", 25 | } as const 26 | 27 | let count = 0 28 | 29 | function genId() { 30 | count = (count + 1) % Number.MAX_SAFE_INTEGER 31 | return count.toString() 32 | } 33 | 34 | type ActionType = typeof actionTypes 35 | 36 | type Action = 37 | | { 38 | type: ActionType["ADD_TOAST"] 39 | toast: ToasterToast 40 | } 41 | | { 42 | type: ActionType["UPDATE_TOAST"] 43 | toast: Partial 44 | } 45 | | { 46 | type: ActionType["DISMISS_TOAST"] 47 | toastId?: ToasterToast["id"] 48 | } 49 | | { 50 | type: ActionType["REMOVE_TOAST"] 51 | toastId?: ToasterToast["id"] 52 | } 53 | 54 | interface State { 55 | toasts: ToasterToast[] 56 | } 57 | 58 | const toastTimeouts = new Map>() 59 | 60 | const addToRemoveQueue = (toastId: string) => { 61 | if (toastTimeouts.has(toastId)) { 62 | return 63 | } 64 | 65 | const timeout = setTimeout(() => { 66 | toastTimeouts.delete(toastId) 67 | dispatch({ 68 | type: "REMOVE_TOAST", 69 | toastId: toastId, 70 | }) 71 | }, TOAST_REMOVE_DELAY) 72 | 73 | toastTimeouts.set(toastId, timeout) 74 | } 75 | 76 | export const reducer = (state: State, action: Action): State => { 77 | switch (action.type) { 78 | case "ADD_TOAST": 79 | return { 80 | ...state, 81 | toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), 82 | } 83 | 84 | case "UPDATE_TOAST": 85 | return { 86 | ...state, 87 | toasts: state.toasts.map((t) => 88 | t.id === action.toast.id ? { ...t, ...action.toast } : t 89 | ), 90 | } 91 | 92 | case "DISMISS_TOAST": { 93 | const { toastId } = action 94 | 95 | // ! Side effects ! - This could be extracted into a dismissToast() action, 96 | // but I'll keep it here for simplicity 97 | if (toastId) { 98 | addToRemoveQueue(toastId) 99 | } else { 100 | state.toasts.forEach((toast) => { 101 | addToRemoveQueue(toast.id) 102 | }) 103 | } 104 | 105 | return { 106 | ...state, 107 | toasts: state.toasts.map((t) => 108 | t.id === toastId || toastId === undefined 109 | ? { 110 | ...t, 111 | open: false, 112 | } 113 | : t 114 | ), 115 | } 116 | } 117 | case "REMOVE_TOAST": 118 | if (action.toastId === undefined) { 119 | return { 120 | ...state, 121 | toasts: [], 122 | } 123 | } 124 | return { 125 | ...state, 126 | toasts: state.toasts.filter((t) => t.id !== action.toastId), 127 | } 128 | } 129 | } 130 | 131 | const listeners: Array<(state: State) => void> = [] 132 | 133 | let memoryState: State = { toasts: [] } 134 | 135 | function dispatch(action: Action) { 136 | memoryState = reducer(memoryState, action) 137 | listeners.forEach((listener) => { 138 | listener(memoryState) 139 | }) 140 | } 141 | 142 | type Toast = Omit 143 | 144 | function toast({ ...props }: Toast) { 145 | const id = genId() 146 | 147 | const update = (props: ToasterToast) => 148 | dispatch({ 149 | type: "UPDATE_TOAST", 150 | toast: { ...props, id }, 151 | }) 152 | const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) 153 | 154 | dispatch({ 155 | type: "ADD_TOAST", 156 | toast: { 157 | ...props, 158 | id, 159 | open: true, 160 | onOpenChange: (open) => { 161 | if (!open) dismiss() 162 | }, 163 | }, 164 | }) 165 | 166 | return { 167 | id: id, 168 | dismiss, 169 | update, 170 | } 171 | } 172 | 173 | function useToast() { 174 | const [state, setState] = React.useState(memoryState) 175 | 176 | React.useEffect(() => { 177 | listeners.push(setState) 178 | return () => { 179 | const index = listeners.indexOf(setState) 180 | if (index > -1) { 181 | listeners.splice(index, 1) 182 | } 183 | } 184 | }, [state]) 185 | 186 | return { 187 | ...state, 188 | toast, 189 | dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), 190 | } 191 | } 192 | 193 | export { useToast, toast } 194 | -------------------------------------------------------------------------------- /components/views.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { useEffect, useState } from "react"; 3 | 4 | type ViewProps = { 5 | slug: string; 6 | }; 7 | 8 | const Views = (props: ViewProps) => { 9 | const { slug } = props; 10 | const [viewed, setViewed] = useState(false); 11 | useEffect(() => { 12 | fetch("/api/increment", { 13 | method: "POST", 14 | headers: { 15 | "Content-Type": "application/json", 16 | }, 17 | body: JSON.stringify({ slug }), 18 | }); 19 | }, [slug]); 20 | return null; 21 | }; 22 | 23 | export default Views; 24 | -------------------------------------------------------------------------------- /content/authors/kinfish.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: kinfish 3 | avatar: /images/kinfe.jpeg 4 | twitter: KinfishT 5 | description: Dev @ Farmers 6 | --- -------------------------------------------------------------------------------- /content/pages/about.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: About 3 | description: About the site 4 | --- 5 | 6 | Blandit libero volutpat sed cras ornare arcu. Cursus sit amet dictum sit amet. Nunc vel risus commodo viverra maecenas accumsan. Libero id faucibus nisl tincidunt eget nullam non nisi est. Varius quam quisque id diam vel quam. Id donec ultrices tincidunt arcu non. 7 | 8 | ## Consent 9 | 10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Volutpat sed cras ornare arcu. Nibh ipsum consequat nisl vel pretium lectus quam id leo. A arcu cursus vitae congue. Amet justo donec enim diam. Vel pharetra vel turpis nunc eget lorem. Gravida quis blandit turpis cursus in. Semper auctor neque vitae tempus. Elementum facilisis leo vel fringilla est ullamcorper eget nulla. Imperdiet nulla malesuada pellentesque elit eget. 11 | 12 | Felis donec et odio pellentesque diam volutpat commodo sed. 13 | 14 | Tortor consequat id porta nibh. Fames ac turpis egestas maecenas pharetra convallis posuere morbi leo. Scelerisque fermentum dui faucibus in. Tortor posuere ac ut consequat semper viverra. 15 | 16 | ## Information we collect 17 | 18 | Amet justo donec enim diam. In hendrerit gravida rutrum quisque non. Hac habitasse platea dictumst quisque sagittis purus sit. 19 | 20 | ## How we use your Information 21 | 22 | Ut sem nulla pharetra diam sit amet nisl suscipit adipiscing. Consectetur adipiscing elit pellentesque habitant. Ut tristique et egestas quis ipsum suspendisse ultrices gravida. 23 | -------------------------------------------------------------------------------- /content/posts/hacking-meeting.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hacking Meetings 3 | description: This is me try hacking a meetings 4 | image: /images/blogs/zoom1.jpg 5 | date: "2024-01-19" 6 | authors: 7 | - kinfish 8 | --- 9 | 10 | You know guys... when I was at the company, I used to attend meetings with a lot of people three times a day. Yeah, I know, it's so tiresome, and programmers are too lazy for this, though. "Talk is cheap, show me the code" was from Linus Torvalds, if I'm not mistaken. 11 | 12 | Yeah, I decided to automate it. Hopefully, the meeting link is attached to the calendar invite. What I did was try to create a bot, kind of thing along with a webhook, to automate the hooking from the calendar based on their time and join the meeting using some scrapper tools. Yeah, it went pretty well. I thought it would be somehow buggy, but it was not that much buggy. The first time I joined the meeting based on the bot, yeah, I was too excited, and I thought a lot of things that I can do if I didn't attend the meeting because it was like time-consuming - 40+ minutes was really time-consuming, man. Yeah, my muscle was like this. 13 | 14 | I fetched the data from the calendar -> check the arrival time -> when it reaches, it pops out the meeting link and joins the meeting. I was pretty happy with that. But then, I said, wait, what if I extend this further? Like, what if I get called in a meeting by the presenter or meeting leader to explain my task? Yeah, as you can see, we are going somewhere near AI. Yeah, it actually is. I want to feed AI about my current update, and I want it to give a summary based on the data I feed it. Or like ToD - topic of the day - and to kind of impersonate me and talk like me, which would be voice processing intensive, like making sure to listen for keywords that concern me, like my name, the task I am working on, or something like that. 15 | 16 | I want that AI to explain, but not only that, I want the AI to take a summary note for that. I guess I can use external services like voice-intensive LLM out there, like Fehem - the famous one. I guess she is a girl, no offense 😂, for AI. Yeah, or I can build the native one there for some specific purpose of mine. I really want to make it more specific to meeting stuff. I guess there is also one closer to meeting utilities I may check out for API 😄. Yeah, the guess developers have to take this issue so seriously that we have a win-win situation. 17 | 18 | Assuming we had some meeting-oriented job, all of the API-featured stuff is not implemented yet, but a non-AI version of it is there on a [GitHub](https://github.com/Kinfe123/AutoJoin-Meeting-From-Calendar.) repository, which was a while ago. Yeah, I wish you all stand with me. For those who don't have meetings, you don't need external effort, but I am definitely sure at some point you need some such kind of services, not only for devs but also other professionals. I believe this is not being lazy, and we do need to opt out from a bloated calendar. Hopefully, you find it insightful. I need it as a billionaire dollar idea, but I'll let you guys steal it 😭😄. Yeah, we need to make that happen. 19 | -------------------------------------------------------------------------------- /content/posts/is-bun-dropin-replacement.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Is Bun A Drop In Replacement 3 | description: This will be a brief discussion about bun being a replacement 4 | image: /images/blogs/bun.png 5 | date: "2023-01-01" 6 | authors: 7 | - kinfish 8 | --- 9 | 10 | 11 | # Bun: A Fast and Comprehensive Toolkit 12 | 13 | 14 | 15 | > A wise man once told me, "When you start eating Bun, Node.js will feel bland". 16 | 17 | 18 | Bun is a fast and comprehensive toolkit for JavaScript and TypeScript development. It is designed to handle various tasks involved in the development process, including running, building, testing, and debugging applications. Bun aims to provide a streamlined experience by allowing developers to work with JavaScript and TypeScript projects of different scales. Whether you're working on a small single-file project or a larger full-stack application, Bun aims to be a versatile tool that can handle the necessary tasks efficiently. 19 | 20 | ## Naming Issue - Theo 21 | 22 | The creator of T3, Theo, warned them about not using the name "buntime," but it seems they didn't heed the advice. This decision had consequences, as Bun became a compiler, package manager, and bundler. 23 | 24 | ## What Makes Bun Different? 25 | 26 | What sets Bun apart from other primitive JavaScript runtimes? The goal of Bun is to eliminate slowness and complexity while retaining the great features of JavaScript. It ensures that your favorite libraries and frameworks continue to work, and you don't need to unlearn the conventions you're already familiar with. 27 | 28 | One notable difference is that Bun drops the use of Node.js's primitive JavaScript engine, Chrome V8, and instead utilizes the JavaScript core engine (Apple), which is optimized for startup time. Additionally, as a YC-funded company, Bun's long-term sustainability may be a concern, making it challenging for Jarred, the creator of Bun, to pay developers and recruit more creative developers to the team except for OSS guys. 29 | 30 | Furthermore, while the camel was wandering with me, it shared a piece of advice: to use OCaml for building such runtimes and compilers due to its functional and powerful type safety features. However, it seems Zig was chosen instead, as Zig made the development process a "bun-dle" of joy, while OCaml and C++ couldn't "knead" up the same level of fun! Rest assured, Jarred Sumner was present during the camel's storytelling—just kidding! 😆 31 | 32 | 33 | ## Behind the Drama: Exploring the Bun Ecosystem 34 | 35 | Zig covers over 43% of Bun's codebase, alongside C++, both being performant choices for building runtimes and compilers. However, let me share a secret: ThePrimeage, a somewhat average Rust user, is quite pissed off. This doesn't necessarily mean Zig is faster than the C++ on which Node.js is built. Also, keep in mind C++ is fast, but that doesn't mean any code written in C++ will be. Perhaps I'm more sensitive to the peculiar friction within the Node.js space. So, let's dive deeper into what's happening behind this drama. 36 | 37 | ### Test Runner and Development Tools 38 | 39 | - Is the built-in test runner in Bun legitimate, or do you need something else? 40 | - What are people using nowadays? Is npm still the go-to package manager, or should you consider Yarn or pnpm? 41 | - what about workspaces? Do people still rely on ts-node, or does nodemon suffice, even though it's not well-documented? Do you still need ts-watch or node-watch? 42 | 43 | ### tsconfig and package.json 44 | 45 | - What new additions have been made to tsconfig? 46 | - Should you start using modules yet? Are there any new fields in package.json, 47 | - what should you be doing with the "targets" field if you're building a library? Should you stick with tsc, or is there a better alternative that everyone is using? 48 | 49 | ### Express and ORM/Query Builders 50 | 51 | - Is Express 5 already out? Just kidding! Well, the beta version seems to work, so can you just use that? 52 | - speaking of which, what's the new ORM/query builder/driver du jour? Is the one you used a few months ago considered abandonware? Can you opt for something different? Is it production-ready? 53 | 54 | ### Bun's Solutions 55 | 56 | Surprisingly, all these questions are answered by Bun. Bun provides access to a faster runtime, which enhances the entire ecosystem that our projects rely on. It significantly speeds up test suites, bundlers, linters, and all the developer tooling that supports modern JavaScript development. 57 | 58 | Let me ask you something: Do you consider the database as a bottleneck? While performing queries doesn't block the main thread, running JS does. However, performance is definitely a selling point for the Bun team. It's a way to provide the Node.js community with a better experience and address the performance obsession. 59 | 60 | What about the network? Can that be a bottleneck too? Both caching mechanisms are employed. The great thing about Bun is that it doesn't check the network when installing packages. It relies on the oldy versions, possible number that can be represented by the caret (^) symbol, and it also ignores the latest package versions (@latest). 61 | 62 | Some argue that all these benchmarks and comparisons are nitpicks and often unfair. The true value Bun offers is an improved developer experience (DX) with built-in TypeScript support. 63 | 64 | Now, I'm curious to hear your thoughts. What do you think about all of this? 65 | 66 | 67 | ## What Bun Replaces in Node.js 68 | 69 | - Bunx: Bunx is five times faster than npx and eliminates the need for modules like dotenv and cross-env. It provides faster dependency installation and includes a default watch mode with websocket support. 70 | 71 | - Transpiler: Bun can run various file types such as `.js`, `.ts`, `.cjs`, .`mjs`, .`jsx`, and `.tsx`. This eliminates the need for tools like esbuild, Webpack, Parcel, and Rollup. 72 | 73 | - Node.js Compatibility: Bun aims for complete compatibility with the Node.js API. Most npm packages intended for Node.js environments can work seamlessly with Bun. Check the list of supported Node.js built-in modules on [the Bun documentation](https://bun.sh/docs/runtime/nodejs-apis). 74 | 75 | - APIs: Bun implements a set of native APIs on the Bun global object and through built-in modules. These APIs are highly optimized and introduce new APIs primarily for server-side tasks where no standard exists. See the list of supported Bun APIs on [the Bun documentation](https://bun.sh/docs/runtime/bun-apis). 76 | 77 | - Package Manager: Bun is an npm-compatible package manager that reads your package.json and writes to node_modules. 78 | 79 | - Testing: Bun is Jest compatible, providing snapshot testing, mocking, and code coverage. 80 | 81 | Bun also offers ESM and CommonJS compatibility, allowing you to use both module systems within the same file without complex configuration. 82 | 83 | For more information, you can visit the Bun documentation links provided. 84 | 85 | 86 | - Like yarn, npm, and pnpm, Bun acts as a package manager focused on saving disk space and boosting installation speed. Starting today, Projects that contain a bun.lockb file will automatically run bun install as the default Install Command using bun@1. 87 | Bun is a fast JavaScript runtime. Its goal is to make the experience of building software faster, less frustrating, and more fun. Bun has been benchmarked in the cloud as well as locally, and it outperforms the Node.js runtime. It is on par with other server-side languages like Rust in terms of performance. For example, when benchmarked using wrk: 88 | 89 | 90 | 91 | Bun is a fast JavaScript runtime. Its goal is to make the experience of building software faster, less frustrating, and more fun. Bun has been benchmarked in the cloud as well as locally, and it outperforms the Node.js runtime. It is on par with other server-side languages like Rust in terms of performance. For example, when benchmarked using wrk: 92 | 93 | The source code for this test can be found at: [github](https://github.com/emilpriver/go-rust-bun) 94 | 95 | 96 | ### Bun Benchmark 97 | ```bash 98 | ➜ ~ wrk -t16 -c1000 -d30 http://IP_ADDRESS:3000 [23/09/11|06:20pm] 99 | Running 30s test @ http://IP_ADDRESS:3000 100 | 16 threads and 1000 connections 101 | Thread Stats Avg Stdev Max +/- Stdev 102 | Latency 42.61ms 15.20ms 647.53ms 95.99% 103 | Req/Sec 1.48k 173.54 2.17k 80.20% 104 | 707302 requests in 30.10s, 88.36MB read 105 | Socket errors: connect 0, read 83, write 0, timeout 0 106 | Requests/sec: 23497.18 107 | Transfer/sec: 2.94MB 108 | ``` 109 | 110 | ### Nodeje Benchmark 111 | ```bash 112 | ➜ ~ wrk -t16 -c1000 -d30 http://IP_ADDRESS:3000 [23/09/11|06:21pm] 113 | Running 30s test @ http://IP_ADDRESS:3000 114 | 16 threads and 1000 connections 115 | Thread Stats Avg Stdev Max +/- Stdev 116 | Latency 52.50ms 77.15ms 2.00s 98.27% 117 | Req/Sec 1.23k 235.30 2.54k 78.12% 118 | 587719 requests in 30.10s, 91.92MB read 119 | Socket errors: connect 0, read 0, write 0, timeout 434 120 | Requests/sec: 19524.73 121 | Transfer/sec: 3.05MB 122 | ``` 123 | Some other benchmarks record 124 | 125 | ## Results 126 | 127 | For results suffix with `-node` means that the framework is run in Node, otherwise is using Bun. 128 | 129 | These results are measured in req/s: 130 | 131 | | Framework | Average | Get (/) | Params, query & header | Post JSON | 132 | | ---------------------- | ----------- | ---------- | ---------------------- | ---------- | 133 | | uws (node) | 369,192.103 | 457,538.99 | 389,308.63 | 260,728.69 | 134 | | stricjs (bun) | 268,422.07 | 323,535.76 | 262,470.15 | 219,260.3 | 135 | | bun (bun) | 262,250.81 | 325,012.5 | 238,600.42 | 223,139.51 | 136 | | elysia (bun) | 261,538.61 | 321,378.82 | 248,866.5 | 214,370.51 | 137 | | vixeny (bun) | 260,097.983 | 321,361.76 | 250,442.26 | 208,489.93 | 138 | | hyper-express (node) | 241,177.05 | 350,373.13 | 274,099.12 | 99,058.9 | 139 | | hono (bun) | 238,294.85 | 295,794.19 | 227,806.78 | 191,283.58 | 140 | | bun-web-standard (bun) | 233,734.623 | 282,952.77 | 220,206.67 | 198,044.43 | 141 | | nhttp (bun) | 232,273.04 | 300,289.39 | 213,002.07 | 183,527.66 | 142 | | hyperbun (bun) | 162,952.447 | 218,591.35 | 158,992.25 | 111,273.74 | 143 | | nbit (bun) | 149,914.61 | 190,477.31 | 147,009.36 | 112,257.16 | 144 | | baojs (bun) | 148,991.963 | 187,599.82 | 144,528.44 | 114,847.63 | 145 | | hono (deno) | 132,527.407 | 167,513.6 | 137,757.28 | 92,311.34 | 146 | | h3 (node) | 109,805.423 | 134,438.55 | 97,886.93 | 97,090.79 | 147 | | fast (deno) | 94,872.417 | 111,352.95 | 94,498.72 | 78,765.58 | 148 | | cheetah (deno) | 65,816.437 | 123,169.82 | 56,127.76 | 18,151.73 | 149 | | fastify (node) | 65,813.137 | 78,048.68 | 67,553.99 | 51,836.74 | 150 | | oak (deno) | 49,623.603 | 58,177.14 | 50,212.64 | 40,481.03 | 151 | | abc (deno) | 42,806.143 | 54,345.39 | 45,928.65 | 28,144.39 | 152 | | koa (node) | 39,195.18 | 45,212.34 | 40,435.12 | 31,938.08 | 153 | | express (bun) | 29,432.237 | 38,914.36 | 33,669.54 | 15,712.81 | 154 | | hapi (node) | 28,066.047 | 42,783.67 | 15,394.81 | 26,019.66 | 155 | | adonis (node) | 23,047.5 | 22,368.91 | 21,316.67 | 25,456.92 | 156 | | express (node) | 16,791.037 | 18,300.92 | 17,711.03 | 14,361.16 | 157 | | hono (node) | 15,607.28 | 17,964.72 | 16,495.52 | 12,361.6 | 158 | | nest (node) | 15,139.233 | 17,054.97 | 15,822.37 | 12,540.36 | 159 | | acorn (deno) | 3,217.67 | 5,340.93 | 2,452.29 | 1,859.79 | 160 | 161 | 162 | 163 | See more detail in [results](https://github.com/SaltyAom/bun-http-framework-benchmark/tree/main/results) 164 | 165 | # Conclussion 166 | 167 | Despite the impressive performance of Bun, it's important to note that it's not necessary to replace your current tech stack with Bun. Both Bun and Node.js have their strengths and are capable of fulfilling their respective roles effectively. It's possible that Node.js is working hard to keep up with the demands of the ecosystem. Ultimately, the choice of technology depends on your specific requirements and preferences. 168 | 169 | For more information, you can visit the Bun documentation links provided. 170 | 171 | -------------------------------------------------------------------------------- /content/posts/my-interview-xp.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: My interview experience in big tech company 3 | description: Unveiling my Experience in big tech company and how it went and lessons that i have learned from that 4 | image: /images/blogs/interview.webp 5 | date: "2024-01-05" 6 | authors: 7 | - kinfish 8 | --- 9 | 10 | 11 | # Just rough overview of my experience from interviews 12 | 13 | 14 | - Yeah , One thing I have learned on having an interview with big tech companies is like you should always be talking to the end of the interview starting from a very first start like you should be making your self as leader like a team player plus ask a lot of questions - trust me on this + know exactly what the company values and principles from their website which is crucial for the question - 'why do you wanna join us' so guys where even not in big tech but other interview try being a team player as much as possible with out any grand exaggeration .. just keep it smooth ... Being nervous is so normal.. even I told him that I am so nervous so that he gave 2 or 3 min to relax and he was even talking me about other stuff like school and stuff like that + after you do all this time there is a time where you being asked about the project and stuff like that and mentioning about opensource contribution is heck keypoint with your contribution proof like what you actually did , what changed after your change and stuff like that ...since it is the actual replica of the work environment you will be working on except on closed source projects . 15 | - Yeah communication communication communication communication is really key you got have to take it consideration and take it really seriously over the technical side I can say... Honestly the technical questions was not that bad rather it was easy like he asked me to implement MRU - mostly recently used - you can call it as new varient of data structure but here there is some rule on ordering and putting stuff plus removing and inserting . 16 | - Yeah as the name implies it is just there will be a set of operation you need to do on most recently used value from your **MRU** data structure implementation which was the opposite of LRU which is the most famous interview questiosn and yeah first I allow my self to explain my thought process plus what data structure like nested data structure am gonna be using while implementing the algorithm + data structure and I just went through the farming approach so called brute force and explained to him why it does not scale as our input size grows which have a direct correlation with our output beside any auxiliary space since I ain't use any..and yeah coming up with brute force solution is so crucial so that even you even showed him how well you understood the question but also you will have a credit on doing so .. 17 | - so that even it can helps you on optimizing the code interms of time or space complexity yeah the brute force one took me about 5 min and I went to trying out the optimized approach which is somehow hard by that time plus the pressure yeah I just trying calming my self and continued explaining why brute force does not work and we need to optimize further and yeah with 3 or 4 minute I came up with some optimization which I really did interms of operation optimization like insertion and deletion and some other operation was a bit time and space costy which I optimized them later to constant time operation instead of avg O(n) time complexity and and I just went over writing the pseudo code while explaining my thoughts and I explained the fine details about why I did choose some data structure instead of other and stuff like that and yeah told him and explained him at my best which I hoped he understood my approach very clear and he was happy by my solution since we were having a fun at some point me trying to explain some crazy word that I usually use in amahric and getting a stutter Infront of him 🤣 which was kind of funny by that time and we both laughed and he requested me to calm down for more time if I need so. Yeah after about 10 min I finished implementing my solution and finished the analysis like auxiliary space , time , space , operation wise and stuff like that . More or less this was a bit of my experience with the company and we even shared our linkedin , by the end it was somehow a kind of question like what you major accomplishments, what is you proudest moment on your career - for me it was participating on hackaton and contributing to opensource project which he was really interested of listening to , we have talked about some of the contribution that I have done and why I did that , the impact , the pros and cons all of the flaws and by the end he asked me if I do have a question for him and I said nope and we have shared our good byes and that was the end of the interview process and after that I have doubt a lot of mistake which I did while the interview and which was not that bad but still something that need to addressed. And for further questions I'm might have another blog like a part 2 explaining a detail of my experience on that. Other than that I still don't know the result but I don't know if it will goes as I expected or not .. there were a mistake that I did but I really do well on technical + expressing my thought . And if anybody who guessed a company will have **100ETB card** except for this fellas who knows. **sorry** for long post ;) guys .. hope you get lucky on this 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /content/posts/rsc-mental-models-and-new-react-era.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: RSC and Mental models - React on Server 3 | description: Most of the thing about React Servers as well Nextjs Adoption 4 | image: /images/blogs/ai-2.png 5 | date: "2024-04-01" 6 | authors: 7 | - kinfish 8 | --- 9 | 10 | 11 | ## Hm... Quite Interesting 12 | 13 | They is a lot to cover about the new Mental Models / Archs that the react and Nextjs has come up with. Yeah we will discuss a lot of thing related to the **RSC** and Some points of confusion will be addressed. 14 | 15 | #@ Good old days 16 | 17 | Earlier , React is supposed to replace HTML + JS concept by something called JSX - which is a bundled rich components that makes your website interactive and responsive to the user. that we call it a frontend framework. i.e framework is not libraries. libraries are meant to solve a specific set of closly related task which 18 | you can call it as Module but they still have difference. Yeah the point is not this. so lets move on to our points. 19 | 20 | Traditional server-clinet model does the job but we need better user xp at scale or not - use DRY here - no more memoized roundtrip from client to servers if you could think of it as recurssive function so called DP - Dynamic Programming. which helds us using client react API to do all the job but it is not at a scale 21 | so why dont we need something as preprocessor like C++ Macro tag - means liee somthing or somewhere the data can be store and process upfront and bringing the latest data to the end users. i am not saying this is the so effecient but it something that is not new for us. Devs lik PHP , Rails and other Server side langs not all but been using this thing. 22 | 23 | however bring this in to life on client framework is something cool or somehow bad yeah but the idea of pruning data on sever for UI layer is pretty cool. 24 | The clinet side is just no-brainer just what you want to see is there in react itself. 25 | 26 | ## **RSC** sratching the surface 27 | 28 | Lets start by definining **RSC** by my own terms - It is new Mental model for react that allows us to kind of deviate us from client heavy to hybrid or server heavy model. 29 | Yeah we all know that React is all frontend framework , no idea about servers only cares about bundlers - ESbuilds :) 30 | 31 | I can also be saying **RSC** is aiming for zero-bundle-size React Server Components, which aim to enable modern UX with a server-driven mental model. BUt this is so different from SSR(more of dyanmic) and SSG (more of static). You will learn about this one also. 32 | 33 | 34 | ## SSR vs SSG ? The combo ? 35 | So lets deep dive in , SSR is more technical word is like turning JSX into an HTML string, Yeah this is input and th bi-product symbosis. 36 | 37 | 38 | When we break it down , it is a way to prepare and render your compoents on server instead of browser and send the final product to browser called HTML, which can appear to result in a fast First Contentful Paint or Largest Contentful Paint. 39 | 40 | so the most simplified step will looks something like this - JSX -> Server(runtime) -> HTML -> Client Browser. 41 | 42 | 43 | With SSG, all the pages are generated at build time as static pages (with some Javascript tricks to load/preload content as fast as possible). The Time-To-First-Byte is the best you can get and you can host your website on a Static 44 | 45 | But like you can consider it like this SSG is more for static website like something that the data can be processed at a build time. so it is always available as props from layout as high level access. which we can deploy it on CDN . but SSG is like for dyanmic content but there exists a data that always up-to-date and let us generate an HTML from that. 46 | 47 | It is the limitation of SSR leads to us for most of the concepts around **RSC**. since JS is still need to be fetched from remote server just to go through hydration process. BUT what is hydration here tho ? Hydration is like water bringing a functionality to your body. it is like paiting of Javascript to our website to make it interactive for initially loaded page. You can break down the step , hydration = download html -> download js -> evaluate js -> attaching event listener -> paint the state. Yeah this step needs to be done even if it SSR'ed 48 | There is some web framework that do resumablity like qwik does - like serlializing everything on pause and resumes any where inside of your app. which is an optimization for hydration 49 | Enough of this concepts - lets get to **RSC** like i said .. it is something that makes react to be somehow more than UI framework .. Yeah it break it down. 50 | 51 | As i said it is like migrating from client first to server first or hybrid so that we can significant reduce a bundle size that shipped to the client so that they user would have a good UX. 52 | 53 | 54 | 55 | so what happens is 56 | 1 - The user opens their browser and requests to open the webpage. 57 | 2 - The server creates rendered content in HTML file and sends it to the user. 58 | 3 - Maeanwhile the static assets can be loaded either from CDN , Edge or Dedicated Servers 59 | 4 - So the user is not trapped in to the Client - server waterfalls means at least it can get the HTML down the wire instead of being blocked waiting for something cocked finished 60 | 61 | With SSR, the website pages are generated at runtime on the server means it needs a runtime to serve those requests like Nodejs. The contents are also up-to-date even th roundtrip still persist from you to make a request and SSR gives you a latest data on server 62 | 63 | we can say like SSR provides a faster load time not build time , ideal for static sites , for SEO since it already made the crawler can index that up but it comes with some cons tho like server costs for data heavy apps , caching might be an issue here, also Time-To-First-Byte is a bit slower because the content is generated on the server for each request but you can prevent this from happening by adding a caching layer with short TTL(Time To Live) to impove the performance becuase you can not deploy it on the Static CDN 64 | 65 | 66 | So RSC and SSR ar not the same thing but they are so complimentary to each other , enabling rendering into an intermediate abstraction format without needing to add to the JavaScript bundle ,this allows us for merging JSX tree node so called server tree with the client tree node without lossing any kind of state and interactivity. 67 | 68 | 69 | ## Server Components - Bad a** niggas 70 | 71 | Those are the components that are render only on the sever. Those are the one that will be streamed down to the client browser. also they are a replacement for SSR but creating a really fast early paint and reduce JS bundles that the client needs to download. this not meant to dump on the JS , still JS is the most important part of it. since you can not avoid it , atleast we make something around and optimize it because **GREAT POWER COMES WITH GREAT CHUNK** 72 | 73 | if you are familiar with Nextjs - yeah it is server component first backend(hmm) framework solving a lof modern web problems. which you optout using `use client` directive to acheive more of client first thing 74 | 75 | Server comp renders before the client so using server component in client causes a waterfall issue (the stuff that comes first - server at a build time before hand). when we say clients we also mean by - client means any one who want to consume the server components may be browsers , another servers origins. One thing to note also the client compoents will be rendered once at compilation with undefined values. 76 | 77 | 78 | So lets see some core concepts and we will see indepth more on part 2 or something like that 79 | 80 | So wheen we talk about RSC we usaully have to talk about the backbone of it , which is Suspensing and Streaming. Let break down them up 81 | 82 | 83 | **Suspensing** is a big pipe architecture adoption, it is all about streaming , handling promises 84 | streaming data and present the UI as soon as they are available. 85 | 86 | ```js 87 | }> 88 | 89 | 90 | ``` 91 | 92 | here on the above we are streaming a data from server to client , also something that could take us sometimee like fetching from remote servers , yeah until all things get resolved when can make sure to display the fallback. 93 | 94 | 95 | **Streaming**: is like parallelism helping in popping the intial shells instead of blocking , yeah server side html streaming and data fetching doing them at parallel is just an optimization. it is like moving from blocking to nonblocking model. 96 | 97 | It is like sending the data bit by bit for the client. 98 | 99 | take a senarios where you display gallary of 100 picture with a given paginated page , so naive way is to block the everything till the data is available and showing spinner as fallback , which is not bad tho .. but what if the image differs in size like having 2 extreme sizes i.e 20MB - the highest and 10KB - the smallest so do you think i should sacrifice the FCP or LCP for this 100 | size issue so another good possible solution will be what if we make size agnostic like we send the a pic as soon it as available and showing a spinner , shimmers or skeleon as fallback for each iamge till loaded intead of showing the same loading spinner for all waiting for all to resolve. so sending data bit by bit and construct html as fly time is suge a huge optimization that is made so far. 101 | when using React Suspense, components would wait until all the data and components in their subtree were ready before rendering anything. This could lead to delays in displaying content to the user, especially if there were asynchronous operations or network requests involved. 102 | 103 | With the streaming feature, React components can start rendering and streaming their content to the client as soon as it's ready, regardless of the completion status of other components or data in the tree. This allows for a more progressive rendering experience, where the user sees partial content being rendered incrementally 104 | 105 | 106 | and Streaming and Suspense are something that goes together well, like for streaming a contents you have to Suspense those who are not loaded properly with fallback. 107 | 108 | ## Use client vs Use server nextjs api 109 | 110 | it does really means the client and servre compoents, it is not even like that 111 | 112 | **Use client** means you are opting out server component(which means acheiving the client compoent), from nextjs default server first component approach and you are telling the bunlder - Turbopack that you need to split this code on seperate client folder so that later if can be fetched easily once we know where we put our serevr code and client codes. 113 | so when ever you need interactivity , you need to optout from using `use client` directive to use client first interactivity. 114 | 115 | **Use server** means not a server compoents but it is the bridge between your server code and client components it like a code that you can generate from client on server like when the form submitted you can use `use server` to kind of bridge the connection between client codee to server code like recording something on db or something . those function exclusively runs on servers but triggered from the client 116 | 117 | 118 | Next up 119 | 120 | - RSC Payloads 121 | - ReactElement VS JSX 122 | - In depth guide on ReactDOM client and server apis for parsing JSX Symtax tree -> HTML 123 | - Suspense Behind the scene like readableStreams , promises , and SQS kind of implementation along with it 124 | - Building Simple RSC framework - if i am fortunate with Nitro + vite with @beka_cru on voice chat on my T[elegram channel](https://t.me/kinfishfarms) 125 | - Strict rules on react 19 - api less vs bundler heavy or strict rules 126 | 127 | Yeah much is coming on the series 128 | 129 | 130 | 131 | wanna collab on this post - hit me up at [Telegram](https://t.me/Kinfe123) or fork the project ena send pr i would love to see you here 132 | 133 | 134 | -------------------------------------------------------------------------------- /content/posts/top-frontend-toos-for-shipping-amazing-web.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Best Frontend Dev Resource - Tailwind Titans 3 | description: This will be introducing the most tool i used for building a amazing and user apealing web and shipping in a sec 4 | image: /images/blogs/ai-2.png 5 | date: "2024-04-20" 6 | authors: 7 | - kinfish 8 | --- 9 | 10 | 11 | 12 | In this blog post, we'll dive into the world of most of Tailwind UI-based component libraries and UI utilities. Tailwind CSS has gained immense popularity in the web development community for its utility-first approach to styling, and many developers have leveraged this framework to create comprehensive component libraries and UI tools. 13 | 14 | 15 | 16 | So let cook them together 17 | 18 | 19 | ## Shadcn/ui 20 | 21 | [**Shadcn**](https://ui.shadcn.com) - is not ui library but ,If there's one Tailwind UI library that straight-up dominated the scene in 2023, it's gotta be shadcn/ui, man. This bad boy is built on top of Tailwind CSS and Radix UI as a primitive, and it's bringing a whole new approach to the game – you just copy and paste the code for any component you need right into your project, giving you full ownership and control. The trade-off is you won't get those automatic updates, so your dev team's gotta be on point to handle the maintenance, but if you've got the chops, this level of customization is gonna be a game-changer, letting you make those components look and feel exactly how you want. 22 | 23 | 24 | btw i got got a couple of pr i made the both for feat: and fix: hopefully they will live soon 25 | 26 | Image 31 | 32 | 33 | ## NextUI 34 | [**Nextui**](https://nextui.org) - Yo, despite the name, Next UI has got nothin' to do with Next.js, my man. But don't sleep on this bad boy – since v2.0, it's been built on the unstoppable combo of Tailwind CSS and React Aria, and it's one of the fastest-growing Tailwind-based UI libraries out there, hands down. The deal with Next UI is simple: you just import the React components from the @nextui-org/react npm package and start using 'em in your app. No extra hassle, no hoops to jump through – just straight-up, high-powered UI components ready to level up your project. And let me tell you, these components are clean, they're versatile, and they're packed with features that'll have your users sayin', "Damn, this is smooth." Tremor, another Tailwind-powered library, might get some shine, but Next UI is really takin' the scene by storm right now. If you're lookin' to bring some next-level UI to your app, this is the way to go, my friend. 35 | 36 | Image 42 | 43 | ## Preline 44 | 45 | [**Preline**](https://preline.co) - If you're talkin' about Tailwind UI libraries that'll have your project lookin' fresh as hell, you gotta put Preline on your radar, my dude. This bad boy's got the biggest free set of Tailwind component examples out there – we're talkin' over 60 components and 170 sections, all built to perfection and ready to take your app to the next level. And the best part? Every single one of 'em comes with full dark mode support, so you can make your UI shine no matter what mode your users prefer. Preline is straight-up the Tailwind UI powerhouse you need to elevate your project and have your users bein' like, "Damn, this is clean! 46 | 47 | Image 53 | 54 | 55 | 56 | ## Hover.dev 57 | 58 | 59 | [**Hover.dev**](https://hover.dev) - If you're lookin' to take your UI game to the next level with some dope-as-hell animated components, you gotta check out HoverDev, my friend. This platform is straight-up empowerin' users with the power of Framer Motion, servin' up a killer collection of animated UI blocks that you can just copy and paste right into your projects. We're talkin' interactive components that'll have your users bein' like, "Damn, this is smooth!" And the best part? HoverDev's got a pricing structure that'll let you unlock even more advanced, heavily-animated components if you need 'em. Whether you're tryna keep it free and basic or you wanna go all-in on that premium, next-level interactivity, HoverDev's got you covered with a solution that'll make your UI shine brighter than the sun 60 | 61 | Image 67 | 68 | 69 | ## ParkUi 70 | [**ParkUI**](https://park-ui.com) - Let me break down the deal with Park UI, fam. This Tailwind library might be relatively new on the scene, but it's a serious contender to the popular shadcn/ui, no doubt. The approach is similar in terms of coupling with Tailwind, but Park UI's got way more versatility goin' on. See, this bad boy comes with first-class support for both Tailwind CSS and Panda CSS - that's another atomic CSS library that takes a JavaScript-first approach. And on top of that, Park UI integrates seamlessly with React, Vue, and Solid via Ark UI, a headless UI library that's got official implementations for all those frameworks. So whether you're workin' with Tailwind, Panda CSS, or any of the major front-end frameworks, Park UI's got you covered with a consistent, high-quality set of components to level up your UI game. This library's bringin' the heat, my dude - definitely worth checkin' out if you wanna keep your options open and have a versatile Tailwind solution in your toolkit.R 71 | 72 | 73 | 74 | Image 80 | 81 | 82 | ## Aceternity UI 83 | 84 | [**Aceternity**](https://ui.aceternity.com/) - We got Aceternity UI which is kind of similar with Hover.dev here and it's unlike your typical UI component libraries you've seen before. This collection of bespoke and meticulously crafted UI sections is built on top of the powerhouse duo of Tailwind CSS and Framer Motion. The brains behind this is the amazing Manu Arora, who's really brought something special to the table. Instead of the same old generic components, Aceternity UI delivers a unique set of UI pieces that'll make your projects stand out. If you're looking to elevate your Tailwind game with some next-level interactive and visually stunning UI, Aceternity UI is definitely worth checking out. This isn't your average off-the-shelf solution - it's a curated library of custom-built components that'll have your users sayin' "Whoa, that's fresh!" 85 | 86 | Image 91 | 92 | 93 | ## Flowbite 94 | 95 | [**Flowbite**](https://flowbite.com) - This open-source library is straight-up bringin' the heat with over 600 UI components, sections, and pages - all built using the utility classes from Tailwind CSS and meticulously designed in Figma. If you're tryna start developing some killer user interfaces, Flowbite's got your back. It's packed with a massive selection of pre-built UI blocks that you can just plug and play into your projects. And the best part? It's all built on the solid foundation of Tailwind CSS, so you know it's gonna be easy to customize and integrate with your workflow. Whether you need components, sections, or full-blown page templates, Flowbite's got you covered. This library's a one-stop-shop for leveling up your Tailwind-powered UI development game 96 | 97 | 98 | Image 103 | 104 | 105 | 106 | ## TailwindUI 107 | 108 | [**TailwindUI**](https://tailwindui.com) - Yo, check out Tailwind UI if you wanna take your Tailwind CSS game to the next level. This collection of expertly crafted components and templates is brought to you by the same crew behind Tailwind CSS. We're talkin' a fully-fledged website built with TypeScript and JavaScript, currently serving as the core design system and library for well-known startups and companies. These meticulously designed components and templates seamlessly integrate with Tailwind, packed with advanced features to build killer UIs. Whether you need nav bars, card layouts, or form elements, Tailwind UI's got you covered. It's the ultimate toolkit for crafting top-notch user experiences on the solid foundation of Tailwind CSS. 109 | 110 | 111 | 112 | Image 117 | 118 | 119 | ## DaisyUI 120 | 121 | [**DaisyUI**](https://daisyui.com/) - i dont like it personally , tailwinded bootstrap kind of it , but it deos a good job on locking you to it , but it is the most popular one fam , using semantic class name instead of tailwindcss because of the thing fewer classanme , fast dev , small bundle size 122 | Image 127 | 128 | 129 | 130 | ## HyperUI 131 | [**HyperUI**](https://www.hyperui.dev/) - HyperUI, fam. This collection of free, copy-pastable Tailwind CSS components has been around since 2021, and it's pretty similar to Tailwind UI in terms of what it offers. You got your application, marketing, and e-commerce website components and sections, all ready for you to just copy and paste into your projects. The best part? There's nothing to install, so you can easily integrate it with any headless UI library you're workin' with. No fuss, no muss – just pure HTML/CSS that you can plug right in and get your development goin'. If you're tryna speed up your Tailwind-powered projects without sacrificing quality, HyperUI could be the way to go. It's a great resource for quickly building out UI elements, so you can focus on the rest of your app or website 132 | Image 137 | 138 | 139 | 140 | ## v0.dev 141 | [**v0.dev**](https://v0.dev/) - Yo, have you heard about shadcn/ui? This bad boy is a game-changer for your Tailwind-powered development projects. It's like having a personal UI designer on your team, but instead of sketching out designs, you just hit it with some simple text prompts or even images, and boom – it generates the code for you. And the best part? You can keep iterating on that UI, refining the look and feel until you've got the perfect components for your app or website. No more endless hours spent perfecting every little detail – shadcn/ui handles all that for you, so you can focus on the bigger picture. Just copy and paste the generated code, or add the component straight through the CLI – it's that easy. If you're serious about leveling up your Tailwind game, you gotta check out shadcn/ui. It's the ultimate UI generation tool that's gonna have your projects lookin' fresh AF. 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | Image 154 | 155 | 156 | 157 | 158 | Trust me if you compose all the power of each , you can really build amazing as fast as possible. 159 | 160 | This is the most of them i used to build a good looking smooth website, but since there is a lot more i used other than , i will still keep mention their link down below so that you can expore about fam. 161 | 162 | - https://ui.ibelick.com/ 163 | - https://bg.ibelick.com/ 164 | - https://uiverse.io/ 165 | 166 | 167 | .... this list could be from you guys to add on so make sure to send a pr over [**here**](https://github.com/Kinfe123/kinfish-dumpy/blob/main/content/posts/top-frontend-toos-for-shipping-amazing-web.mdx) if you would like to have tool that fams can be using it. 168 | 169 | 170 | 171 | 172 | if you would like to reach me for anything - you can ping me on my email - [**kinfetare83@gmail.com**](mailto:kinfetare83@gmail.com) 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /contentlayer.config.js: -------------------------------------------------------------------------------- 1 | import { defineDocumentType, makeSource } from "contentlayer/source-files"; 2 | import rehypeAutolinkHeadings from "rehype-autolink-headings"; 3 | import rehypePrettyCode from "rehype-pretty-code"; 4 | import rehypeSlug from "rehype-slug"; 5 | import remarkGfm from "remark-gfm"; 6 | 7 | /** @type {import('contentlayer/source-files').ComputedFields} */ 8 | const computedFields = { 9 | slug: { 10 | type: "string", 11 | resolve: (doc) => `/${doc._raw.flattenedPath}`, 12 | }, 13 | slugAsParams: { 14 | type: "string", 15 | resolve: (doc) => doc._raw.flattenedPath.split("/").slice(1).join("/"), 16 | }, 17 | readTime: { 18 | type: "number", 19 | resolve: (doc) => { 20 | const content = doc.body.raw 21 | const wordsPerMinute = 210 22 | const numberOfWords = content.split(/\s/g).length 23 | const minutes = numberOfWords / wordsPerMinute 24 | return Math.ceil(minutes) 25 | }, 26 | }, 27 | 28 | }; 29 | 30 | export const Page = defineDocumentType(() => ({ 31 | name: "Page", 32 | filePathPattern: `pages/**/*.mdx`, 33 | contentType: "mdx", 34 | fields: { 35 | title: { 36 | type: "string", 37 | required: true, 38 | }, 39 | description: { 40 | type: "string", 41 | }, 42 | }, 43 | computedFields, 44 | })); 45 | export const Author = defineDocumentType(() => ({ 46 | name: "Author", 47 | filePathPattern: `authors/**/*.mdx`, 48 | contentType: "mdx", 49 | fields: { 50 | name: { 51 | type: "string", 52 | require: true, 53 | }, 54 | description: { 55 | type: "string", 56 | require: true, 57 | }, 58 | avatar: { 59 | type: "string", 60 | require: true, 61 | }, 62 | twitter: { 63 | type: "string", 64 | require: true, 65 | }, 66 | }, 67 | computedFields, 68 | })); 69 | export const Post = defineDocumentType(() => ({ 70 | name: "Post", 71 | filePathPattern: `posts/**/*.mdx`, 72 | contentType: "mdx", 73 | fields: { 74 | title: { 75 | type: "string", 76 | required: true, 77 | }, 78 | description: { 79 | type: "string", 80 | }, 81 | date: { 82 | type: "date", 83 | required: true, 84 | }, 85 | published: { 86 | type: "boolean", 87 | default: true, 88 | 89 | }, 90 | image: { 91 | type: "string", 92 | required: true, 93 | }, 94 | authors: { 95 | type: "list", 96 | of: { type: "string" }, 97 | required: true, 98 | }, 99 | }, 100 | computedFields, 101 | })); 102 | 103 | export default makeSource({ 104 | contentDirPath: "./content", 105 | documentTypes: [Post, Page, Author], 106 | 107 | mdx: { 108 | remarkPlugins: [remarkGfm], 109 | rehypePlugins: [ 110 | rehypeSlug, 111 | [ 112 | rehypePrettyCode, 113 | { 114 | theme: "github-dark", 115 | onVisitLine(node) { 116 | // Prevent lines from collapsing in `display: grid` mode, and allow empty 117 | // lines to be copy/pasted 118 | if (node.children.length === 0) { 119 | node.children = [{ type: "text", value: " " }]; 120 | } 121 | }, 122 | onVisitHighlightedLine(node) { 123 | node.properties.className.push("line--highlighted"); 124 | }, 125 | onVisitHighlightedWord(node) { 126 | node.properties.className = ["word--highlighted"]; 127 | }, 128 | }, 129 | ], 130 | [ 131 | rehypeAutolinkHeadings, 132 | { 133 | properties: { 134 | className: ["subheading-anchor"], 135 | ariaLabel: "Link to section", 136 | }, 137 | }, 138 | ], 139 | ], 140 | }, 141 | }); 142 | -------------------------------------------------------------------------------- /db/actions/index.ts: -------------------------------------------------------------------------------- 1 | 'use server' 2 | 3 | 4 | export const increment = () => { 5 | 6 | } -------------------------------------------------------------------------------- /db/actions/save.ts: -------------------------------------------------------------------------------- 1 | "use server"; 2 | 3 | export const countReq = async () => { 4 | // to be implemented 5 | }; 6 | -------------------------------------------------------------------------------- /db/index.tsx: -------------------------------------------------------------------------------- 1 | import { drizzle } from 'drizzle-orm/postgres-js' 2 | import postgres from 'postgres' 3 | 4 | 5 | const connectionString = process.env.DATABASE_URL 6 | 7 | const client = postgres(connectionString!) 8 | export const db = drizzle(client); 9 | 10 | -------------------------------------------------------------------------------- /db/migrations/0000_dear_squirrel_girl.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS "visitor" ( 2 | "id" serial NOT NULL, 3 | "name" text 4 | ); 5 | -------------------------------------------------------------------------------- /db/migrations/meta/0000_snapshot.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "cb7f15bc-a896-4ada-9614-fb65427811b5", 3 | "prevId": "00000000-0000-0000-0000-000000000000", 4 | "version": "5", 5 | "dialect": "pg", 6 | "tables": { 7 | "visitor": { 8 | "name": "visitor", 9 | "schema": "", 10 | "columns": { 11 | "id": { 12 | "name": "id", 13 | "type": "serial", 14 | "primaryKey": false, 15 | "notNull": true 16 | }, 17 | "name": { 18 | "name": "name", 19 | "type": "text", 20 | "primaryKey": false, 21 | "notNull": false 22 | } 23 | }, 24 | "indexes": {}, 25 | "foreignKeys": {}, 26 | "compositePrimaryKeys": {}, 27 | "uniqueConstraints": {} 28 | } 29 | }, 30 | "enums": {}, 31 | "schemas": {}, 32 | "_meta": { 33 | "columns": {}, 34 | "schemas": {}, 35 | "tables": {} 36 | } 37 | } -------------------------------------------------------------------------------- /db/migrations/meta/_journal.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "5", 3 | "dialect": "mysql", 4 | "entries": [ 5 | { 6 | "idx": 0, 7 | "version": "5", 8 | "when": 1704140027510, 9 | "tag": "0000_dear_squirrel_girl", 10 | "breakpoints": true 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /db/schema.ts: -------------------------------------------------------------------------------- 1 | import { serial, text, timestamp, pgTable } from "drizzle-orm/pg-core"; 2 | 3 | export var visitor = pgTable("visitor", { 4 | id: serial("id"), 5 | name: text("name"), 6 | }); 7 | export var guesser = pgTable("guesser", { 8 | id: serial("id"), 9 | name: text("name"), 10 | phone: text("phone"), 11 | guess: text("guess"), 12 | }); 13 | export var subscribers = pgTable("subscribers", { 14 | id: serial("id"), 15 | name: text("name"), 16 | email: text("email"), 17 | createdAt: timestamp("created_at").defaultNow().notNull(), 18 | }); 19 | -------------------------------------------------------------------------------- /drizzle.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'drizzle-kit'; 2 | // import 'dotenv/config'; 3 | 4 | if (!process.env.DATABASE_URL) { 5 | throw new Error('DATABASE_URL environment variable is required.'); 6 | } 7 | 8 | export default { 9 | schema: './db/schema.ts', 10 | out: './db/migrations', 11 | driver: 'pg', 12 | dbCredentials: { 13 | 14 | connectionString: process.env.DATABASE_URL 15 | // connectionString: process.env.DATABASE_URL, 16 | }, 17 | } satisfies Config; -------------------------------------------------------------------------------- /lib/email-helper.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | 3 | import nodemailer from "nodemailer"; 4 | 5 | export const transporter = nodemailer.createTransport({ 6 | service: "gmail", 7 | auth: { 8 | user: "kinfishfarms@gmail.com", 9 | pass: process.env.EMAIL_PASSWORD, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /lib/locals.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/mdx-helper.ts: -------------------------------------------------------------------------------- 1 | import { allPosts } from "@/.contentlayer/generated"; 2 | import { Redis } from "@upstash/redis"; 3 | import { compareDesc } from "date-fns"; 4 | import { sumNums } from "./utils"; 5 | 6 | const redis = Redis.fromEnv(); 7 | export const getSlugs = () => { 8 | const posts = allPosts 9 | .filter((post) => post.date) 10 | .sort((a, b) => { 11 | return compareDesc(new Date(a.date), new Date(b.date)); 12 | }); 13 | 14 | return posts; 15 | }; 16 | 17 | export const getViewCount = async () => { 18 | const allSlugs = getSlugs().map((p) => `pageviews:projects:${p.slug}`); 19 | const allViews = await redis.mget<(number | null)[]>(...allSlugs); 20 | // @ts-ignore 21 | return sumNums(allViews) 22 | }; 23 | -------------------------------------------------------------------------------- /lib/useMouse.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | interface MousePosition { 4 | x: number; 5 | y: number; 6 | } 7 | 8 | export function useMousePosition(): MousePosition { 9 | const [mousePosition, setMousePosition] = useState({ 10 | x: 0, 11 | y: 0, 12 | }); 13 | 14 | useEffect(() => { 15 | const handleMouseMove = (event: MouseEvent) => { 16 | setMousePosition({ x: event.clientX, y: event.clientY }); 17 | }; 18 | 19 | window.addEventListener("mousemove", handleMouseMove); 20 | 21 | return () => { 22 | window.removeEventListener("mousemove", handleMouseMove); 23 | }; 24 | }, []); 25 | 26 | return mousePosition; 27 | } -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | 8 | 9 | export function formatDate(input: string | number): string { 10 | const date = new Date(input) 11 | return date.toLocaleDateString("en-US", { 12 | month: "long", 13 | day: "numeric", 14 | year: "numeric", 15 | }) 16 | } 17 | 18 | export function absoluteUrl(path: string) { 19 | return `${process.env.NEXT_PUBLIC_APP_URL}${path}` 20 | } 21 | 22 | 23 | 24 | export function sumNums(array: number[]) { 25 | let sum = 0 26 | for(let i=0; i -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /site/nav.tsx: -------------------------------------------------------------------------------- 1 | import { IconHome, IconMessage, IconUser } from "@tabler/icons-react"; 2 | export const navItems = [ 3 | { 4 | name: "Home", 5 | link: "/", 6 | icon: , 7 | }, 8 | { 9 | name: "Blog", 10 | link: "/posts", 11 | icon: , 12 | }, 13 | { 14 | name: "DX", 15 | link: "/dx", 16 | icon: , 17 | }, 18 | ]; 19 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | // const defaultTheme = require("tailwindcss/defaultTheme"); 2 | // const colors = require("tailwindcss/colors"); 3 | const { 4 | default: flattenColorPalette, 5 | } = require("tailwindcss/lib/util/flattenColorPalette"); 6 | const svgToDataUri = require("mini-svg-data-uri"); 7 | 8 | const colors = require("tailwindcss/colors"); 9 | 10 | /** @type {import('tailwindcss').Config} */ 11 | module.exports = { 12 | darkMode: ["class"], 13 | content: [ 14 | "./pages/**/*.{ts,tsx}", 15 | "./components/**/*.{ts,tsx}", 16 | "./app/**/*.{ts,tsx}", 17 | "./src/**/*.{ts,tsx}", 18 | ], 19 | prefix: "", 20 | theme: { 21 | container: { 22 | center: true, 23 | padding: "2rem", 24 | screens: { 25 | "2xl": "1400px", 26 | }, 27 | }, 28 | extend: { 29 | colors: { 30 | border: "hsl(var(--border))", 31 | input: "hsl(var(--input))", 32 | ring: "hsl(var(--ring))", 33 | background: "hsl(var(--background))", 34 | foreground: "hsl(var(--foreground))", 35 | primary: { 36 | DEFAULT: "hsl(var(--primary))", 37 | foreground: "hsl(var(--primary-foreground))", 38 | }, 39 | secondary: { 40 | DEFAULT: "hsl(var(--secondary))", 41 | foreground: "hsl(var(--secondary-foreground))", 42 | }, 43 | destructive: { 44 | DEFAULT: "hsl(var(--destructive))", 45 | foreground: "hsl(var(--destructive-foreground))", 46 | }, 47 | muted: { 48 | DEFAULT: "hsl(var(--muted))", 49 | foreground: "hsl(var(--muted-foreground))", 50 | }, 51 | accent: { 52 | DEFAULT: "hsl(var(--accent))", 53 | foreground: "hsl(var(--accent-foreground))", 54 | }, 55 | popover: { 56 | DEFAULT: "hsl(var(--popover))", 57 | foreground: "hsl(var(--popover-foreground))", 58 | }, 59 | card: { 60 | DEFAULT: "hsl(var(--card))", 61 | foreground: "hsl(var(--card-foreground))", 62 | }, 63 | }, 64 | 65 | fontFamily: { 66 | heading: ["var(--font-heading)"], 67 | headingAlt: ["var(--font-headingAlt)"], 68 | subheading: ["var(--font-subheading)"], 69 | subalt: ["var(--font-subalt)"], 70 | }, 71 | 72 | borderRadius: { 73 | lg: "var(--radius)", 74 | md: "calc(var(--radius) - 2px)", 75 | sm: "calc(var(--radius) - 4px)", 76 | }, 77 | keyframes: { 78 | spotlight: { 79 | "0%": { 80 | opacity: 0, 81 | transform: "translate(-72%, -62%) scale(0.5)", 82 | }, 83 | "100%": { 84 | opacity: 1, 85 | transform: "translate(-50%,-40%) scale(1)", 86 | }, 87 | }, 88 | "accordion-down": { 89 | from: { height: "0" }, 90 | to: { height: "var(--radix-accordion-content-height)" }, 91 | }, 92 | 93 | "accordion-up": { 94 | from: { height: "var(--radix-accordion-content-height)" }, 95 | to: { height: "0" }, 96 | }, 97 | }, 98 | animation: { 99 | spotlight: "spotlight 2s ease .75s 1 forwards", 100 | "accordion-down": "accordion-down 0.2s ease-out", 101 | "accordion-up": "accordion-up 0.2s ease-out", 102 | }, 103 | }, 104 | }, 105 | plugins: [ 106 | require("tailwindcss-animate"), 107 | require("@tailwindcss/typography"), 108 | require("@tailwindcss/aspect-ratio"), 109 | addVariablesForColors, 110 | function ({ matchUtilities, theme }) { 111 | matchUtilities( 112 | { 113 | "bg-grid": (value) => ({ 114 | backgroundImage: `url("${svgToDataUri( 115 | `` 116 | )}")`, 117 | }), 118 | "bg-grid-small": (value) => ({ 119 | backgroundImage: `url("${svgToDataUri( 120 | `` 121 | )}")`, 122 | }), 123 | "bg-dot": (value) => ({ 124 | backgroundImage: `url("${svgToDataUri( 125 | `` 126 | )}")`, 127 | }), 128 | }, 129 | { values: flattenColorPalette(theme("backgroundColor")), type: "color" } 130 | ); 131 | } 132 | ], 133 | }; 134 | 135 | function addVariablesForColors({ addBase, theme }) { 136 | let allColors = flattenColorPalette(theme("colors")); 137 | let newVars = Object.fromEntries( 138 | Object.entries(allColors).map(([key, val]) => [`--${key}`, val]) 139 | ); 140 | 141 | addBase({ 142 | ":root": newVars, 143 | }); 144 | } 145 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "baseUrl": ".", 23 | "paths": { 24 | "@/*": ["./*"], 25 | "contentlayer/generated": ["./.contentlayer/generated"] 26 | } 27 | }, 28 | "include": [ 29 | "next-env.d.ts", 30 | "**/*.ts", 31 | "**/*.tsx", 32 | ".next/types/**/*.ts", 33 | ".contentlayer/generated" 34 | ], 35 | "exclude": ["node_modules"] 36 | } 37 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "pipeline": { 4 | "build": { 5 | "outputs": [".next/**", "!.next/cache/**"] 6 | }, 7 | "type-check": {} 8 | } 9 | } 10 | --------------------------------------------------------------------------------