mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
update landing page styles
This commit is contained in:
@@ -7,10 +7,7 @@
|
||||
"bin": {
|
||||
"create-better-t-stack": "dist/index.js"
|
||||
},
|
||||
"files": [
|
||||
"template",
|
||||
"dist"
|
||||
],
|
||||
"files": ["template", "dist"],
|
||||
"keywords": [
|
||||
"better-t-stack",
|
||||
"typescript",
|
||||
@@ -39,7 +36,7 @@
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/better-t-stack/create-better-t-stack.git",
|
||||
"url": "git+https://github.com/AmanVarshney01/create-better-t-stack.git",
|
||||
"directory": "apps/cli"
|
||||
},
|
||||
"homepage": "https://better-t-stack.pages.dev/",
|
||||
|
||||
@@ -43,7 +43,7 @@ function generateReadmeContent(options: ProjectConfig): string {
|
||||
|
||||
return `# ${projectName}
|
||||
|
||||
This project was created with [Better-T-Stack](https://github.com/better-t-stack/Better-T-Stack), a modern TypeScript stack that combines React, ${hasTanstackRouter ? "TanStack Router" : "React Router"}, Hono, tRPC, and more.
|
||||
This project was created with [Better-T-Stack](https://github.com/AmanVarshney01/create-better-t-stack), a modern TypeScript stack that combines React, ${hasTanstackRouter ? "TanStack Router" : "React Router"}, Hono, tRPC, and more.
|
||||
|
||||
## Features
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ ${
|
||||
}${pc.cyan("•")} API: http://localhost:3000
|
||||
${nativeInstructions ? `\n${nativeInstructions.trim()}` : ""}${databaseInstructions ? `\n${databaseInstructions.trim()}` : ""}${tauriInstructions ? `\n${tauriInstructions.trim()}` : ""}${lintingInstructions ? `\n${lintingInstructions.trim()}` : ""}${pwaInstructions ? `\n${pwaInstructions.trim()}` : ""}
|
||||
\n${pc.bold("Like Better-T Stack?")} Please consider giving us a star on GitHub:
|
||||
${pc.cyan("https://github.com/better-t-stack/create-better-t-stack")}`,
|
||||
${pc.cyan("https://github.com/AmanVarshney01/create-better-t-stack")}`,
|
||||
"Next steps",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
@theme {
|
||||
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
import { motion } from "framer-motion";
|
||||
import { Check, CircleCheck, ClipboardCopy, Terminal } from "lucide-react";
|
||||
import { Check, ClipboardCopy, Terminal } from "lucide-react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
const CodeContainer = () => {
|
||||
@@ -8,24 +8,37 @@ const CodeContainer = () => {
|
||||
const [selectedPM, setSelectedPM] = useState<"npm" | "pnpm" | "bun">("bun");
|
||||
const [copied, setCopied] = useState(false);
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
const [typingComplete, setTypingComplete] = useState(false);
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
const [showCursor, setShowCursor] = useState(true);
|
||||
const [step, setStep] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
|
||||
const handleClickOutside = (e: MouseEvent) => {
|
||||
if (menuRef.current && !menuRef.current.contains(e.target as Node))
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => setShowCursor((p) => !p), 500);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (step < 5) {
|
||||
const timer = setTimeout(
|
||||
() => setStep((s) => s + 1),
|
||||
step === 0 ? 1000 : 400,
|
||||
);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [step]);
|
||||
|
||||
const commands = {
|
||||
npm: "npx create-better-t-stack@latest my-better-t-app --yes",
|
||||
pnpm: "pnpm create better-t-stack@latest my-better-t-app --yes",
|
||||
bun: "bun create better-t-stack@latest my-better-t-app --yes",
|
||||
npm: "npx create-better-t-stack@latest my-app",
|
||||
pnpm: "pnpm create better-t-stack@latest my-app",
|
||||
bun: "bun create better-t-stack@latest my-app",
|
||||
};
|
||||
|
||||
const copyToClipboard = async (pm: "npm" | "pnpm" | "bun") => {
|
||||
@@ -36,54 +49,35 @@ const CodeContainer = () => {
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!typingComplete) {
|
||||
const timer = setTimeout(() => {
|
||||
setTypingComplete(true);
|
||||
}, 1000);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
|
||||
if (typingComplete && currentStep < 5) {
|
||||
const timer = setTimeout(() => {
|
||||
setCurrentStep((prev) => prev + 1);
|
||||
}, 800);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [typingComplete, currentStep]);
|
||||
|
||||
return (
|
||||
<div className="mx-auto mt-4 w-full max-w-3xl sm:mt-8">
|
||||
<div className="overflow-hidden rounded-xl border border-gray-300 bg-gray-100 text-gray-800 shadow-xl dark:border-gray-700 dark:bg-black dark:text-white">
|
||||
<div className="flex items-center justify-between bg-gray-200 px-3 py-2 sm:px-4 dark:bg-gray-800">
|
||||
<div className="flex space-x-2">
|
||||
<div className="h-3 w-3 rounded-full bg-red-500" />
|
||||
<div className="h-3 w-3 rounded-full bg-yellow-500" />
|
||||
<div className="h-3 w-3 rounded-full bg-green-500" />
|
||||
<div className="mx-auto mt-4 w-full max-w-3xl">
|
||||
<div className="overflow-hidden rounded-lg border border-gray-200 bg-white shadow-md dark:border-gray-800 dark:bg-gray-950">
|
||||
<div className="flex items-center justify-between bg-gray-100 px-3 py-2 dark:bg-gray-900">
|
||||
<div className="flex gap-1.5">
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-red-500" />
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-yellow-500" />
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-green-500" />
|
||||
</div>
|
||||
<div className="xs:block hidden font-mono text-[10px] text-gray-600 sm:text-xs dark:text-gray-400">
|
||||
Quick Install Terminal
|
||||
|
||||
<div className="text-gray-600 text-xs dark:text-gray-400">
|
||||
Terminal
|
||||
</div>
|
||||
|
||||
<div className="relative" ref={menuRef}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="flex items-center rounded border border-gray-300 bg-gray-300/50 px-1.5 py-1 text-[10px] hover:bg-gray-300/80 sm:px-2 sm:text-xs dark:border-gray-700 dark:bg-gray-800/50 dark:hover:bg-gray-700/50"
|
||||
className="flex items-center gap-1 rounded border border-gray-200 bg-white px-2 py-1 text-gray-700 text-xs hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"
|
||||
>
|
||||
<Terminal className="mr-1 h-3 w-3 text-gray-600 dark:text-gray-400">
|
||||
<title>Package Manager</title>
|
||||
</Terminal>
|
||||
<span className="mr-1 text-gray-700 dark:text-gray-300">
|
||||
{selectedPM}
|
||||
</span>
|
||||
<Terminal className="h-3 w-3 text-gray-600 dark:text-gray-400" />
|
||||
<span>{selectedPM}</span>
|
||||
<svg
|
||||
className="h-3 w-3 text-gray-700 dark:text-gray-400"
|
||||
className="h-3 w-3 text-gray-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<title>Toggle Dropdown</title>
|
||||
<title>arrow</title>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
@@ -97,254 +91,137 @@ const CodeContainer = () => {
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -5 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="absolute right-0 z-50 mt-1 w-32 rounded-md border border-gray-300 bg-white shadow-lg sm:w-36 dark:border-gray-700 dark:bg-gray-900"
|
||||
className="absolute right-0 z-50 mt-1 w-28 rounded-md border border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-800"
|
||||
>
|
||||
<ul>
|
||||
{(Object.keys(commands) as Array<"npm" | "pnpm" | "bun">).map(
|
||||
(pm) => (
|
||||
<li key={pm}>
|
||||
<button
|
||||
type="button"
|
||||
className={`block w-full px-3 py-1.5 text-left text-[10px] sm:text-xs ${
|
||||
selectedPM === pm
|
||||
? "border-blue-500 border-l-2 bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300"
|
||||
: "text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800"
|
||||
}`}
|
||||
onClick={() => copyToClipboard(pm)}
|
||||
>
|
||||
{pm === "npm" && "npm"}
|
||||
{pm === "pnpm" && "pnpm"}
|
||||
{pm === "bun" && (
|
||||
<span className="flex items-center">
|
||||
<span className="mr-1">🥟</span> bun
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</li>
|
||||
),
|
||||
)}
|
||||
</ul>
|
||||
{(["npm", "pnpm", "bun"] as const).map((pm) => (
|
||||
<button
|
||||
type="button"
|
||||
key={pm}
|
||||
className={`block w-full px-3 py-1.5 text-left text-xs ${
|
||||
selectedPM === pm
|
||||
? "bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-gray-200"
|
||||
: "text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-700/50"
|
||||
}`}
|
||||
onClick={() => copyToClipboard(pm)}
|
||||
>
|
||||
{pm === "bun" ? "🥟 bun" : pm}
|
||||
</button>
|
||||
))}
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto bg-gray-50 p-3 font-mono text-xs sm:p-4 sm:text-sm dark:bg-gray-900">
|
||||
<div className="bg-gray-50 p-4 text-left font-mono text-sm dark:bg-gray-900">
|
||||
<div className="flex items-center">
|
||||
<div className="flex-grow overflow-x-auto">
|
||||
<span className="mr-2 text-green-600 dark:text-green-400">$</span>
|
||||
<span className="text-gray-700 dark:text-gray-300">
|
||||
<span className="mr-2 text-gray-600 dark:text-gray-400">$</span>
|
||||
<div className="flex-grow">
|
||||
<span className="text-gray-800 dark:text-gray-200">
|
||||
{commands[selectedPM]}
|
||||
</span>
|
||||
<span
|
||||
className={
|
||||
typingComplete
|
||||
? "hidden"
|
||||
: "ml-1 animate-pulse text-blue-600 dark:text-blue-500"
|
||||
}
|
||||
>
|
||||
▌
|
||||
</span>
|
||||
{step === 0 && (
|
||||
<span
|
||||
className={`ml-0.5 inline-block h-4 w-2 bg-gray-800 dark:bg-white ${showCursor ? "opacity-100" : "opacity-0"}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyToClipboard(selectedPM)}
|
||||
className="ml-2 flex-shrink-0 text-gray-600 transition-colors hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
title="Copy command"
|
||||
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300"
|
||||
>
|
||||
{copied ? (
|
||||
<Check className="h-4 w-4">
|
||||
<title>Copied!</title>
|
||||
</Check>
|
||||
<Check className="h-4 w-4 text-gray-600 dark:text-gray-400" />
|
||||
) : (
|
||||
<ClipboardCopy className="h-4 w-4">
|
||||
<title>Copy to clipboard</title>
|
||||
</ClipboardCopy>
|
||||
<ClipboardCopy className="h-4 w-4" />
|
||||
)}
|
||||
</motion.button>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{typingComplete && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
className="overflow-x-auto"
|
||||
>
|
||||
<div className="mt-3 pl-2 text-amber-600 sm:pl-4 dark:text-amber-400">
|
||||
{currentStep >= 1 && (
|
||||
<motion.p
|
||||
initial={{ opacity: 0, y: -5 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.1 }}
|
||||
>
|
||||
Creating a new Better-T-Stack project
|
||||
</motion.p>
|
||||
)}
|
||||
{currentStep >= 2 && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="mt-2"
|
||||
>
|
||||
<p className="text-gray-700 dark:text-gray-300">
|
||||
Project name:{" "}
|
||||
<span className="text-amber-600 dark:text-amber-400">
|
||||
my-better-t-app
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-gray-700 dark:text-gray-300">
|
||||
Frontend:{" "}
|
||||
<span className="text-amber-600 dark:text-amber-400">
|
||||
React Web
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-gray-700 dark:text-gray-300">
|
||||
Runtime:{" "}
|
||||
<span className="text-amber-600 dark:text-amber-400">
|
||||
Bun
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-gray-700 dark:text-gray-300">
|
||||
Backend:{" "}
|
||||
<span className="text-amber-600 dark:text-amber-400">
|
||||
Hono
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-gray-700 dark:text-gray-300">
|
||||
Database:{" "}
|
||||
<span className="text-amber-600 dark:text-amber-400">
|
||||
SQLite + Drizzle
|
||||
</span>
|
||||
</p>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
{step > 0 && (
|
||||
<div className="mt-3 space-y-1.5 text-sm">
|
||||
{step > 0 && (
|
||||
<div className="text-gray-600 dark:text-gray-400">
|
||||
Creating a new Better-T-Stack project
|
||||
</div>
|
||||
)}
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="mt-3 pl-2 sm:pl-4"
|
||||
>
|
||||
{currentStep >= 3 && (
|
||||
<motion.p
|
||||
initial={{ opacity: 0, x: -5 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.4 }}
|
||||
className="flex items-center text-blue-600 dark:text-blue-400"
|
||||
>
|
||||
<CircleCheck className="mr-1 h-4 w-4 flex-shrink-0">
|
||||
<title>Completed</title>
|
||||
</CircleCheck>
|
||||
<span>Creating project structure</span>
|
||||
</motion.p>
|
||||
)}
|
||||
{currentStep >= 4 && (
|
||||
<motion.p
|
||||
initial={{ opacity: 0, x: -5 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.5 }}
|
||||
className="flex items-center text-blue-600 dark:text-blue-400"
|
||||
>
|
||||
<CircleCheck className="mr-1 h-4 w-4 flex-shrink-0">
|
||||
<title>Completed</title>
|
||||
</CircleCheck>
|
||||
<span>Installing dependencies</span>
|
||||
</motion.p>
|
||||
)}
|
||||
{currentStep >= 5 && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.6 }}
|
||||
>
|
||||
<motion.p
|
||||
initial={{ opacity: 0, x: -5 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.7 }}
|
||||
className="flex items-center text-blue-600 dark:text-blue-400"
|
||||
>
|
||||
<CircleCheck className="mr-1 h-4 w-4 flex-shrink-0">
|
||||
<title>Completed</title>
|
||||
</CircleCheck>
|
||||
<span>Setting up database schema</span>
|
||||
</motion.p>
|
||||
<motion.p
|
||||
initial={{ opacity: 0, x: -5 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.8 }}
|
||||
className="flex items-center text-blue-600 dark:text-blue-400"
|
||||
>
|
||||
<CircleCheck className="mr-1 h-4 w-4 flex-shrink-0">
|
||||
<title>Completed</title>
|
||||
</CircleCheck>
|
||||
<span>Configuring authentication</span>
|
||||
</motion.p>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.9 }}
|
||||
className="mt-4 flex xs:flex-row flex-col xs:items-center rounded border border-blue-300 bg-blue-100 px-2 py-2 text-[10px] text-blue-800 sm:text-xs dark:border-blue-800/30 dark:bg-blue-900/20 dark:text-blue-300"
|
||||
>
|
||||
<svg
|
||||
className="xs:mr-2 mb-1 xs:mb-0 h-4 w-4 flex-shrink-0 text-blue-600 dark:text-blue-400"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<title>Success</title>
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
|
||||
<polyline points="22 4 12 14.01 9 11.01" />
|
||||
</svg>
|
||||
<div className="flex flex-wrap">
|
||||
<span className="mr-1">Project ready! Run</span>
|
||||
<code className="mr-1 mb-1 xs:mb-0 rounded bg-blue-200 px-1 py-0.5 dark:bg-blue-800/50">
|
||||
cd my-better-t-app
|
||||
</code>
|
||||
<span className="mr-1">and</span>
|
||||
<code className="rounded bg-blue-200 px-1 py-0.5 dark:bg-blue-800/50">
|
||||
{selectedPM === "npm" && "npm run dev"}
|
||||
{selectedPM === "pnpm" && "pnpm dev"}
|
||||
{selectedPM === "bun" && "bun dev"}
|
||||
</code>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
{step > 1 && (
|
||||
<div className="ml-2 grid grid-cols-[80px_1fr] gap-x-2 text-gray-700 text-xs dark:text-gray-300">
|
||||
<span>Project:</span>
|
||||
<span className="text-gray-800 dark:text-gray-200">
|
||||
my-app
|
||||
</span>
|
||||
<span>Frontend:</span>
|
||||
<span className="text-gray-800 dark:text-gray-200">
|
||||
React Web
|
||||
</span>
|
||||
<span>Backend:</span>
|
||||
<span className="text-gray-800 dark:text-gray-200">Hono</span>
|
||||
<span>Database:</span>
|
||||
<span className="text-gray-800 dark:text-gray-200">
|
||||
SQLite + Drizzle
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{step > 2 && (
|
||||
<div className="text-gray-600 dark:text-gray-400">
|
||||
✓ Creating project structure
|
||||
</div>
|
||||
)}
|
||||
|
||||
{step > 3 && (
|
||||
<div className="text-gray-600 dark:text-gray-400">
|
||||
✓ Installing dependencies
|
||||
</div>
|
||||
)}
|
||||
|
||||
{step > 4 && (
|
||||
<div className="mt-2 border-gray-400 border-l-2 bg-gray-100 py-2 pl-3 text-xs dark:border-gray-600 dark:bg-gray-800">
|
||||
<span className="font-semibold text-gray-800 dark:text-gray-200">
|
||||
Project created successfully! Run:
|
||||
</span>
|
||||
<div className="mt-1 flex flex-wrap gap-1">
|
||||
<code className="rounded bg-gray-200 px-1 py-0.5 text-gray-800 dark:bg-gray-700 dark:text-white">
|
||||
cd my-app
|
||||
</code>
|
||||
<span className="text-gray-700 dark:text-gray-300">
|
||||
and
|
||||
</span>
|
||||
<code className="rounded bg-gray-200 px-1 py-0.5 text-gray-800 dark:bg-gray-700 dark:text-white">
|
||||
{selectedPM === "npm"
|
||||
? "npm run dev"
|
||||
: selectedPM === "pnpm"
|
||||
? "pnpm dev"
|
||||
: "bun dev"}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
className={`mt-4 flex ${
|
||||
currentStep >= 5 && typingComplete ? "" : "hidden"
|
||||
}`}
|
||||
>
|
||||
<span className="mr-2 text-green-600 dark:text-green-400">$</span>
|
||||
<span className="animate-pulse text-blue-600 dark:text-blue-500">
|
||||
▌
|
||||
</span>
|
||||
</div>
|
||||
{step > 4 && (
|
||||
<div className="mt-3 flex items-center">
|
||||
<span className="mr-2 text-gray-600 dark:text-gray-400">$</span>
|
||||
<span
|
||||
className={`inline-block h-4 w-2 bg-gray-800 dark:bg-white ${showCursor ? "opacity-100" : "opacity-0"}`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="border-gray-300 border-t bg-gray-200 px-2 py-2 sm:px-4 dark:border-gray-700 dark:bg-gray-900">
|
||||
<div className="flex items-center justify-center text-center text-[10px] text-gray-600 sm:text-xs dark:text-gray-400">
|
||||
<span className="inline-flex flex-wrap items-center justify-center gap-1">
|
||||
<span>For custom options, use</span>
|
||||
<code className="whitespace-nowrap rounded bg-gray-300 px-1 py-0.5 dark:bg-gray-700">
|
||||
{selectedPM === "npm" && "npx"}
|
||||
{selectedPM === "pnpm" && "pnpm dlx"}
|
||||
{selectedPM === "bun" && "bunx"} create-better-t-stack
|
||||
</code>
|
||||
<span>without flags</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="border-gray-200 border-t bg-gray-50 px-4 py-1.5 text-left text-gray-600 text-xs dark:border-gray-800 dark:bg-gray-900 dark:text-gray-400">
|
||||
For customization options:{" "}
|
||||
<code className="rounded bg-gray-200 px-1 py-0.5 text-gray-700 dark:bg-gray-700 dark:text-gray-300">
|
||||
{selectedPM === "npm"
|
||||
? "npx"
|
||||
: selectedPM === "pnpm"
|
||||
? "pnpm dlx"
|
||||
: "bunx"}{" "}
|
||||
create-better-t-stack
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,11 +13,8 @@ export default function CustomizableSection() {
|
||||
transition={{ duration: 0.5 }}
|
||||
className="relative"
|
||||
>
|
||||
<h2 className="font-bold text-3xl sm:text-4xl">
|
||||
<span className="mr-1 font-mono text-blue-500 dark:text-blue-400">
|
||||
{">"}
|
||||
</span>
|
||||
<span className="bg-gradient-to-r from-blue-500 to-indigo-600 bg-clip-text text-transparent dark:from-blue-400 dark:to-indigo-500">
|
||||
<h2 className="font-bold font-mono text-2xl tracking-tight sm:text-3xl md:text-4xl lg:text-5xl">
|
||||
<span className="border-blue-500 border-b-2 pb-1 text-gray-900 dark:text-blue-100">
|
||||
Your Stack, Your Choice
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
const SideCircles = () => {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<div className="-translate-y-1/2 -left-[30%] fixed top-1/2 z-40 h-[50vh] w-[40vw] rounded-full bg-gradient-to-b from-transparent via-violet-950/20 to-transparent backdrop-blur-xl" />
|
||||
<div className="-translate-y-1/2 -left-[35%] fixed top-1/2 z-50 h-[40vh] w-[40vw] rounded-full bg-gradient-to-b from-transparent via-violet-950/20 to-transparent backdrop-blur-xl" />
|
||||
<div className="-translate-y-1/2 -left-[25%] fixed top-1/2 z-30 h-[60vh] w-[40vw] rounded-full bg-gradient-to-b from-transparent via-violet-950/20 to-transparent backdrop-blur-xl" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="-translate-y-1/2 -right-[35%] fixed top-1/2 z-50 h-[40vh] w-[40vw] rounded-full bg-gradient-to-b from-transparent via-violet-950/20 to-transparent backdrop-blur-xl" />
|
||||
<div className="-translate-y-1/2 -right-[30%] fixed top-1/2 z-40 h-[50vh] w-[40vw] rounded-full bg-gradient-to-b from-transparent via-violet-950/20 to-transparent backdrop-blur-xl" />
|
||||
<div className="-translate-y-1/2 -right-[25%] fixed top-1/2 z-30 h-[60vh] w-[40vw] rounded-full bg-gradient-to-b from-transparent via-violet-950/20 to-transparent backdrop-blur-xl" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SideCircles;
|
||||
@@ -19,7 +19,9 @@ const TWEET_IDS = [
|
||||
"1904301540422070671",
|
||||
"1904338606409531710",
|
||||
"1904318186750652606",
|
||||
"1908568583799484519",
|
||||
"1904179661086556412",
|
||||
"1908558365128876311",
|
||||
"1907772878139072851",
|
||||
"1906149740095705265",
|
||||
"1906001923456790710",
|
||||
@@ -82,11 +84,8 @@ export default function Testimonials() {
|
||||
transition={{ duration: 0.5 }}
|
||||
className="relative"
|
||||
>
|
||||
<h2 className="font-bold text-3xl sm:text-4xl">
|
||||
<span className="mr-1 font-mono text-blue-500 dark:text-blue-400">
|
||||
{">"}
|
||||
</span>
|
||||
<span className="bg-gradient-to-r from-blue-500 to-indigo-600 bg-clip-text text-transparent dark:from-blue-400 dark:to-indigo-500">
|
||||
<h2 className="font-bold font-mono text-2xl tracking-tight sm:text-3xl md:text-4xl lg:text-5xl">
|
||||
<span className="border-blue-500 border-b-2 pb-1 text-gray-900 dark:text-blue-100">
|
||||
Developer Feedback
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
@@ -9,13 +9,13 @@ import Testimonials from "./_components/Testimonials";
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-start px-2 pt-24 pb-10 sm:px-4 sm:pb-16 md:px-8 md:pt-28">
|
||||
<main className="flex flex-col items-center justify-start px-2 pt-24 pb-10 sm:px-4 sm:pb-16 md:px-8 md:pt-28 lg:pt-36">
|
||||
<BackgroundGradients />
|
||||
<div className="relative z-10 mx-auto mb-10 max-w-5xl text-center sm:mb-16">
|
||||
<div className="px-1 sm:px-6 lg:px-8">
|
||||
<div className="flex flex-col items-center justify-center space-y-3 text-center sm:space-y-4">
|
||||
<h1 className="font-bold text-4xl text-gray-900 xs:text-5xl tracking-tight sm:text-6xl md:text-7xl dark:text-white">
|
||||
<span className="block bg-gradient-to-r from-blue-500 to-indigo-600 bg-clip-text pb-1 text-transparent">
|
||||
<h1 className="font-bold font-mono text-4xl xs:text-5xl tracking-tight sm:text-6xl md:text-7xl">
|
||||
<span className="border-blue-500 border-b-2 pb-1 text-gray-900 dark:text-blue-100">
|
||||
Better-T Stack
|
||||
</span>
|
||||
</h1>
|
||||
@@ -24,7 +24,7 @@ export default function HomePage() {
|
||||
<NpmPackage />
|
||||
</div>
|
||||
|
||||
<p className="max-w-2xl px-1 font-medium text-gray-600 text-lg sm:text-xl dark:text-gray-300">
|
||||
<p className="max-w-2xl px-1 font-mono text-gray-600 text-lg sm:text-xl dark:text-gray-300">
|
||||
A modern CLI tool for scaffolding end-to-end type-safe TypeScript
|
||||
projects with best practices and customizable configurations
|
||||
</p>
|
||||
@@ -36,14 +36,10 @@ export default function HomePage() {
|
||||
<ShinyText
|
||||
text="Type-safe. Modern. Minimal. Fast."
|
||||
speed={3}
|
||||
className="text-gray-600 text-xs xs:text-sm sm:text-base dark:text-gray-400"
|
||||
className="font-mono text-gray-600 text-xs xs:text-sm sm:text-base dark:text-gray-400"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="-z-10 absolute inset-0">
|
||||
<div className="-skew-y-12 absolute inset-0 transform bg-gradient-to-r from-blue-300/20 to-indigo-300/20 blur-2xl dark:from-purple-500/20 dark:to-indigo-500/20 dark:blur-3xl" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CustomizableSection />
|
||||
@@ -57,10 +53,10 @@ export default function HomePage() {
|
||||
</div>
|
||||
|
||||
<div className="px-4 sm:px-6">
|
||||
<div className="flex h-7 w-7 items-center justify-center rounded-full bg-gradient-to-br from-blue-500 to-indigo-600 shadow-md sm:h-8 sm:w-8">
|
||||
<div className="flex h-7 w-7 items-center justify-center rounded-full border border-blue-500 bg-white sm:h-8 sm:w-8 dark:bg-gray-900">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-3.5 w-3.5 text-white sm:h-4 sm:w-4"
|
||||
className="h-3.5 w-3.5 text-blue-500 sm:h-4 sm:w-4"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
@@ -75,12 +71,12 @@ export default function HomePage() {
|
||||
</div>
|
||||
|
||||
<div className="hidden w-1/3 items-center sm:flex">
|
||||
<div className="h-2 w-2 rounded-full bg-indigo-500/50" />
|
||||
<div className="h-px flex-grow bg-gradient-to-l from-transparent to-indigo-500/40" />
|
||||
<div className="h-2 w-2 rounded-full bg-blue-500/50" />
|
||||
<div className="h-px flex-grow bg-gradient-to-l from-transparent to-blue-500/40" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 h-px w-full bg-gradient-to-r from-blue-500/20 via-indigo-500/40 to-blue-500/20 sm:hidden" />
|
||||
<div className="mt-6 h-px w-full bg-blue-500/20 sm:hidden" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
}
|
||||
|
||||
/* custom scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
/* ::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
@@ -90,4 +90,4 @@
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(45deg, #888, #aaa);
|
||||
}
|
||||
} */
|
||||
|
||||
Reference in New Issue
Block a user