added terminal design and tech stack

This commit is contained in:
fgrreloaded
2025-02-16 14:56:18 +05:30
parent e5badb108c
commit d31b03bf77
8 changed files with 358 additions and 8 deletions

View File

@@ -55,10 +55,8 @@ const Navbar = () => {
</div>
<div
className={`flex items-center rounded-full border border-white/10 py-1 px-1.5 text-sm relative transition-all duration-500 ease-out ${
scrolled
? "bg-white/5 backdrop-blur-md w-[470px]"
: "bg-transparent w-[335px]"
className={`flex items-center backdrop-blur-md bg-white/5 rounded-full border border-white/10 py-1 px-1.5 text-sm relative transition-all duration-500 ease-out ${
scrolled ? "w-[470px]" : "w-[335px]"
}`}
>
<div

View File

@@ -0,0 +1,163 @@
"use client";
import { technologies } from "@/lib/constant";
import { useEffect, useRef, useState } from "react";
type TechConstellationProp = {
fromRef: React.RefObject<HTMLElement>;
toRef: React.RefObject<HTMLElement>;
containerRef: React.RefObject<HTMLElement>;
delay?: number;
};
const AnimatedBeam = ({
fromRef,
toRef,
containerRef,
delay = 0,
}: TechConstellationProp) => {
const [path, setPath] = useState("");
useEffect(() => {
const updatePath = () => {
if (!fromRef.current || !toRef.current || !containerRef.current) return;
const containerRect = containerRef.current.getBoundingClientRect();
const fromRect = fromRef.current.getBoundingClientRect();
const toRect = toRef.current.getBoundingClientRect();
const fromX = fromRect.left - containerRect.left + fromRect.width / 2;
const fromY = fromRect.top - containerRect.top + fromRect.height / 2;
const toX = toRect.left - containerRect.left + toRect.width / 2;
const toY = toRect.top - containerRect.top + toRect.height / 2;
setPath(
`M ${fromX},${fromY} Q ${(fromX + toX) / 2},${(fromY + toY) / 2 - 50} ${toX},${toY}`,
);
};
updatePath();
window.addEventListener("resize", updatePath);
return () => window.removeEventListener("resize", updatePath);
}, [fromRef, toRef, containerRef]);
return (
<svg className="absolute top-0 left-0 w-full h-full pointer-events-none">
<title>Tech Stack</title>
<path
d={path}
fill="none"
stroke="url(#gradient)"
strokeWidth="2"
className="opacity-50"
>
<animate
attributeName="stroke-dasharray"
values="0,1000;1000,0"
dur="3s"
begin={`${delay}s`}
repeatCount="indefinite"
/>
</path>
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor="#3B82F6" stopOpacity="0" />
<stop offset="50%" stopColor="#3B82F6" />
<stop offset="100%" stopColor="#3B82F6" stopOpacity="0" />
</linearGradient>
</defs>
</svg>
);
};
const TechConstellation = () => {
const containerRef = useRef<HTMLDivElement>(null);
const centerRef = useRef<HTMLDivElement>(null);
const techRefs = useRef<{ [key: string]: HTMLDivElement | null }>({});
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
setIsVisible(true);
}, []);
return (
<div
ref={containerRef}
className="relative w-full h-screen bg-gradient-to-b from-transparent to-gray-950 overflow-hidden flex items-center justify-center"
>
<div
ref={centerRef}
className={`absolute z-10 w-32 h-32 bg-blue-600 rounded-xl flex items-center justify-center transform transition-all duration-1000 ${isVisible ? "scale-100 opacity-100" : "scale-0 opacity-0"}`}
>
<span className="text-4xl font-bold text-white">TS</span>
</div>
{technologies.map((tech, index) => {
const radius = 250;
const x = Math.cos((tech.angle * Math.PI) / 180) * radius;
const y = Math.sin((tech.angle * Math.PI) / 180) * radius;
return (
<div
key={tech.name}
ref={(el) => {
techRefs.current[tech.name] = el;
}}
className={`absolute z-20 transform -translate-x-1/2 -translate-y-1/2 transition-all duration-1000
${isVisible ? "scale-100 opacity-100" : "scale-0 opacity-0"}`}
style={{
left: `calc(50% + ${x}px)`,
top: `calc(50% + ${y}px)`,
transitionDelay: `${index * 100}ms`,
}}
>
<div
className={`w-16 h-16 ${tech.color} rounded-full flex items-center justify-center
transform hover:scale-125 transition-all duration-300 cursor-pointer
shadow-lg hover:shadow-xl hover:rotate-12`}
>
<tech.icon className={`w-8 h-8 ${tech.textColor}`} />
</div>
<div
className="opacity-0 group-hover:opacity-100 absolute -top-12 left-1/2 transform -translate-x-1/2
bg-gray-900 text-white px-4 py-2 rounded-lg shadow-xl transition-all duration-300
whitespace-nowrap text-sm hover:scale-105"
>
<strong>{tech.name}</strong>
<p className="text-gray-300 text-xs">{tech.description}</p>
</div>
</div>
);
})}
{isVisible &&
technologies.map((tech, index) => (
<AnimatedBeam
key={`beam-${tech.name}`}
fromRef={centerRef as React.RefObject<HTMLElement>}
toRef={{ current: techRefs.current[tech.name] as HTMLElement }}
containerRef={containerRef as React.RefObject<HTMLElement>}
delay={index * 0.2}
/>
))}
<div className="absolute inset-0 overflow-hidden">
{[...Array(20)].map((_, i) => (
<div
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
key={`star-${i}`}
className="absolute w-2 h-2 bg-blue-500 rounded-full opacity-20"
style={{
left: `${Math.random() * 100}%`,
top: `${Math.random() * 100}%`,
animationDelay: `${Math.random() * 5}s`,
}}
/>
))}
</div>
</div>
);
};
export default TechConstellation;

View File

@@ -0,0 +1,56 @@
import React from "react";
const TerminalDisplay = () => {
const TITLE_TEXT = `
╔════════════════════════════════════════════════════════════╗
║ ║
║ ██████╗ ███████╗████████╗████████╗███████╗██████╗ ║
║ ██╔══██╗██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗ ║
║ ██████╔╝█████╗ ██║ ██║ █████╗ ██████╔╝ ║
║ ██╔══██╗██╔══╝ ██║ ██║ ██╔══╝ ██╔══██╗ ║
║ ██████╔╝███████╗ ██║ ██║ ███████╗██║ ██║ ║
║ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ║
║ ║
║ ████████╗ ███████╗████████╗ █████╗ ██████╗██╗ ██╗ ║
║ ╚══██╔══╝ ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██║ ██╔╝ ║
║ ██║ ███████╗ ██║ ███████║██║ █████╔╝ ║
║ ██║ ╚════██║ ██║ ██╔══██║██║ ██╔═██╗ ║
║ ██║ ███████║ ██║ ██║ ██║╚██████╗██║ ██╗ ║
║ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ║
║ ║
║ The Modern Full-Stack Framework ║
║ ║
╚════════════════════════════════════════════════════════════╝
`;
return (
<div className="max-w-6xl mx-auto p-6 mt-12">
<div className="bg-gray-900/30 backdrop-blur-3xl rounded-lg shadow-xl overflow-hidden">
<div className="bg-gray-800/30 backdrop-blur-3xl px-4 py-2 flex items-center">
<div className="flex space-x-2">
<div className="w-3 h-3 rounded-full bg-red-500" />
<div className="w-3 h-3 rounded-full bg-yellow-500" />
<div className="w-3 h-3 rounded-full bg-green-500" />
</div>
</div>
<div className="p-4 font-mono text-sm flex flex-col">
<div className="flex items-center text-gray-300 mb-4">
<span className="text-green-400"></span>
<span className="text-blue-400 ml-2">~</span>
<span className="ml-2">$</span>
<span className="ml-2 text-white">
npx create-better-t-stack@latest
</span>
</div>
<pre className="text-blue-400 whitespace-pre overflow-x-auto px-8">
{TITLE_TEXT}
</pre>
</div>
</div>
</div>
);
};
export default TerminalDisplay;

View File

@@ -1,7 +1,13 @@
import { baseOptions } from "@/app/layout.config";
import { HomeLayout } from "fumadocs-ui/layouts/home";
import type { Metadata } from "next";
import type { ReactNode } from "react";
export const metadata: Metadata = {
title: "Better-T-Stack",
description: "Unleash the power of better-t-stack",
};
export default function Layout({ children }: { children: ReactNode }) {
return <HomeLayout {...baseOptions}>{children}</HomeLayout>;
}

View File

@@ -1,3 +1,4 @@
"use client";
import ShinyText from "components/ShinyText/ShinyText";
import { Poppins } from "next/font/google";
import React from "react";
@@ -6,6 +7,8 @@ import CodeContainer from "./_components/CodeContainer";
import NpmPackage from "./_components/NpmPackage";
import SideCircles from "./_components/SideCircles";
import Spotlight from "./_components/Spotlight";
import TechConstellation from "./_components/TechConstellation";
import TerminalDisplay from "./_components/Terminal";
const poppins = Poppins({
subsets: ["latin"],
@@ -21,7 +24,7 @@ export default function HomePage() {
<BackgroundGradients />
<Spotlight />
<SideCircles />
<div className="max-w-6xl mx-auto text-center mb-16 relative z-50">
<div className="max-w-6xl mx-auto text-center mb-16 relative z-50 ">
<div className="relative z-10">
<div className="flex flex-col items-center justify-center space-y-4 text-center">
<NpmPackage />
@@ -57,6 +60,8 @@ export default function HomePage() {
<div className="absolute inset-0 bg-gradient-to-r from-purple-500/20 to-pink-500/20 blur-3xl transform -skew-y-12" />
</div>
</div>
<TerminalDisplay />
<TechConstellation />
</main>
);
}

View File

@@ -36,3 +36,19 @@
.shiny-text.disabled {
animation: none;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fadeIn {
opacity: 0;
animation: fadeInUp 0.5s ease-out forwards;
}

View File

@@ -1,16 +1,17 @@
import "./global.css";
import { RootProvider } from "fumadocs-ui/provider";
import { Inter } from "next/font/google";
import { Poppins } from "next/font/google";
import { type ReactNode, Suspense } from "react";
import Navbar from "./(home)/_components/Navbar";
const inter = Inter({
const poppins = Poppins({
subsets: ["latin"],
weight: ["400", "500", "600", "700", "800"],
});
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en" className={inter.className} suppressHydrationWarning>
<html lang="en" className={poppins.className} suppressHydrationWarning>
<body className="flex flex-col min-h-screen relative bg-black">
<RootProvider
search={{

View File

@@ -0,0 +1,105 @@
import {
AppWindow,
Binary,
Boxes,
Component,
Database,
FastForward,
Lock,
Palette,
ServerCog,
Workflow,
} from "lucide-react";
export const technologies = [
{
name: "Bun",
category: "core",
angle: -60,
icon: FastForward,
color: "bg-yellow-100",
textColor: "text-black",
description: "Fast all-in-one JavaScript runtime",
},
{
name: "TypeScript",
category: "core",
angle: -30,
icon: Binary,
color: "bg-blue-500",
textColor: "text-white",
description: "Type safety across the stack",
},
{
name: "tRPC",
category: "core",
angle: 0,
icon: Workflow,
color: "bg-blue-600",
textColor: "text-white",
description: "End-to-end type-safe APIs",
},
{
name: "TanStack Router",
category: "frontend",
angle: 60,
icon: AppWindow,
color: "bg-red-500",
textColor: "text-white",
description: "Type-safe routing",
},
{
name: "Tailwind CSS",
category: "frontend",
angle: 90,
icon: Palette,
color: "bg-sky-400",
textColor: "text-white",
description: "Utility-first CSS framework",
},
{
name: "shadcn/ui",
category: "frontend",
angle: 120,
icon: Component,
color: "bg-gray-900",
textColor: "text-white",
description: "Re-usable components",
},
{
name: "Hono",
category: "backend",
angle: 180,
icon: ServerCog,
color: "bg-orange-500",
textColor: "text-white",
description: "Ultrafast web framework",
},
{
name: "Better-Auth",
category: "backend",
angle: 210,
icon: Lock,
color: "bg-indigo-600",
textColor: "text-white",
description: "Modern authentication solution",
},
{
name: "Drizzle ORM",
category: "backend",
angle: 240,
icon: Database,
color: "bg-green-400",
textColor: "text-black",
description: "TypeScript ORM",
},
{
name: "libSQL",
category: "backend",
angle: 270,
icon: Boxes,
color: "bg-gray-600",
textColor: "text-white",
description: "SQLite-compatible database engine",
},
];