mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
develop the hero section of the landing page
This commit is contained in:
22
apps/web/components/ShinyText/ShinyText.tsx
Normal file
22
apps/web/components/ShinyText/ShinyText.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
interface ShinyTextProps {
|
||||
text: string;
|
||||
disabled?: boolean;
|
||||
speed?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const ShinyText = ({ text, disabled = false, speed = 5, className = '' }: ShinyTextProps) => {
|
||||
const animationDuration = `${speed}s`;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`shiny-text ${disabled ? 'disabled' : ''} ${className}`}
|
||||
style={{ animationDuration }}
|
||||
>
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ShinyText;
|
||||
@@ -10,23 +10,24 @@
|
||||
"postinstall": "fumadocs-mdx"
|
||||
},
|
||||
"dependencies": {
|
||||
"fumadocs-core": "15.0.6",
|
||||
"fumadocs-mdx": "11.5.3",
|
||||
"fumadocs-ui": "15.0.6",
|
||||
"lucide-react": "^0.475.0",
|
||||
"next": "15.1.6",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"fumadocs-ui": "15.0.6",
|
||||
"fumadocs-core": "15.0.6",
|
||||
"fumadocs-mdx": "11.5.3"
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.0.5",
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@types/node": "22.13.1",
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-dom": "^19.0.3",
|
||||
"typescript": "^5.7.3",
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@tailwindcss/postcss": "^4.0.5",
|
||||
"tailwindcss": "^4.0.5",
|
||||
"postcss": "^8.5.1",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "15.1.6"
|
||||
"eslint-config-next": "15.1.6",
|
||||
"postcss": "^8.5.1",
|
||||
"tailwindcss": "^4.0.5",
|
||||
"typescript": "^5.7.3"
|
||||
}
|
||||
}
|
||||
|
||||
25
apps/web/src/app/(home)/_components/BackgroundGradients.tsx
Normal file
25
apps/web/src/app/(home)/_components/BackgroundGradients.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from "react";
|
||||
|
||||
const BackgroundGradients = () => {
|
||||
return (
|
||||
<div className="fixed inset-0 -z-10 overflow-hidden">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(circle_at_30%_20%,rgba(168,85,247,0.08)_0%,transparent_40%),radial-gradient(circle_at_70%_60%,rgba(94,234,212,0.05)_0%,transparent_40%)] dark:bg-[radial-gradient(circle_at_30%_20%,rgba(168,85,247,0.15)_0%,transparent_40%),radial-gradient(circle_at_70%_60%,rgba(94,234,212,0.1)_0%,transparent_40%)]" />
|
||||
|
||||
<div className="absolute inset-0 opacity-20 dark:opacity-30">
|
||||
<div className="absolute h-28 w-28 rounded-full bg-rose-300/30 dark:bg-amber-500/30 blur-[120px] top-1/4 left-1/3 " />
|
||||
|
||||
<div className="absolute h-32 w-32 rounded-full bg-teal-300/30 dark:bg-emerald-500/30 blur-[140px] top-2/3 right-1/4 delay-700" />
|
||||
|
||||
<div className="absolute h-36 w-36 rounded-full bg-purple-300/30 dark:bg-fuchsia-500/30 blur-[130px] bottom-1/4 right-1/3 delay-1000" />
|
||||
|
||||
<div className="absolute h-24 w-24 rounded-full bg-slate-300/30 dark:bg-slate-500/30 blur-[100px] top-1/2 left-1/2 delay-500" />
|
||||
</div>
|
||||
|
||||
<div className="absolute inset-0 bg-[linear-gradient(to_right,#e5e7eb_1px,transparent_1px),linear-gradient(to_bottom,#e5e7eb_1px,transparent_1px)] dark:bg-[linear-gradient(to_right,#1f2937_1px,transparent_1px),linear-gradient(to_bottom,#1f2937_1px,transparent_1px)] bg-[size:4rem_4rem] [mask-image:radial-gradient(ellipse_60%_50%_at_50%_0%,#000_70%,transparent_100%)] opacity-[0.15]" />
|
||||
|
||||
{/* <div className="absolute inset-0 bg-noise opacity-[0.035] dark:opacity-[0.07] mix-blend-overlay" /> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BackgroundGradients;
|
||||
18
apps/web/src/app/(home)/_components/CenterLines.tsx
Normal file
18
apps/web/src/app/(home)/_components/CenterLines.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
|
||||
const CenterLines = () => {
|
||||
return (
|
||||
<>
|
||||
<div className='absolute top-3/4 -translate-y-1/2 left-0 w-80 h-14
|
||||
rounded-bl-3xl transform rotate-180
|
||||
border-b-2 border-l-2 border-slate-700
|
||||
shadow-lg backdrop-blur-sm' />
|
||||
<div className='absolute top-3/4 -translate-y-1/2 right-0 w-80 h-14
|
||||
rounded-br-3xl transform rotate-180
|
||||
border-b-2 border-r-2 border-slate-700
|
||||
shadow-lg backdrop-blur-sm' />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default CenterLines
|
||||
123
apps/web/src/app/(home)/_components/CodeContainer.tsx
Normal file
123
apps/web/src/app/(home)/_components/CodeContainer.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { ChevronRight } from "lucide-react";
|
||||
import PackageIcon from "./Icons";
|
||||
|
||||
const CodeContainer = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [selectedPM, setSelectedPM] = useState<"npm" | "yarn" | "pnpm" | "bun">("npm");
|
||||
const [copied, setCopied] = useState(false);
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||
}, []);
|
||||
|
||||
const commands = {
|
||||
npm: "npx create-better-t-stack@latest",
|
||||
yarn: "yarn dlx create better-t-stack",
|
||||
pnpm: "pnpm dlx create better-t-stack",
|
||||
bun: "bunx create-better-t-stack"
|
||||
};
|
||||
|
||||
const copyToClipboard = async (pm: "npm" | "yarn" | "pnpm" | "bun") => {
|
||||
await navigator.clipboard.writeText(commands[pm]);
|
||||
setSelectedPM(pm);
|
||||
setCopied(true);
|
||||
setIsOpen(false);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-3xl mx-auto mt-12">
|
||||
<div className="relative group">
|
||||
<div className="absolute -inset-1 bg-gradient-to-r from-purple-600 to-pink-600 rounded-lg backdrop-blur-lg opacity-25 transition duration-1000 group-hover:duration-200"></div>
|
||||
<div className="relative rounded-lg p-1 bg-slate-900/30 backdrop-blur-xl">
|
||||
<div className="p-4 font-mono text-gray-300 text-sm bg-black/20 rounded-lg flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<ChevronRight />
|
||||
<span className="text-base bg-clip-text text-transparent bg-gradient-to-br from-purple-400 via-pink-400 to-yellow-400">
|
||||
{commands[selectedPM]}
|
||||
</span>
|
||||
</div>
|
||||
<div className="relative" ref={menuRef}>
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="flex items-center space-x-2 px-3 py-2 w-10 justify-center rounded-md cursor-pointer hover:bg-white/10 transition-colors text-gray-300 hover:text-white relative"
|
||||
>
|
||||
{copied ? (
|
||||
<span className="flex items-center space-x-2">
|
||||
<CheckIcon className="w-5 h-5" />
|
||||
</span>
|
||||
) : (
|
||||
<span className="flex items-center space-x-2">
|
||||
<CopyIcon className="w-5 h-5" />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
{isOpen && (
|
||||
<div className="absolute right-6 top-8 mt-2 w-24 rounded-lg backdrop-blur-lg bg-violet-950/10 shadow-xl ring-1 ring-white/10 divide-y divide-gray-700/30 transition-all duration-200">
|
||||
{(["npm", "yarn", "pnpm", "bun"] as const).map((pm) => (
|
||||
<button
|
||||
key={pm}
|
||||
onClick={() => copyToClipboard(pm)}
|
||||
className="group cursor-pointer flex items-center w-full px-4 py-2 text-sm text-gray-300 hover:text-white hover:bg-white/10 transition-all duration-200 first:rounded-t-lg last:rounded-b-lg"
|
||||
>
|
||||
<PackageIcon className="h-4 w-4 mr-2 group-hover:scale-110 transition-transform" pm={pm} /> {pm}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const CopyIcon = ({ className = "" }) => (
|
||||
<svg
|
||||
className={className}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const CheckIcon = ({ className = "" }) => (
|
||||
<svg
|
||||
className={className}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default CodeContainer;
|
||||
58
apps/web/src/app/(home)/_components/CodeExample.tsx
Normal file
58
apps/web/src/app/(home)/_components/CodeExample.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
/** eslint-disable react/jsx-no-comment-textnodes */
|
||||
import React from 'react'
|
||||
|
||||
const CodeExample = () => {
|
||||
return (
|
||||
<div className="max-w-2xl mx-auto mt-8 rounded-lg overflow-hidden bg-slate-900 border border-slate-700">
|
||||
<div className="flex items-center px-4 py-2 bg-slate-800">
|
||||
<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>
|
||||
<span className="ml-4 text-sm text-slate-400">example.ts</span>
|
||||
</div>
|
||||
|
||||
<div className="p-4 font-mono text-sm relative">
|
||||
<div className="space-y-2">
|
||||
<div className="text-slate-400">{"// ❌ Without Type Safety"}</div>
|
||||
<div className="text-white">
|
||||
function processUser(user) {
|
||||
<span className="text-red-400">console.log(user.namee)</span>
|
||||
}
|
||||
</div>
|
||||
<div className="text-red-400 text-xs bg-red-900/30 p-2 rounded">
|
||||
Property 'namee' does not exist on type 'User'.
|
||||
Did you mean 'name'?
|
||||
</div>
|
||||
|
||||
<div className="mt-6 text-slate-400">{"// ✅ With Type Safety"}</div>
|
||||
<div>
|
||||
<span className="text-blue-400">interface</span>
|
||||
<span className="text-green-400"> User</span>
|
||||
<span className="text-white"> {'{'}</span>
|
||||
</div>
|
||||
<div className="pl-4 text-slate-200">
|
||||
name: string;
|
||||
<br />
|
||||
age: number;
|
||||
</div>
|
||||
<div className="text-white">{'}'}</div>
|
||||
<div>
|
||||
<span className="text-blue-400">function</span>
|
||||
<span className="text-yellow-400"> processUser</span>
|
||||
<span className="text-white">(user: </span>
|
||||
<span className="text-green-400">User</span>
|
||||
<span className="text-white">) {'{'}</span>
|
||||
</div>
|
||||
<div className="pl-4 text-slate-200">
|
||||
console.log(user.name) <span className="text-slate-400">{"// ✨ Type checked!"}</span>
|
||||
</div>
|
||||
<div className="text-white">{'}'}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CodeExample
|
||||
126
apps/web/src/app/(home)/_components/Icons.tsx
Normal file
126
apps/web/src/app/(home)/_components/Icons.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
const PackageIcon = ({ pm, className }: { pm: string; className?: string }) => {
|
||||
switch (pm) {
|
||||
case "npm":
|
||||
return (
|
||||
// biome-ignore lint/a11y/noSvgWithoutTitle: <explanation>
|
||||
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z" />
|
||||
</svg>
|
||||
);
|
||||
case "yarn":
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
viewBox="0 0 512 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="2"
|
||||
>
|
||||
<path
|
||||
d="M256 0c141.344 0 256 114.656 256 256S397.344 512 256 512 0 397.344 0 256 114.656 0 256 0z"
|
||||
fill="#2c8ebb"
|
||||
fillRule="nonzero"
|
||||
/>
|
||||
<path
|
||||
d="M430.16 333.59c-1.78-14.035-13.641-23.721-28.863-23.524-22.733.297-41.81 12.06-54.461 19.868-4.943 3.064-9.193 5.337-12.85 7.017.79-11.465.099-26.49-5.832-42.996-7.215-19.768-16.901-31.926-23.82-38.943 8.006-11.664 18.977-28.665 24.117-54.956 4.448-22.437 3.064-57.329-7.117-76.9-2.075-3.953-5.535-6.82-9.884-8.005-1.779-.495-5.14-1.483-11.762.395-9.983-20.658-13.442-22.832-16.111-24.612-5.535-3.558-12.059-4.349-18.187-2.075-8.204 2.965-15.222 10.872-21.844 24.908-.988 2.075-1.878 4.052-2.669 6.03-12.553.889-32.321 5.435-49.025 23.523-2.076 2.274-6.128 3.954-10.379 5.536h.1c-8.699 3.064-12.653 10.18-17.496 23.03-6.721 17.989.198 35.682 7.018 47.147-9.291 8.303-21.646 21.548-28.17 37.066-8.105 19.175-8.994 37.955-8.698 48.136-6.919 7.314-17.594 21.053-18.78 36.472-1.581 21.548 6.227 36.176 9.687 41.514.988 1.581 2.075 2.866 3.261 4.151-.395 2.669-.494 5.535.1 8.5 1.284 6.92 5.633 12.553 12.256 16.112 13.047 6.919 31.234 9.884 45.27 2.866 5.04 5.338 14.232 10.477 30.937 10.477h.988c4.25 0 58.218-2.866 73.934-6.72 7.017-1.681 11.86-4.646 15.023-7.315 10.082-3.163 37.956-12.652 64.248-29.653 18.582-12.058 25.007-14.628 38.844-17.989 13.443-3.262 21.844-15.518 20.164-29.06zm-23.525 14.53c-15.815 3.756-23.821 7.216-43.392 19.966-30.542 19.769-63.95 28.961-63.95 28.961s-2.768 4.151-10.774 6.03c-13.838 3.36-65.927 6.226-70.672 6.325-12.75.1-20.559-3.261-22.733-8.5-6.623-15.815 9.488-22.734 9.488-22.734s-3.558-2.174-5.634-4.151c-1.878-1.878-3.854-5.634-4.448-4.25-2.47 6.03-3.756 20.757-10.378 27.379-9.093 9.192-26.292 6.128-36.473.79-11.169-5.93.791-19.866.791-19.866s-6.03 3.558-10.872-3.756c-4.35-6.722-8.402-18.187-7.315-32.322 1.186-16.11 19.176-31.728 19.176-31.728s-3.163-23.82 7.215-48.235c9.39-22.239 34.694-40.13 34.694-40.13s-21.251-23.524-13.344-44.676c5.14-13.838 7.215-13.739 8.896-14.332 5.93-2.273 11.663-4.744 15.913-9.39 21.251-22.931 48.334-18.582 48.334-18.582s12.85-39.043 24.71-31.432c3.657 2.372 16.803 31.63 16.803 31.63s14.036-8.204 15.617-5.14c8.5 16.506 9.49 48.037 5.733 67.212-6.326 31.63-22.14 48.63-28.466 59.305-1.483 2.471 17 10.28 28.664 42.601 10.774 29.554 1.186 54.363 2.866 57.13.297.495.396.692.396.692s12.355.989 37.164-14.332c13.245-8.204 28.96-17.396 46.851-17.593 17.297-.297 18.187 19.966 5.14 23.128z"
|
||||
fill="#fff"
|
||||
fillRule="nonzero"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "pnpm":
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
width="800px"
|
||||
height="800px"
|
||||
viewBox="0 0 32 32"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>file_type_pnpm</title>
|
||||
<path d="M30,10.75H21.251V2H30Z" style={{ fill: "#f9ad00" }} />
|
||||
<path d="M20.374,10.75h-8.75V2h8.75Z" style={{ fill: "#f9ad00" }} />
|
||||
<path d="M10.749,10.75H2V2h8.749Z" style={{ fill: "#f9ad00" }} />
|
||||
<path d="M30,20.375H21.251v-8.75H30Z" style={{ fill: "#f9ad00" }} />
|
||||
<path d="M20.374,20.375h-8.75v-8.75h8.75Z" style={{ fill: "#fff" }} />
|
||||
<path d="M20.374, 30h - 8.75V21.25h8.75Z" style={{ fill: "#fff" }} />
|
||||
<path d="M30,30H21.251V21.25H30Z" style={{ fill: "#fff" }} />
|
||||
<path d="M10.749,30H2V21.25h8.749Z" style={{ fill: "#fff" }} />
|
||||
</svg>
|
||||
);
|
||||
case "bun":
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 100 100"
|
||||
>
|
||||
<path
|
||||
fill="#000"
|
||||
d="M89.237 32.3c-.2-.213-.412-.425-.625-.625-.212-.2-.412-.425-.625-.625-.212-.2-.412-.425-.625-.625-.212-.2-.412-.425-.625-.625-.212-.2-.412-.425-.625-.625-.212-.2-.412-.425-.625-.625-.212-.2-.412-.425-.625-.625A33.08 33.08 0 0 1 94.75 51c0 20.712-21.025 37.562-46.875 37.562-14.475 0-27.425-5.287-36.038-13.575l.625.625.625.625.625.625.625.625.625.625.625.625.625.625c8.6 8.638 21.838 14.2 36.663 14.2 25.85 0 46.875-16.85 46.875-37.5 0-8.825-3.8-17.187-10.513-23.762"
|
||||
/>
|
||||
<path
|
||||
fill="#FBF0DF"
|
||||
d="M91.625 51c0 19.012-19.588 34.425-43.75 34.425S4.125 70.012 4.125 51c0-11.788 7.5-22.2 19.025-28.375s18.7-12.5 24.725-12.5 11.175 5.162 24.725 12.5C84.125 28.8 91.625 39.212 91.625 51"
|
||||
/>
|
||||
<path
|
||||
fill="#F6DECE"
|
||||
d="M91.625 51a27 27 0 0 0-1-7.225C87.213 85.4 36.438 87.4 16.475 74.95a50 50 0 0 0 31.4 10.475C72 85.425 91.625 69.987 91.625 51"
|
||||
/>
|
||||
<path
|
||||
fill="#FFFEFC"
|
||||
d="M31.038 20.337c5.587-3.35 13.012-9.637 20.312-9.65a11.6 11.6 0 0 0-3.475-.562c-3.025 0-6.25 1.562-10.312 3.912-1.413.825-2.876 1.738-4.425 2.688-2.913 1.8-6.25 3.837-10 5.875C11.237 29.037 4.124 39.65 4.124 51v1.487c7.575-26.762 21.338-28.8 26.913-32.15"
|
||||
/>
|
||||
<path
|
||||
fill="#CCBEA7"
|
||||
fillRule="evenodd"
|
||||
d="M44.275 13.287a20.51 20.51 0 0 1-7.037 15.588c-.35.312-.075.912.375.737 4.212-1.637 9.9-6.537 7.5-16.425-.1-.562-.838-.412-.838.1m2.838 0a20.3 20.3 0 0 1 2.012 16.838c-.15.437.388.812.688.45 2.737-3.5 5.125-10.45-2.025-17.95-.363-.325-.925.175-.675.612zm3.45-.212a20.52 20.52 0 0 1 8.562 14.7.412.412 0 0 0 .813.137c1.15-4.362.5-11.8-8.963-15.662-.5-.2-.825.475-.412.775zm-23.075 13a21.18 21.18 0 0 0 13.087-11.25c.225-.45.938-.275.825.225-2.162 10-9.4 12.087-13.9 11.812-.475.013-.462-.65-.012-.787"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
<path
|
||||
fill="#000"
|
||||
d="M47.875 88.562C22.025 88.562 1 71.712 1 51c0-12.5 7.725-24.163 20.663-31.15 3.75-2 6.962-4.013 9.825-5.775a262 262 0 0 1 4.5-2.738C40.375 8.737 44.125 7 47.875 7S54.9 8.5 59 10.925c1.25.712 2.5 1.487 3.837 2.337 3.113 1.925 6.626 4.1 11.25 6.588C87.026 26.837 94.75 38.487 94.75 51c0 20.712-21.025 37.562-46.875 37.562m0-78.437c-3.025 0-6.25 1.562-10.312 3.912-1.413.825-2.876 1.738-4.425 2.688-2.913 1.8-6.25 3.837-10 5.875C11.237 29.037 4.124 39.65 4.124 51c0 18.987 19.625 34.437 43.75 34.437S91.625 69.987 91.625 51c0-11.35-7.112-21.963-19.025-28.375-4.725-2.5-8.412-4.85-11.4-6.7-1.363-.838-2.613-1.613-3.75-2.3-3.788-2.25-6.55-3.5-9.575-3.5"
|
||||
/>
|
||||
<path
|
||||
fill="#B71422"
|
||||
d="M56.688 60.125a11.16 11.16 0 0 1-3.65 5.887 8.5 8.5 0 0 1-5 2.35 8.55 8.55 0 0 1-5.163-2.35 11.16 11.16 0 0 1-3.6-5.887.9.9 0 0 1 1-1.013H55.7a.9.9 0 0 1 .987 1.013"
|
||||
/>
|
||||
<path
|
||||
fill="#FF6164"
|
||||
d="M42.875 66.112a8.64 8.64 0 0 0 5.15 2.375 8.64 8.64 0 0 0 5.137-2.375q.672-.625 1.25-1.337a8.54 8.54 0 0 0-6.125-2.888 7.69 7.69 0 0 0-6.25 3.475c.288.263.538.513.838.75"
|
||||
/>
|
||||
<path
|
||||
fill="#000"
|
||||
d="M43.075 65.125a6.7 6.7 0 0 1 5.237-2.6 7.5 7.5 0 0 1 5 2.112c.288-.312.563-.637.825-.962a8.75 8.75 0 0 0-5.887-2.413 7.95 7.95 0 0 0-6.112 2.95q.443.482.937.913"
|
||||
/>
|
||||
<path
|
||||
fill="#000"
|
||||
d="M47.987 69.112a9.28 9.28 0 0 1-5.562-2.5 11.9 11.9 0 0 1-3.888-6.312 1.5 1.5 0 0 1 .325-1.25 1.76 1.76 0 0 1 1.413-.638H55.7a1.8 1.8 0 0 1 1.412.638 1.49 1.49 0 0 1 .313 1.25 11.9 11.9 0 0 1-3.888 6.312 9.27 9.27 0 0 1-5.55 2.5m-7.712-9.25c-.2 0-.25.088-.263.113a10.36 10.36 0 0 0 3.413 5.462 7.8 7.8 0 0 0 4.562 2.188 7.85 7.85 0 0 0 4.563-2.163A10.38 10.38 0 0 0 55.95 60a.26.26 0 0 0-.25-.113z"
|
||||
/>
|
||||
<path
|
||||
fill="#FEBBD0"
|
||||
d="M66.9 60.9c4.038 0 7.312-1.926 7.312-4.3 0-2.375-3.273-4.3-7.312-4.3s-7.313 1.925-7.313 4.3 3.274 4.3 7.313 4.3m-37.837 0c4.038 0 7.312-1.926 7.312-4.3 0-2.375-3.274-4.3-7.312-4.3-4.04 0-7.313 1.925-7.313 4.3s3.274 4.3 7.313 4.3"
|
||||
/>
|
||||
<path
|
||||
fill="#000"
|
||||
fillRule="evenodd"
|
||||
d="M32.5 54.875a6.888 6.888 0 1 0 .025-13.775 6.888 6.888 0 0 0-.025 13.775m30.963 0a6.887 6.887 0 1 0-6.838-6.888 6.875 6.875 0 0 0 6.837 6.888"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
<path
|
||||
fill="#fff"
|
||||
fillRule="evenodd"
|
||||
d="M30.375 48.425a2.588 2.588 0 1 0 .025-5.176 2.588 2.588 0 0 0-.025 5.176m30.963 0a2.588 2.588 0 1 0-.026 0z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export default PackageIcon;
|
||||
160
apps/web/src/app/(home)/_components/Navbar.tsx
Normal file
160
apps/web/src/app/(home)/_components/Navbar.tsx
Normal file
@@ -0,0 +1,160 @@
|
||||
"use client";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
const Navbar = () => {
|
||||
const [activeLink, setActiveLink] = useState("about");
|
||||
const [bgStyles, setBgStyles] = useState({});
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
const linkRefs = useRef<{ [key: string]: HTMLAnchorElement | null }>({});
|
||||
|
||||
const updateBackground = (linkId: string) => {
|
||||
const linkElement = linkRefs.current[linkId];
|
||||
if (linkElement) {
|
||||
setBgStyles({
|
||||
padding: "1rem 0rem",
|
||||
width: `${linkElement.clientWidth - 12}px`,
|
||||
transform: `translateX(${linkElement.offsetLeft}px)`,
|
||||
opacity: 1,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
|
||||
useEffect(() => {
|
||||
updateBackground(activeLink);
|
||||
|
||||
const handleScroll = () => {
|
||||
const isScrolled = window.scrollY > 50;
|
||||
setScrolled(isScrolled);
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
window.addEventListener("resize", () => updateBackground(activeLink));
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
window.removeEventListener("resize", () => updateBackground(activeLink));
|
||||
};
|
||||
}, [activeLink]);
|
||||
|
||||
return (
|
||||
<nav
|
||||
className={`fixed top-0 left-0 z-50 w-screen px-8 py-5 flex items-center justify-between transition-all duration-300 ${
|
||||
scrolled
|
||||
? "bg-transparent border-transparent"
|
||||
: "bg-black/10 backdrop-blur-xl border-b border-white/10"
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`flex items-center space-x-2 transition-opacity duration-300 ${scrolled ? "opacity-0" : "opacity-100"}`}
|
||||
>
|
||||
<div className="bg-gradient-to-br from-purple-500 via-pink-400 to-yellow-200 w-8 h-8 rounded-lg flex items-center justify-center">
|
||||
<div className="bg-white w-4 h-4 rounded-sm" />
|
||||
</div>
|
||||
<span className="text-white font-semibold text-lg">Better T Stack</span>
|
||||
</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]"
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="absolute transition-all duration-300 ease-in-out bg-white/5 border border-white/10 rounded-full py-2"
|
||||
style={bgStyles}
|
||||
/>
|
||||
{/* biome-ignore lint/a11y/useValidAnchor: <explanation> */}
|
||||
<a
|
||||
href="#about"
|
||||
ref={(ref) => {
|
||||
linkRefs.current.about = ref;
|
||||
}}
|
||||
onClick={() => setActiveLink("about")}
|
||||
className="text-gray-300 hover:text-white transition-colors py-2 px-4 rounded-full relative"
|
||||
>
|
||||
About
|
||||
</a>
|
||||
{/* biome-ignore lint/a11y/useValidAnchor: <explanation> */}
|
||||
<a
|
||||
href="#careers"
|
||||
ref={(ref) => {
|
||||
linkRefs.current.careers = ref;
|
||||
}}
|
||||
onClick={() => setActiveLink("careers")}
|
||||
className="text-gray-300 hover:text-white transition-colors py-2 px-4 rounded-full relative"
|
||||
>
|
||||
Careers
|
||||
</a>
|
||||
{/* biome-ignore lint/a11y/useValidAnchor: <explanation> */}
|
||||
<a
|
||||
href="#blog"
|
||||
ref={(ref) => {
|
||||
linkRefs.current.blog = ref;
|
||||
}}
|
||||
onClick={() => setActiveLink("blog")}
|
||||
className="text-gray-300 hover:text-white transition-colors py-2 px-4 rounded-full relative"
|
||||
>
|
||||
Blog
|
||||
</a>
|
||||
{/* biome-ignore lint/a11y/useValidAnchor: <explanation> */}
|
||||
<a
|
||||
href="#changelog"
|
||||
ref={(ref) => {
|
||||
linkRefs.current.changelog = ref;
|
||||
}}
|
||||
onClick={() => setActiveLink("changelog")}
|
||||
className="text-gray-300 hover:text-white transition-colors py-2 px-4 rounded-full relative"
|
||||
>
|
||||
Changelog
|
||||
</a>
|
||||
<span
|
||||
className="text-gray-500 transition-all duration-300"
|
||||
style={{
|
||||
opacity: scrolled ? 1 : 0,
|
||||
transform: scrolled ? "translateY(0)" : "translateY(-8px)",
|
||||
}}
|
||||
>
|
||||
|
|
||||
</span>
|
||||
{/* biome-ignore lint/a11y/useValidAnchor: <explanation> */}
|
||||
<a
|
||||
href="#documentation"
|
||||
ref={(ref) => {
|
||||
linkRefs.current.documentation = ref;
|
||||
}}
|
||||
onClick={() => setActiveLink("documentation")}
|
||||
style={{
|
||||
transform: scrolled ? "translateY(0)" : "translateY(-8px)",
|
||||
}}
|
||||
className={`text-gray-300 hover:text-white transition-all duration-300 py-2 px-4 rounded-full ${
|
||||
scrolled
|
||||
? "opacity-100 translate-y-0"
|
||||
: "opacity-0 pointer-events-none"
|
||||
}`}
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`transition-opacity duration-300 ${
|
||||
scrolled ? "opacity-0 pointer-events-none" : "opacity-100"
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="relative inline-flex h-12 overflow-hidden rounded-full p-[1px] focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 focus:ring-offset-slate-50"
|
||||
>
|
||||
<span className="absolute inset-[-1000%] animate-[spin_2s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#E2CBFF_0%,#393BB2_50%,#E2CBFF_100%)]" />
|
||||
<span className="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-slate-950 px-6 py-px text-sm font-medium text-white backdrop-blur-3xl">
|
||||
Documentation
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navbar;
|
||||
48
apps/web/src/app/(home)/_components/NpmPackage.tsx
Normal file
48
apps/web/src/app/(home)/_components/NpmPackage.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const NpmPackage = () => {
|
||||
const [version, setVersion] = useState("");
|
||||
|
||||
const getLatestVersion = async () => {
|
||||
const res = await fetch(
|
||||
"https://registry.npmjs.org/create-better-t-stack/latest",
|
||||
);
|
||||
const data = await res.json();
|
||||
setVersion(data.version);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getLatestVersion();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<button className="bg-slate-800 no-underline group cursor-pointer relative shadow-2xl shadow-zinc-900 rounded-full p-px text-xs font-semibold leading-6 text-white inline-block">
|
||||
<span className="absolute inset-0 overflow-hidden rounded-full">
|
||||
<span className="absolute inset-0 rounded-full bg-[image:radial-gradient(75%_100%_at_50%_0%,rgba(56,189,248,0.6)_0%,rgba(56,189,248,0)_75%)] opacity-0 transition-opacity duration-500 group-hover:opacity-100" />
|
||||
</span>
|
||||
<div className="relative flex space-x-2 items-center z-10 rounded-full backdrop-blur-3xl bg-gradient-to-tr from-purple-900/50 via-pink-900/50 to-yellow-900/10 py-0.5 px-4 ring-1 ring-white/10 ">
|
||||
<span>create-better-t-stack@{version}</span>
|
||||
<svg
|
||||
fill="none"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M10.75 8.75L14.25 12L10.75 15.25"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<span className="absolute -bottom-0 left-[1.125rem] h-px w-[calc(100%-2.25rem)] bg-gradient-to-r from-emerald-400/0 via-emerald-400/90 to-emerald-400/0 transition-opacity duration-500 group-hover:opacity-40" />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default NpmPackage;
|
||||
10
apps/web/src/app/(home)/_components/SafetyMessage.tsx
Normal file
10
apps/web/src/app/(home)/_components/SafetyMessage.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
const SafetyMessage = () => {
|
||||
return (
|
||||
<div className="relative">
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SafetyMessage
|
||||
18
apps/web/src/app/(home)/_components/SideCircles.tsx
Normal file
18
apps/web/src/app/(home)/_components/SideCircles.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
const SideCircles = () => {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<div className="h-[40vh] w-[40vw] rounded-full bg-violet-950/10 backdrop-blur-xl z-50 fixed top-1/2 -translate-y-1/2 -left-[30%]" />
|
||||
<div className="h-[50vh] w-[40vw] rounded-full bg-violet-950/10 backdrop-blur-xl z-40 fixed top-1/2 -translate-y-1/2 -left-[25%]" />
|
||||
<div className="h-[60vh] w-[40vw] rounded-full bg-violet-950/10 backdrop-blur-xl z-30 fixed top-1/2 -translate-y-1/2 -left-[20%]" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="h-[40vh] w-[40vw] rounded-full bg-violet-950/10 backdrop-blur-xl z-50 fixed top-1/2 -translate-y-1/2 -right-[30%]" />
|
||||
<div className="h-[50vh] w-[40vw] rounded-full bg-violet-950/10 backdrop-blur-xl z-40 fixed top-1/2 -translate-y-1/2 -right-[25%]" />
|
||||
<div className="h-[60vh] w-[40vw] rounded-full bg-violet-950/10 backdrop-blur-xl z-30 fixed top-1/2 -translate-y-1/2 -right-[20%]" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SideCircles;
|
||||
16
apps/web/src/app/(home)/_components/Spotlight.tsx
Normal file
16
apps/web/src/app/(home)/_components/Spotlight.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
|
||||
const Spotlight = () => {
|
||||
return (
|
||||
<div className="fixed w-full h-96 -top-12 overflow-hidden">
|
||||
<div className="absolute top-0 left-1/2 transform -translate-x-1/2 flex gap-24">
|
||||
<div className="w-12 h-[40vh] bg-gradient-to-b from-white/30 to-transparent blur-xl" />
|
||||
<div className="w-12 h-[50vh] bg-gradient-to-b from-white/30 to-transparent blur-xl" />
|
||||
<div className="w-12 h-[50vh] bg-gradient-to-b from-white/30 to-transparent blur-xl" />
|
||||
<div className="w-12 h-[40vh] bg-gradient-to-b from-white/30 to-transparent blur-xl" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Spotlight;
|
||||
@@ -1,19 +1,53 @@
|
||||
import Link from "next/link";
|
||||
import React from "react";
|
||||
import { Poppins } from "next/font/google";
|
||||
import BackgroundGradients from "./_components/BackgroundGradients";
|
||||
import Spotlight from "./_components/Spotlight";
|
||||
import NpmPackage from "./_components/NpmPackage";
|
||||
import SideCircles from "./_components/SideCircles";
|
||||
import CodeContainer from "./_components/CodeContainer";
|
||||
import ShinyText from "components/ShinyText/ShinyText";
|
||||
|
||||
const poppins = Poppins({
|
||||
subsets: ["latin"],
|
||||
weight: ["400", "500", "600", "700"],
|
||||
});
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<main className="flex flex-1 flex-col justify-center text-center">
|
||||
<h1 className="mb-4 text-2xl font-bold">Hello World</h1>
|
||||
<p className="text-fd-muted-foreground">
|
||||
You can open{" "}
|
||||
<Link
|
||||
href="/docs"
|
||||
className="text-fd-foreground font-semibold underline"
|
||||
>
|
||||
/docs
|
||||
</Link>{" "}
|
||||
and see the documentation.
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
return (
|
||||
<main className="min-h-screen flex flex-col items-center justify-start p-8" style={poppins.style}>
|
||||
<BackgroundGradients />
|
||||
<Spotlight />
|
||||
<SideCircles />
|
||||
<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 />
|
||||
<h1 className="text-6xl font-extrabold text-white">
|
||||
<span className="block text-7xl bg-clip-text text-transparent bg-gradient-to-r from-purple-500 via-pink-400 to-yellow-200">Better-T Stack</span>
|
||||
<span className="relative">
|
||||
<span className="absolute -bottom-1 left-0 right-0 h-1 bg-gradient-to-r from-purple-400 via-pink-500 to-rose-500 transform origin-left transition-transform duration-300 ease-out scale-x-0 group-hover:scale-x-100" />
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="text-2xl font-medium text-gray-300 max-w-2xl">
|
||||
<span className="inline-block transform hover:scale-105 transition-transform duration-200">
|
||||
Scaffold
|
||||
</span>{" "}
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-emerald-400">
|
||||
production-ready
|
||||
</span>{" "}
|
||||
<span className="inline-block transition-transform duration-200">
|
||||
Better-T projects in seconds
|
||||
</span>
|
||||
</p>
|
||||
<CodeContainer />
|
||||
<ShinyText text="Be the safest developer with typesafe Typescript" speed={3} className="text-lg" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute inset-0 -z-10">
|
||||
<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>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,3 +3,34 @@
|
||||
@import "fumadocs-ui/css/preset.css";
|
||||
|
||||
@source '../../../../node_modules/fumadocs-ui/dist/**/*.js';
|
||||
|
||||
.bg-noise {
|
||||
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%' height='100%' filter='url(%23noise)' opacity='0.4'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.shiny-text {
|
||||
color: #b5b5b5a4;
|
||||
background: linear-gradient(120deg,
|
||||
rgba(255, 255, 255, 0) 40%,
|
||||
rgba(255, 255, 255, 0.8) 50%,
|
||||
rgba(255, 255, 255, 0) 60%);
|
||||
background-size: 200% 100%;
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
display: inline-block;
|
||||
animation: shine 5s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes shine {
|
||||
0% {
|
||||
background-position: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -100%;
|
||||
}
|
||||
}
|
||||
|
||||
.shiny-text.disabled {
|
||||
animation: none;
|
||||
}
|
||||
@@ -11,6 +11,7 @@ export const baseOptions: BaseLayoutProps = {
|
||||
nav: {
|
||||
// can be JSX too!
|
||||
title: "Better-T-Stack",
|
||||
enabled: false,
|
||||
},
|
||||
links: [
|
||||
{
|
||||
|
||||
@@ -1,18 +1,34 @@
|
||||
import "./global.css";
|
||||
import { RootProvider } from "fumadocs-ui/provider";
|
||||
import { Inter } from "next/font/google";
|
||||
import type { ReactNode } from "react";
|
||||
import { Suspense, type ReactNode } from "react";
|
||||
import Navbar from "./(home)/_components/Navbar";
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="en" className={inter.className} suppressHydrationWarning>
|
||||
<body className="flex flex-col min-h-screen">
|
||||
<RootProvider>{children}</RootProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
return (
|
||||
<html lang="en" className={inter.className} suppressHydrationWarning>
|
||||
<body className="flex flex-col min-h-screen relative bg-black">
|
||||
<RootProvider>
|
||||
<Navbar />
|
||||
<div className="relative z-10 bg-zinc-50 dark:bg-zinc-950 pt-20 transition-colors duration-300 overflow-hidden">
|
||||
<Suspense fallback={<LoadingSpinner />}>
|
||||
{children}
|
||||
</Suspense>
|
||||
</div>
|
||||
</RootProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
function LoadingSpinner() {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-[200px]">
|
||||
<div className="w-8 h-8 border-4 border-zinc-300 border-t-zinc-800 rounded-full animate-spin" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
3
bun.lock
3
bun.lock
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"apps/cli": {
|
||||
"name": "create-better-t-stack",
|
||||
"version": "0.6.2",
|
||||
"version": "0.7.2",
|
||||
"bin": {
|
||||
"create-better-t-stack": "dist/index.js"
|
||||
},
|
||||
@@ -42,6 +42,7 @@
|
||||
"fumadocs-core": "15.0.6",
|
||||
"fumadocs-mdx": "11.5.3",
|
||||
"fumadocs-ui": "15.0.6",
|
||||
"lucide-react": "^0.475.0",
|
||||
"next": "15.1.6",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
|
||||
10462
package-lock.json
generated
Normal file
10462
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user