From 0790fd08948d5e648efb78692a133fbf9262ef59 Mon Sep 17 00:00:00 2001 From: fgrreloaded Date: Sat, 22 Mar 2025 20:54:46 +0530 Subject: [PATCH] Add TechShowcase component to display technology stack --- .../src/app/(home)/_components/TechMatrix.tsx | 379 ++++++++++++++++++ .../app/(home)/_components/TechShowcase.tsx | 206 ++++++++++ apps/web/src/app/(home)/page.tsx | 4 +- 3 files changed, 587 insertions(+), 2 deletions(-) create mode 100644 apps/web/src/app/(home)/_components/TechMatrix.tsx create mode 100644 apps/web/src/app/(home)/_components/TechShowcase.tsx diff --git a/apps/web/src/app/(home)/_components/TechMatrix.tsx b/apps/web/src/app/(home)/_components/TechMatrix.tsx new file mode 100644 index 0000000..11ca314 --- /dev/null +++ b/apps/web/src/app/(home)/_components/TechMatrix.tsx @@ -0,0 +1,379 @@ +import { AnimatePresence, motion } from "framer-motion"; +import { useEffect, useState } from "react"; + +interface TechItem { + name: string; + description: string; + category: "frontend" | "backend" | "database" | "tooling" | "deployment"; + logo?: string; + color?: string; +} + +const techStack: TechItem[] = [ + { + name: "Next.js", + description: "React framework for production", + category: "frontend", + logo: "/tech/nextjs.svg", + color: "#ffffff", + }, + { + name: "TypeScript", + description: "Strongly typed programming language", + category: "frontend", + logo: "/tech/typescript.svg", + color: "#3178c6", + }, + { + name: "tRPC", + description: "End-to-end typesafe APIs", + category: "backend", + logo: "/tech/trpc.svg", + color: "#398CCB", + }, + { + name: "Tailwind CSS", + description: "Utility-first CSS framework", + category: "frontend", + logo: "/tech/tailwind.svg", + color: "#38bdf8", + }, + { + name: "Prisma", + description: "Next-generation ORM", + category: "database", + logo: "/tech/prisma.svg", + color: "#5a67d8", + }, + { + name: "PostgreSQL", + description: "Advanced open source database", + category: "database", + logo: "/tech/postgresql.svg", + color: "#336791", + }, + { + name: "Zod", + description: "TypeScript-first schema validation", + category: "backend", + logo: "/tech/zod.svg", + color: "#3E67B1", + }, + { + name: "Auth.js", + description: "Authentication for the web", + category: "backend", + logo: "/tech/authjs.svg", + color: "#32383E", + }, + { + name: "Turborepo", + description: "High-performance build system", + category: "tooling", + logo: "/tech/turborepo.svg", + color: "#EF4444", + }, + { + name: "Docker", + description: "Containerization platform", + category: "deployment", + logo: "/tech/docker.svg", + color: "#2496ED", + }, + { + name: "ESLint", + description: "Pluggable JavaScript linter", + category: "tooling", + logo: "/tech/eslint.svg", + color: "#4B32C3", + }, + { + name: "Prettier", + description: "Opinionated code formatter", + category: "tooling", + logo: "/tech/prettier.svg", + color: "#F7B93E", + }, +]; + +export default function TechMatrix() { + const [selectedCategory, setSelectedCategory] = useState(null); + const [cursorPosition, setCursorPosition] = useState({ x: 0, y: 0 }); + const [typedCommand, setTypedCommand] = useState(""); + const [isTyping, setIsTyping] = useState(false); + const fullCommand = "show tech-stack --category all"; + + // biome-ignore lint/correctness/useExhaustiveDependencies: + useEffect(() => { + if (isTyping) return; + + setIsTyping(true); + let index = 0; + + const typeInterval = setInterval(() => { + if (index < fullCommand.length) { + setTypedCommand(fullCommand.substring(0, index + 1)); + index++; + } else { + clearInterval(typeInterval); + } + }, 80); + + return () => clearInterval(typeInterval); + }, []); + + const categories = Array.from( + new Set(techStack.map((item) => item.category)), + ); + + const filteredTech = selectedCategory + ? techStack.filter((tech) => tech.category === selectedCategory) + : techStack; + + const handleMouseMove = (e: React.MouseEvent) => { + const rect = e.currentTarget.getBoundingClientRect(); + setCursorPosition({ + x: e.clientX - rect.left, + y: e.clientY - rect.top, + }); + }; + + return ( +
+ {/* Floating particles effect */} +
+ {[...Array(6)].map((_, i) => ( +
+ key={i} + className="absolute rounded-full bg-blue-500/10 blur-xl" + style={{ + width: `${Math.random() * 200 + 50}px`, + height: `${Math.random() * 200 + 50}px`, + top: `${Math.random() * 100}%`, + left: `${Math.random() * 100}%`, + animation: `float ${Math.random() * 10 + 10}s linear infinite`, + opacity: Math.random() * 0.5, + }} + /> + ))} +
+ + {/* Main container */} + + {/* Gradient border effect */} +
+
+
+ + {/* Terminal header */} +
+
+
+
+
+
+
+ user@better-t-stack + : + ~/tech-matrix + $ +
+
v1.0.0
+
+ +
+ {/* Command line interface effect */} +
+ $ + {typedCommand} + {/* biome-ignore lint/style/useSelfClosingElements: */} + +
+ + {/* Category filters */} + + {/* biome-ignore lint/style/useSelfClosingElements: */} +
+ {/* biome-ignore lint/a11y/useButtonType: */} + + + {categories.map((category) => ( + // biome-ignore lint/a11y/useButtonType: + + ))} +
+ + {/* Tech stack display */} +
+
+ + {/* biome-ignore lint/style/noUnusedTemplateLiteral: */} +
{`// Better-T Stack Tech Matrix`}
+ {/* biome-ignore lint/style/noUnusedTemplateLiteral: */} +
{`const techStack = {`}
+ + + + {filteredTech.map((tech, index) => ( + +
+
+
+ {tech.logo && ( +
+
+
+ )} +
+
+ + {tech.name} + + : + + "{tech.description}" + + {index < filteredTech.length - 1 && ( + , + )} +
+
+
+ {`// ${tech.category}`} + + [installed] + +
+ +
+
+ + ))} + + + + {/* biome-ignore lint/style/noUnusedTemplateLiteral: */} +
{`};`}
+ + {/* Terminal footer */} +
+
+ $ run better-t-stack + --with-typesafety +
+
+ Ready for deployment... +
+
+
+
+
+ + {/* Add animated style tag for custom animations */} + +
+ ); +} diff --git a/apps/web/src/app/(home)/_components/TechShowcase.tsx b/apps/web/src/app/(home)/_components/TechShowcase.tsx new file mode 100644 index 0000000..6aa4c2e --- /dev/null +++ b/apps/web/src/app/(home)/_components/TechShowcase.tsx @@ -0,0 +1,206 @@ +import { motion } from "framer-motion"; +import React, { useState } from "react"; + +interface TechItem { + name: string; + description: string; + category: "frontend" | "backend" | "database" | "tooling" | "deployment"; +} + +const techStack: TechItem[] = [ + { + name: "Next.js", + description: "React framework for production", + category: "frontend", + }, + { + name: "TypeScript", + description: "Strongly typed programming language", + category: "frontend", + }, + { + name: "tRPC", + description: "End-to-end typesafe APIs", + category: "backend", + }, + { + name: "Tailwind CSS", + description: "Utility-first CSS framework", + category: "frontend", + }, + { name: "Prisma", description: "Next-generation ORM", category: "database" }, + { + name: "PostgreSQL", + description: "Advanced open source database", + category: "database", + }, + { + name: "Zod", + description: "TypeScript-first schema validation", + category: "backend", + }, + { + name: "Auth.js", + description: "Authentication for the web", + category: "backend", + }, + { + name: "Turborepo", + description: "High-performance build system", + category: "tooling", + }, + { + name: "Docker", + description: "Containerization platform", + category: "deployment", + }, + { + name: "ESLint", + description: "Pluggable JavaScript linter", + category: "tooling", + }, + { + name: "Prettier", + description: "Opinionated code formatter", + category: "tooling", + }, +]; + +const categoryIcons = { + frontend: "🖥️", + backend: "⚙️", + database: "🗄️", + tooling: "🔧", + deployment: "🚀", +}; + +export default function TechShowcase() { + const [activeCategory, setActiveCategory] = useState(null); + + const categories = Array.from( + new Set(techStack.map((item) => item.category)), + ); + + const filteredTech = activeCategory + ? techStack.filter((tech) => tech.category === activeCategory) + : techStack; + + const groupedTech = !activeCategory + ? categories.map((category) => ({ + category, + items: techStack.filter((tech) => tech.category === category), + })) + : null; + + return ( +
+
+ {/* biome-ignore lint/a11y/useButtonType: */} + + + {categories.map((category) => ( + // biome-ignore lint/a11y/useButtonType: + + ))} +
+ + {activeCategory && ( +
+ {filteredTech.map((tech) => ( + +

+ {tech.name} +

+

{tech.description}

+
+ --package={tech.name.toLowerCase()} +
+
+ ))} +
+ )} + + {!activeCategory && groupedTech && ( +
+ {groupedTech.map((group) => ( +
+
+
+ {categoryIcons[group.category as keyof typeof categoryIcons]} +
+

+ {group.category}/ +

+
+ +
+
+ {group.items.map((tech) => ( + +
+

+ {tech.name} +

+
+ core +
+
+

+ {tech.description} +

+
+ + include: true + + {/* biome-ignore lint/style/useSelfClosingElements: */} + +
+
+ ))} +
+
+
+ ))} +
+ )} + +
+
+ $ The perfect tech stack, + carefully selected for{" "} + maximum developer happiness +
+
+
+ ); +} diff --git a/apps/web/src/app/(home)/page.tsx b/apps/web/src/app/(home)/page.tsx index 232c337..d0610db 100644 --- a/apps/web/src/app/(home)/page.tsx +++ b/apps/web/src/app/(home)/page.tsx @@ -4,7 +4,7 @@ import React from "react"; import CodeContainer from "./_components/CodeContainer"; import CustomizableSection from "./_components/CustomizableSection"; import NpmPackage from "./_components/NpmPackage"; -import TechConstellation from "./_components/TechConstellation"; +import TechShowcase from "./_components/TechShowcase"; // import TerminalDisplay from "./_components/Terminal"; import Testimonials from "./_components/Testimonials"; @@ -86,7 +86,7 @@ export default function HomePage() { {/*
*/}
- +