feat(web): design overhaul

This commit is contained in:
Aman Varshney
2025-07-20 19:37:41 +05:30
parent 81975cfef4
commit 87d4362c6d
31 changed files with 1844 additions and 733 deletions

View File

@@ -1,39 +0,0 @@
import { Card, Cards } from "fumadocs-ui/components/card";
import { Cable, Database, Globe, Lock, Package, Server } from "lucide-react";
export default function Features() {
return (
<Cards>
<Card
icon={<Globe />}
title="Frontend"
description="Choose between Tanstack Router, React Router, Expo, Next.js, and more"
/>
<Card
icon={<Server />}
title="Flexible Backend"
description="Choose between Hono, Elysia, Next.js, Express, and Fastify"
/>
<Card
icon={<Cable />}
title="End to end typesafe APIs"
description="With the help of tRPC or oRPC"
/>
<Card
icon={<Lock />}
title="Authentication"
description="With the help of Better Auth"
/>
<Card
icon={<Database />}
title="Database Setup"
description="Many ORMs and Relational Databases"
/>
<Card
icon={<Package />}
title="Addons"
description="Add PWA support, desktop apps, documentation, and more"
/>
</Cards>
);
}

View File

@@ -0,0 +1,462 @@
---
title: CLI Commands
description: Complete reference for all Better-T-Stack CLI commands and options
---
## Commands Overview
| Command | Description |
|---------|-------------|
| `init` (default) | Create a new Better-T-Stack project |
| `add` | Add addons or deployment configurations to existing projects |
| `sponsors` | Display project sponsors |
| `docs` | Open documentation in browser |
| `builder` | Open web-based stack builder |
---
## `init` - Create Project (Default)
The primary command for creating new Better-T-Stack projects.
### Basic Usage
```bash
# Interactive setup
npx create-better-t-stack@latest
# With project name
npx create-better-t-stack@latest my-project
# With specific directory
npx create-better-t-stack@latest ./path/to/project
# Use current directory
npx create-better-t-stack@latest .
```
### Flags Reference
#### General Options
| Flag | Type | Default | Description |
|------|------|---------|-------------|
| `--yes, -y` | boolean | `false` | Skip prompts, use defaults |
| `--help, -h` | boolean | - | Show help information |
| `--version, -V` | boolean | - | Show CLI version |
#### Frontend Options
| Flag | Values | Default | Description |
|------|--------|---------|-------------|
| `--frontend` | Multiple values | `tanstack-router` | Frontend frameworks to include |
**Available Frontend Values:**
- `tanstack-router` - React with TanStack Router
- `react-router` - React with React Router
- `tanstack-start` - React with TanStack Start (SSR)
- `next` - Next.js framework
- `nuxt` - Vue.js with Nuxt
- `svelte` - SvelteKit
- `solid` - SolidJS
- `native-nativewind` - React Native with NativeWind
- `native-unistyles` - React Native with Unistyles
- `none` - No frontend
**Examples:**
```bash
# Single web frontend
--frontend tanstack-router
# Web + Mobile
--frontend tanstack-router native-nativewind
# Multiple frontends
--frontend next solid
# No frontend (API-only)
--frontend none
```
#### Backend Options
| Flag | Values | Default | Description |
|------|--------|---------|-------------|
| `--backend` | Single value | `hono` | Backend framework |
**Available Backend Values:**
- `hono` - Hono web framework
- `express` - Express.js
- `fastify` - Fastify framework
- `elysia` - Elysia framework
- `next` - Next.js API routes
- `convex` - Convex backend-as-a-service
- `none` - No backend
**Examples:**
```bash
--backend hono
--backend convex
--backend none
```
#### Runtime Options
| Flag | Values | Default | Description |
|------|--------|---------|-------------|
| `--runtime` | Single value | `bun` | Runtime environment |
**Available Runtime Values:**
- `bun` - Bun runtime
- `node` - Node.js runtime
- `workers` - Cloudflare Workers (Hono only)
- `none` - No runtime (Convex/none backend)
**Examples:**
```bash
--runtime bun
--runtime workers # Only with --backend hono
```
#### Database Options
| Flag | Values | Default | Description |
|------|--------|---------|-------------|
| `--database` | Single value | `sqlite` | Database type |
**Available Database Values:**
- `sqlite` - SQLite database
- `postgres` - PostgreSQL
- `mysql` - MySQL
- `mongodb` - MongoDB
- `none` - No database
**Examples:**
```bash
--database postgres
--database none
```
#### ORM Options
| Flag | Values | Default | Description |
|------|--------|---------|-------------|
| `--orm` | Single value | `drizzle` | ORM/Database toolkit |
**Available ORM Values:**
- `drizzle` - Drizzle ORM (TypeScript-first)
- `prisma` - Prisma ORM (feature-rich)
- `mongoose` - Mongoose (MongoDB only)
- `none` - No ORM
**Examples:**
```bash
--orm drizzle
--orm prisma
--orm none
```
#### API Layer Options
| Flag | Values | Default | Description |
|------|--------|---------|-------------|
| `--api` | Single value | `trpc` | API layer type |
**Available API Values:**
- `trpc` - tRPC (end-to-end type safety)
- `orpc` - oRPC (OpenAPI compatible)
- `none` - No API layer
**Examples:**
```bash
--api trpc
--api orpc
--api none
```
#### Authentication Options
| Flag | Type | Default | Description |
|------|------|---------|-------------|
| `--auth` | boolean | `true` | Enable authentication |
| `--no-auth` | boolean | - | Disable authentication |
**Examples:**
```bash
--auth # Enable auth
--no-auth # Disable auth
```
#### Addons Options
| Flag | Values | Default | Description |
|------|--------|---------|-------------|
| `--addons` | Multiple values | `turborepo` | Additional features |
**Available Addon Values:**
- `turborepo` - Turborepo build system
- `pwa` - Progressive Web App support
- `tauri` - Desktop app with Tauri
- `biome` - Biome linter/formatter
- `husky` - Git hooks with Husky
- `starlight` - Documentation site
- `none` - No addons
**Examples:**
```bash
--addons turborepo pwa
--addons biome husky
--addons none
```
#### Examples Options
| Flag | Values | Default | Description |
|------|--------|---------|-------------|
| `--examples` | Multiple values | `[]` | Example applications |
**Available Example Values:**
- `todo` - Todo CRUD application
- `ai` - AI chat interface
- `none` - No examples
**Examples:**
```bash
--examples todo
--examples todo ai
--examples none
```
#### Database Setup Options
| Flag | Values | Default | Description |
|------|--------|---------|-------------|
| `--db-setup` | Single value | `none` | Database hosting setup |
**Available Database Setup Values:**
- `turso` - Turso SQLite hosting
- `neon` - Neon PostgreSQL
- `supabase` - Supabase PostgreSQL
- `prisma-postgres` - Prisma PostgreSQL
- `mongodb-atlas` - MongoDB Atlas
- `d1` - Cloudflare D1 (Workers only)
- `docker` - Local Docker setup
- `none` - Manual setup
**Examples:**
```bash
--db-setup neon
--db-setup docker
--db-setup none
```
#### Deployment Options
| Flag | Values | Default | Description |
|------|--------|---------|-------------|
| `--web-deploy` | Single value | `none` | Web deployment setup |
**Available Deployment Values:**
- `workers` - Cloudflare Workers
- `none` - No deployment setup
**Examples:**
```bash
--web-deploy workers
--web-deploy none
```
#### Project Management Options
| Flag | Type | Default | Description |
|------|------|---------|-------------|
| `--git` | boolean | `true` | Initialize git repository |
| `--no-git` | boolean | - | Skip git initialization |
| `--install` | boolean | `true` | Install dependencies |
| `--no-install` | boolean | - | Skip dependency installation |
| `--package-manager` | string | auto-detect | Package manager to use |
**Package Manager Values:**
- `npm` - Use npm
- `pnpm` - Use pnpm
- `bun` - Use bun
**Examples:**
```bash
--git --install --package-manager pnpm
--no-git --no-install
```
---
## `add` - Add to Existing Project
Add addons or deployment configurations to existing Better-T-Stack projects.
### Usage
```bash
# Interactive addon selection
npx create-better-t-stack@latest add
# Add specific addons
npx create-better-t-stack@latest add --addons pwa tauri
# Add deployment
npx create-better-t-stack@latest add --web-deploy workers
# Add both
npx create-better-t-stack@latest add --addons biome --web-deploy workers
```
### Flags
| Flag | Values | Description |
|------|--------|-------------|
| `--addons` | Multiple values | Addons to add (same as init) |
| `--web-deploy` | Single value | Deployment to add |
| `--project-dir` | string | Target project directory (default: current) |
| `--install` | boolean | Install dependencies after adding |
| `--no-install` | boolean | Skip dependency installation |
| `--package-manager` | string | Package manager to use |
### Examples
```bash
# Add PWA support to current project
npx create-better-t-stack@latest add --addons pwa
# Add multiple addons with dependency installation
npx create-better-t-stack@latest add --addons biome husky --install
# Add to specific project directory
npx create-better-t-stack@latest add --project-dir ./my-project --addons tauri
```
---
## `sponsors` - View Sponsors
Display Better-T-Stack project sponsors.
### Usage
```bash
npx create-better-t-stack@latest sponsors
```
Shows a list of project sponsors with their GitHub profiles and websites.
---
## `docs` - Open Documentation
Open Better-T-Stack documentation in your default browser.
### Usage
```bash
npx create-better-t-stack@latest docs
```
Opens: https://better-t-stack.dev/docs
---
## `builder` - Open Stack Builder
Open the web-based interactive stack builder.
### Usage
```bash
npx create-better-t-stack@latest builder
```
Opens: https://better-t-stack.dev/new
The web builder provides a visual interface for configuring your stack and generates the corresponding CLI command.
---
## Complete Examples
### Full-Stack Web Application
```bash
npx create-better-t-stack@latest my-webapp \
--frontend tanstack-router \
--backend hono \
--runtime bun \
--database postgres \
--orm drizzle \
--api trpc \
--auth \
--db-setup neon \
--addons pwa turborepo \
--examples todo ai
```
### Mobile + Web Application
```bash
npx create-better-t-stack@latest my-mobile-app \
--frontend tanstack-router native-nativewind \
--backend hono \
--database sqlite \
--orm drizzle \
--auth \
--db-setup turso \
--addons turborepo
```
### Cloudflare Workers Project
```bash
npx create-better-t-stack@latest my-workers-app \
--frontend tanstack-router \
--backend hono \
--runtime workers \
--database sqlite \
--orm drizzle \
--db-setup d1 \
--web-deploy workers
```
### API-Only Project
```bash
npx create-better-t-stack@latest my-api \
--frontend none \
--backend fastify \
--runtime node \
--database postgres \
--orm prisma \
--api trpc \
--db-setup docker
```
### Quick Defaults
```bash
# Use all defaults with immediate setup
npx create-better-t-stack@latest my-project --yes
# Convex full-stack (automatically configures compatible options)
npx create-better-t-stack@latest my-convex-app --backend convex
```
---
## Compatibility Notes
Some options have compatibility requirements:
- **Cloudflare Workers**: Only with `--backend hono`, `--orm drizzle`, `--runtime workers`
- **MongoDB**: Requires `--orm mongoose` or `--orm prisma`
- **Convex**: Incompatible with custom database/ORM/API options
- **PWA**: Requires compatible web frontend
- **Tauri**: Requires compatible web frontend
- **AI Examples**: Not compatible with `--backend elysia` or `--frontend solid`
The CLI will validate compatibility and show helpful error messages for invalid combinations.

View File

@@ -0,0 +1,334 @@
---
title: Frequently Asked Questions
description: Common questions and answers about Better-T-Stack CLI
---
## General Questions
### What is Better-T-Stack?
Better-T-Stack is a modern CLI tool that helps you scaffold end-to-end type-safe TypeScript projects. It provides opinionated, production-ready configurations for full-stack applications with support for multiple frontend frameworks, backend frameworks, databases, and deployment options.
### How is Better-T-Stack different from other scaffolding tools?
- **End-to-End Type Safety**: TypeScript across your entire stack with proper type sharing
- **Modern Stack Focus**: Latest versions of popular frameworks and tools
- **Production Ready**: Configurations used in real production applications
- **Highly Customizable**: Mix and match technologies based on your needs
- **Monorepo Structure**: Organized project structure with shared packages
- **Database Integration**: Built-in database setup and ORM configuration
- **Authentication**: Integrated auth with Better-Auth
- **Multi-Platform**: Web, mobile, and desktop app support in one project
### Is Better-T-Stack free to use?
Yes, Better-T-Stack is completely free and open-source under the MIT license. You can use it for personal and commercial projects without any restrictions.
### Do I need to know all these technologies to use Better-T-Stack?
No! Better-T-Stack is designed to help you learn modern full-stack development. Each generated project includes:
- Comprehensive README with setup instructions
- Example code and patterns
- TypeScript for better developer experience
- Best practices and folder structure
---
## Installation & Setup
### Which package manager should I use?
You can use any of the major package managers:
- **npm**: Most widely supported, comes with Node.js
- **pnpm**: Faster installs, better disk space efficiency
- **bun**: All-in-one runtime, extremely fast
For monorepo projects, we recommend **pnpm** for its excellent workspace support.
### Do I need to install the CLI globally?
No, you can use npx to run the latest version without installation:
```bash
npx create-better-t-stack@latest my-project
```
This ensures you always use the latest version with the newest features and bug fixes.
### What Node.js version do I need?
Better-T-Stack requires **Node.js 18 or higher**. We recommend using the latest LTS version for the best experience.
### Can I use Better-T-Stack with existing projects?
Better-T-Stack is designed for new projects. For existing projects, you can:
1. Create a new Better-T-Stack project
2. Gradually migrate your code
3. Use the `add` command to add specific features to existing Better-T-Stack projects
---
## Configuration & Stack Choices
### Can I change my stack choices after creating a project?
Some changes are possible:
- **Easy**: Add addons, examples, or deployment configurations using the `add` command
- **Medium**: Switch between compatible ORMs or databases (requires manual migration)
- **Hard**: Change frontend/backend frameworks (requires significant refactoring)
It's best to plan your stack carefully during initial setup.
### What's the difference between tRPC and oRPC?
- **tRPC**: End-to-end type safety with TypeScript inference, great for TypeScript-only projects
- **oRPC**: OpenAPI-compatible type-safe APIs, better for teams using multiple languages or requiring OpenAPI specs
Both provide excellent type safety, choose based on your team's needs.
### Should I use Drizzle or Prisma?
- **Drizzle**: TypeScript-first, lightweight, great for edge deployments, SQL-like syntax
- **Prisma**: Feature-rich, mature ecosystem, great tooling, GraphQL-like schema
Choose Drizzle for modern TypeScript projects and Prisma for feature-rich applications.
### What's the recommended stack for beginners?
For beginners, we recommend:
```bash
npx create-better-t-stack@latest my-first-project \
--frontend tanstack-router \
--backend hono \
--database sqlite \
--orm drizzle \
--auth \
--addons turborepo biome
```
This provides a simple but powerful full-stack setup that's easy to understand and deploy.
---
## Compatibility Questions
### Can I use MongoDB with Drizzle?
No, Drizzle doesn't support MongoDB. For MongoDB, use:
- **Prisma ORM**: Full ORM support for MongoDB
- **Mongoose**: Traditional MongoDB object modeling
### Why can't I use tRPC with Nuxt/SvelteKit/SolidJS?
tRPC is primarily designed for React ecosystems. For these frameworks, use:
- **oRPC**: Provides similar type safety with broader framework support
- **None**: Use the framework's built-in API capabilities
### Can I use Cloudflare Workers with any backend?
Cloudflare Workers runtime only supports:
- **Backend**: Hono only
- **Database**: SQLite with Cloudflare D1
- **ORM**: Drizzle only
This is due to the serverless nature and limitations of the Workers environment.
### Which addons work with which frontends?
| Addon | Compatible Frontends |
|-------|---------------------|
| PWA | TanStack Router, React Router, SolidJS, Next.js |
| Tauri | TanStack Router, React Router, Nuxt, SvelteKit, SolidJS, Next.js |
| Turborepo | All frontends |
| Biome | All frontends |
| Husky | All frontends |
| Starlight | All frontends |
---
## Database & Hosting
### What database should I choose for production?
**For small to medium applications:**
- **SQLite + Turso**: Excellent performance, easy scaling
- **PostgreSQL + Neon**: Serverless PostgreSQL, great for startups
**For large applications:**
- **PostgreSQL + Supabase**: Full backend-as-a-service
- **MongoDB + Atlas**: NoSQL flexibility with managed hosting
### Do I need Docker for development?
Docker is optional and only required for:
- **Database Setup**: If you choose `--db-setup docker`
- **Local Development**: Some setups like Supabase local development
Many database options (Turso, Neon, MongoDB Atlas) don't require Docker.
### How do I deploy my Better-T-Stack application?
Better-T-Stack projects are configured for easy deployment:
**Frontend:**
- **Vercel**: Zero-config deployment for Next.js, React apps
- **Netlify**: Static site deployment
- **Cloudflare Workers**: Edge deployment with `--web-deploy workers`
**Backend:**
- **Railway**: Easy backend deployment
- **Fly.io**: Global application deployment
- **Cloudflare Workers**: Serverless edge deployment
---
## Development & Troubleshooting
### My project won't start after creation. What should I do?
1. **Check Node.js version**: Ensure you're using Node.js 18+
2. **Install dependencies**: Run `npm install` in the project directory
3. **Check environment variables**: Copy `.env.example` to `.env` and fill in values
4. **Database setup**: Run database migrations if using a database
5. **Check the README**: Each project includes detailed setup instructions
### I'm getting TypeScript errors. How do I fix them?
1. **Install dependencies**: Ensure all packages are installed
2. **Restart TypeScript server**: In VS Code, use Ctrl/Cmd + Shift + P → "TypeScript: Restart TS Server"
3. **Check imports**: Ensure all imports are correct and packages are installed
4. **Update types**: Run `npm run check-types` to see detailed errors
### How do I update dependencies in my project?
```bash
# Check for updates
npx taze -r
# Update all dependencies
npm update
# Or with other package managers
pnpm update
bun update
```
### Can I use Better-T-Stack with VS Code?
Yes! Better-T-Stack projects work excellently with VS Code. We recommend these extensions:
- TypeScript and JavaScript Language Features (built-in)
- Tailwind CSS IntelliSense
- Prisma or Drizzle Kit extensions
- ESLint (if using Biome addon)
### My mobile app won't connect to the backend. What's wrong?
This is a common issue with Expo and local development:
1. **Check environment variables**: Update `EXPO_PUBLIC_SERVER_URL` in `apps/native/.env`
2. **Use your local IP**: Replace `localhost` with your computer's IP address
3. **Check firewall**: Ensure your firewall allows connections on port 3000
4. **Use tunnel**: Consider using `npx expo start --tunnel`
---
## Advanced Usage
### Can I customize the generated templates?
Currently, Better-T-Stack doesn't support custom templates, but you can:
1. Fork the repository and modify templates
2. Create a feature request for specific customizations
3. Modify the generated project after creation
### How do I contribute to Better-T-Stack?
We welcome contributions! Here's how to get started:
1. **Fork the repository** on GitHub
2. **Clone your fork** locally
3. **Install dependencies**: `pnpm install`
4. **Make your changes** and test them
5. **Submit a pull request** with a clear description
### Can I use Better-T-Stack in my company/team?
Absolutely! Better-T-Stack is perfect for:
- **Standardizing project structure** across teams
- **Onboarding new developers** with consistent setup
- **Rapid prototyping** and MVP development
- **Client projects** with proven, production-ready configurations
### How do I disable telemetry?
Better-T-Stack collects anonymous usage data to improve the tool. To disable:
```bash
# Disable for single run
BTS_TELEMETRY_DISABLED=1 npx create-better-t-stack@latest my-app
# Disable globally
export BTS_TELEMETRY_DISABLED=1
```
Add the export to your shell profile (`.bashrc`, `.zshrc`, etc.) to make it permanent.
---
## Getting Help
### Where can I get help?
- **Documentation**: Comprehensive guides at [better-t-stack.dev/docs](https://better-t-stack.dev/docs)
- **GitHub Issues**: Report bugs or request features
- **GitHub Discussions**: Community support and questions
- **Discord/Twitter**: Follow for updates and community discussion
### How do I report a bug?
1. **Search existing issues** to avoid duplicates
2. **Create a new issue** with:
- Clear description of the problem
- Steps to reproduce
- Your system information (OS, Node.js version, etc.)
- Generated project configuration
- Error messages or screenshots
### How do I request a new feature?
1. **Check existing feature requests** in GitHub Issues
2. **Create a new issue** with the "feature request" label
3. **Describe the feature** and its use case
4. **Explain why** it would benefit the community
### Is there a community?
Yes! You can connect with other Better-T-Stack users:
- **GitHub Discussions**: Ask questions and share projects
- **Twitter**: Follow [@AmanVarshney01](https://twitter.com/AmanVarshney01) for updates
- **Show your projects**: Tag us when you build something with Better-T-Stack!
---
## Sponsorship & Support
### How can I support Better-T-Stack?
- **⭐ Star the repository** on GitHub
- **🐛 Report bugs** and suggest improvements
- **💰 Sponsor the project** on GitHub Sponsors
- **📢 Share with others** who might find it useful
- **🤝 Contribute code** or documentation
### Who sponsors Better-T-Stack?
View current sponsors by running:
```bash
npx create-better-t-stack@latest sponsors
```
Or visit: [github.com/sponsors/AmanVarshney01](https://github.com/sponsors/AmanVarshney01)
---
*Still have questions? Feel free to ask in [GitHub Discussions](https://github.com/AmanVarshney01/create-better-t-stack/discussions) or check our [documentation](https://better-t-stack.dev/docs).*

View File

@@ -1,13 +1,118 @@
---
title: Introduction
title: Getting Started
description: A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations
---
Better-T-Stack is a modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations.
> ⚠️ **Warning:** Documentation is a work in progress.
# Why Better-T-Stack?
## What is Better-T-Stack?
Better-T-Stack lets you scaffold your projects for frontend, native apps, and backend with a single CLI command.
Better-T-Stack is designed to eliminate the complexity of setting up modern TypeScript projects. Instead of spending hours configuring build tools, type systems, databases, and deployment pipelines, you can get a production-ready project structure in minutes.
# Features
### Key Features
<Features />
- **🏗️ Full-Stack Ready**: Choose from multiple frontend and backend frameworks
- **🔒 End-to-End Type Safety**: TypeScript across your entire application stack
- **🗄️ Database Integration**: Support for SQLite, PostgreSQL, MySQL, and MongoDB
- **🔐 Built-in Authentication**: Email/password auth with Better-Auth
- **📱 Multi-Platform**: Web, mobile (React Native), and desktop (Tauri) support
- **☁️ Deployment Ready**: Configured for modern hosting platforms
- **⚡ Modern Tooling**: Latest versions of your favorite tools and frameworks
### Supported Technologies
#### Frontend Frameworks
- **React** with TanStack Router or React Router
- **Next.js** - Full-stack React framework
- **SvelteKit** - Web framework for Svelte
- **Nuxt** - Vue.js framework
- **SolidJS** - Performant reactive framework
- **TanStack Start** - SSR with TanStack Router
- **React Native** - Mobile development with Expo
#### Backend Frameworks
- **Hono** - Lightweight, ultrafast web framework
- **Express** - Popular Node.js framework
- **Fastify** - Fast, low-overhead framework
- **Elysia** - Type-safe, high-performance framework
- **Convex** - Reactive backend-as-a-service
- **Next.js API Routes** - Full-stack React
#### Databases & ORMs
- **Databases**: SQLite/Turso, PostgreSQL, MySQL, MongoDB
- **ORMs**: Drizzle (TypeScript-first), Prisma (feature-rich), Mongoose
- **Hosting**: Neon, Supabase, MongoDB Atlas, Cloudflare D1
#### API Layers
- **tRPC** - End-to-end type-safe APIs
- **oRPC** - OpenAPI-compatible type-safe APIs
### Why Choose Better-T-Stack?
#### Traditional Setup Problems
- ⏰ Hours of configuration and setup
- 🔧 Complex toolchain integration
- 📚 Overwhelming technology choices
- 🐛 Configuration bugs and compatibility issues
- 🏗️ Inconsistent project structures
#### Better-T-Stack Solutions
- ⚡ **Quick Setup**: Get started in under 2 minutes
- 🎯 **Curated Choices**: Pre-selected, compatible technology combinations
- 📋 **Best Practices**: Industry-standard configurations out of the box
- 🔄 **Consistent Structure**: Standardized monorepo organization
- 🧪 **Battle-Tested**: Configurations used in production applications
## Quick Example
```bash
# Create a new project
npx create-better-t-stack@latest my-app
# Choose your stack interactively or use flags
npx create-better-t-stack@latest my-app \
--frontend tanstack-router \
--backend hono \
--database postgres \
--orm drizzle \
--auth \
--addons pwa turborepo
```
## Project Types
Better-T-Stack supports various project configurations:
### Full-Stack Web Applications
Perfect for modern web apps with React, Vue, or Svelte frontends backed by type-safe APIs.
### Mobile Applications
Build React Native apps with Expo, sharing type definitions with your backend.
### Desktop Applications
Create cross-platform desktop apps using Tauri with your web frontend.
### API-Only Projects
Build standalone APIs and microservices with your preferred backend framework.
### Monorepo Projects
Organize multiple applications (web, mobile, API) in a single repository with shared packages.
## Who Should Use Better-T-Stack?
- **Indie Developers**: Quickly prototype and build full-stack applications
- **Startups**: Get to market faster with production-ready project structure
- **Teams**: Standardize project setup across your organization
- **Students**: Learn modern full-stack development with best practices
- **Agencies**: Rapidly scaffold client projects with consistent quality
## What's Next?
Ready to get started? Check out our [Quick Start Guide](/docs/quick-start) to create your first Better-T-Stack project, or explore the [Configuration Options](/docs/frontend) to learn about all available technologies and features.
### Need Help?
- 📖 **Documentation**: Comprehensive guides and references
- 🐛 **Issues**: Report bugs on [GitHub](https://github.com/AmanVarshney01/create-better-t-stack/issues)
- 💬 **Discussions**: Community support and questions
- 🌟 **Star us**: Show support on [GitHub](https://github.com/AmanVarshney01/create-better-t-stack)

View File

@@ -0,0 +1,236 @@
---
title: Installation
description: How to install and set up Better-T-Stack CLI
---
## System Requirements
Before installing Better-T-Stack, ensure your system meets these requirements:
- **Node.js**: Version 18 or higher
- **Package Manager**: npm, pnpm, or bun
- **Git**: For repository initialization (optional but recommended)
### Optional Dependencies
Depending on your project configuration, you may need:
- **Docker**: For local database development with Docker Compose
- **Rust & System Dependencies**: For Tauri desktop applications
- **Cloudflare CLI**: For Workers deployment
## Quick Start (Recommended)
The fastest way to get started is using npx, which runs the latest version without installation:
```bash
npx create-better-t-stack@latest my-project
```
This command will:
1. Download the latest version of the CLI
2. Run the interactive setup wizard
3. Create your project in the `my-project` directory
## Package Manager Specific Commands
### npm
```bash
# Run without installing
npx create-better-t-stack@latest my-project
# Or install globally
npm install -g create-better-t-stack
create-better-t-stack my-project
```
### pnpm
```bash
# Run without installing (recommended)
pnpm create better-t-stack@latest my-project
# Or install globally
pnpm add -g create-better-t-stack
create-better-t-stack my-project
```
### bun
```bash
# Run without installing (recommended)
bun create better-t-stack@latest my-project
# Or install globally
bun add -g create-better-t-stack
create-better-t-stack my-project
```
## Global Installation
If you frequently create new projects, you might want to install the CLI globally:
<Tabs items={['npm', 'pnpm', 'bun']}>
<Tab value="npm">
```bash
npm install -g create-better-t-stack
```
</Tab>
<Tab value="pnpm">
```bash
pnpm add -g create-better-t-stack
```
</Tab>
<Tab value="bun">
```bash
bun add -g create-better-t-stack
```
</Tab>
</Tabs>
After global installation, you can run:
```bash
create-better-t-stack my-project
```
## Verification
Verify your installation by checking the version:
```bash
# If installed globally
create-better-t-stack --version
# Or with npx
npx create-better-t-stack@latest --version
```
You should see output similar to:
```
2.26.3
```
## Development Installation
For contributing to Better-T-Stack or running the latest development version:
```bash
# Clone the repository
git clone https://github.com/AmanVarshney01/create-better-t-stack.git
cd create-better-t-stack
# Install dependencies
pnpm install
# Build the CLI
cd apps/cli
pnpm build
# Link for local development
pnpm link --global
```
## Troubleshooting
### Common Issues
#### Permission Errors (npm)
If you encounter permission errors with npm global installation:
```bash
# Use npx instead (recommended)
npx create-better-t-stack@latest my-project
# Or configure npm to use a different directory
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
```
#### Node.js Version Issues
Ensure you're using Node.js 18 or higher:
```bash
node --version
```
If you need to upgrade Node.js:
- **Using nvm**: `nvm install 18 && nvm use 18`
- **Using n**: `n 18`
- **Download**: Visit [nodejs.org](https://nodejs.org/)
#### Package Manager Not Found
If you prefer a specific package manager but it's not installed:
```bash
# Install pnpm
npm install -g pnpm
# Install bun
curl -fsSL https://bun.sh/install | bash
```
#### Network Issues
If you experience network timeouts or connection issues:
```bash
# Try with different registry
npm config set registry https://registry.npmjs.org/
# Or clear npm cache
npm cache clean --force
```
## Next Steps
Once installed, you're ready to create your first project:
1. **Quick Start**: Follow our [Quick Start Guide](/docs/quick-start)
2. **Configuration**: Learn about [Configuration Options](/docs/frontend)
3. **CLI Reference**: Explore all [CLI Commands](/docs/cli-commands)
## Staying Updated
To ensure you're always using the latest version with bug fixes and new features:
### Using npx (Automatic)
When using `npx create-better-t-stack@latest`, you automatically get the latest version.
### Global Installation Updates
If you have it installed globally, update regularly:
<Tabs items={['npm', 'pnpm', 'bun']}>
<Tab value="npm">
```bash
npm update -g create-better-t-stack
```
</Tab>
<Tab value="pnpm">
```bash
pnpm update -g create-better-t-stack
```
</Tab>
<Tab value="bun">
```bash
bun update -g create-better-t-stack
```
</Tab>
</Tabs>
### Release Notes
Stay informed about new features and changes:
- **GitHub Releases**: [View releases](https://github.com/AmanVarshney01/create-better-t-stack/releases)
- **Changelog**: Check the repository for detailed changes
- **Breaking Changes**: Major version updates may include breaking changes

View File

@@ -1,3 +1,33 @@
{
"pages": ["---Getting Started---", "index"]
"pages": [
"index",
"---Getting Started---",
"installation",
"quick-start",
"project-structure",
"---Configuration Options---",
"frontend",
"backend",
"database",
"orm",
"authentication",
"runtime",
"api-layer",
"---Addons & Features---",
"addons",
"examples",
"deployment",
"---Database Setup---",
"database-providers",
"---CLI Reference---",
"cli-commands",
"cli-flags",
"---Guides---",
"migration-guide",
"troubleshooting",
"best-practices",
"---FAQ---",
"faq",
"compatibility"
]
}

1
apps/web/lib/cn.ts Normal file
View File

@@ -0,0 +1 @@
export { twMerge as cn } from "tailwind-merge";

View File

@@ -1 +1 @@
<svg viewBox="0 0 256 199" width="256" height="199" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"><path d="M216.856 16.597A208.502 208.502 0 0 0 164.042 0c-2.275 4.113-4.933 9.645-6.766 14.046-19.692-2.961-39.203-2.961-58.533 0-1.832-4.4-4.55-9.933-6.846-14.046a207.809 207.809 0 0 0-52.855 16.638C5.618 67.147-3.443 116.4 1.087 164.956c22.169 16.555 43.653 26.612 64.775 33.193A161.094 161.094 0 0 0 79.735 175.3a136.413 136.413 0 0 1-21.846-10.632 108.636 108.636 0 0 0 5.356-4.237c42.122 19.702 87.89 19.702 129.51 0a131.66 131.66 0 0 0 5.355 4.237 136.07 136.07 0 0 1-21.886 10.653c4.006 8.02 8.638 15.67 13.873 22.848 21.142-6.58 42.646-16.637 64.815-33.213 5.316-56.288-9.08-105.09-38.056-148.36ZM85.474 135.095c-12.645 0-23.015-11.805-23.015-26.18s10.149-26.2 23.015-26.2c12.867 0 23.236 11.804 23.015 26.2.02 14.375-10.148 26.18-23.015 26.18Zm85.051 0c-12.645 0-23.014-11.805-23.014-26.18s10.148-26.2 23.014-26.2c12.867 0 23.236 11.804 23.015 26.2 0 14.375-10.148 26.18-23.015 26.18Z" fill="#5865F2"/></svg>
<?xml version="1.0" encoding="UTF-8"?><svg id="Discord-Logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 126.644 96"><path id="Discord-Symbol-Black" d="M81.15,0c-1.2376,2.1973-2.3489,4.4704-3.3591,6.794-9.5975-1.4396-19.3718-1.4396-28.9945,0-.985-2.3236-2.1216-4.5967-3.3591-6.794-9.0166,1.5407-17.8059,4.2431-26.1405,8.0568C2.779,32.5304-1.6914,56.3725.5312,79.8863c9.6732,7.1476,20.5083,12.603,32.0505,16.0884,2.6014-3.4854,4.8998-7.1981,6.8698-11.0623-3.738-1.3891-7.3497-3.1318-10.8098-5.1523.9092-.6567,1.7932-1.3386,2.6519-1.9953,20.281,9.547,43.7696,9.547,64.0758,0,.8587.7072,1.7427,1.3891,2.6519,1.9953-3.4601,2.0457-7.0718,3.7632-10.835,5.1776,1.97,3.8642,4.2683,7.5769,6.8698,11.0623,11.5419-3.4854,22.3769-8.9156,32.0509-16.0631,2.626-27.2771-4.496-50.9172-18.817-71.8548C98.9811,4.2684,90.1918,1.5659,81.1752.0505l-.0252-.0505ZM42.2802,65.4144c-6.2383,0-11.4159-5.6575-11.4159-12.6535s4.9755-12.6788,11.3907-12.6788,11.5169,5.708,11.4159,12.6788c-.101,6.9708-5.026,12.6535-11.3907,12.6535ZM84.3576,65.4144c-6.2637,0-11.3907-5.6575-11.3907-12.6535s4.9755-12.6788,11.3907-12.6788,11.4917,5.708,11.3906,12.6788c-.101,6.9708-5.026,12.6535-11.3906,12.6535Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -84,7 +84,7 @@ export default function FeatureCard({
layout
>
<div>
<h4 className="pb-2 text-center font-mono font-semibold text-foreground text-sm">
<h4 className="pb-2 text-center font-semibold text-foreground text-sm">
{title}
</h4>
</div>

View File

@@ -25,13 +25,13 @@ const CodeContainer = () => {
const packageManagers: Array<"npm" | "pnpm" | "bun"> = ["bun", "pnpm", "npm"];
return (
<div className="mx-auto mt-6 w-full max-w-3xl px-2 font-mono md:px-0">
<div className="mx-auto mt-6 w-full max-w-3xl px-2 md:px-0">
<div className="overflow-hidden rounded-lg border border-border bg-muted/30 shadow-sm">
<div className="flex items-center justify-between border-border border-b bg-muted/50 px-4 py-2">
<span className="text-muted-foreground text-xs">
Package manager:
</span>
<div className="flex items-center rounded-md border border-border bg-background p-0.5">
<div className="flex items-center rounded-md border border-border p-0.5">
{packageManagers.map((pm) => (
<button
type="button"
@@ -51,7 +51,7 @@ const CodeContainer = () => {
</div>
</div>
<div className="relative bg-background p-4 text-sm">
<div className="relative p-4 text-sm">
<div className="flex items-center gap-2 overflow-x-auto pb-1">
<span className="select-none text-muted-foreground">$</span>
<code className="whitespace-pre text-foreground">
@@ -64,7 +64,7 @@ const CodeContainer = () => {
type="button"
onClick={copyToClipboard}
className={cn(
"flex h-7 w-7 items-center justify-center rounded border bg-background text-muted-foreground transition-all duration-150 hover:border-border hover:bg-muted hover:text-foreground",
"flex h-7 w-7 items-center justify-center rounded border text-muted-foreground transition-all duration-150 hover:border-border hover:bg-muted hover:text-foreground",
copied
? "border-chart-4/50 bg-chart-4/10 text-chart-4"
: "border-border",

View File

@@ -3,7 +3,7 @@ import StackBuilder from "./stack-builder";
export default function CustomizableSection() {
return (
<section className="relative z-10 mx-auto mt-20 w-full max-w-7xl space-y-16 px-4 sm:px-6">
<section className="relative z-10 mx-auto mt-20 w-full space-y-16 px-4 sm:px-6">
<div className="relative space-y-8 text-center">
<motion.div
initial={{ opacity: 0, y: 20 }}
@@ -12,7 +12,7 @@ export default function CustomizableSection() {
transition={{ duration: 0.5 }}
className="relative"
>
<h2 className="font-bold font-mono text-2xl tracking-tight sm:text-3xl md:text-4xl lg:text-5xl">
<h2 className="font-bold text-2xl tracking-tight sm:text-3xl md:text-4xl lg:text-5xl">
<span className="border-primary border-b-2 pb-1 text-foreground dark:text-primary">
Roll Your Own Stack
</span>
@@ -26,7 +26,7 @@ export default function CustomizableSection() {
transition={{ duration: 0.5, delay: 0.2 }}
className="mx-auto max-w-3xl space-y-6"
>
<p className="font-mono text-lg text-muted-foreground leading-relaxed sm:text-xl">
<p className=" text-lg text-muted-foreground leading-relaxed sm:text-xl">
Build your perfect TypeScript stack.
</p>
</motion.div>

View File

@@ -3,8 +3,8 @@ import Link from "next/link";
const Footer = () => {
return (
<footer className="relative w-full border-border border-t font-mono">
<div className="mx-auto max-w-7xl px-4 py-12 sm:px-6">
<footer className="relative w-full border-border border-t ">
<div className="mx-auto px-4 py-12 sm:px-6">
<div className="mb-12 grid gap-8 md:grid-cols-3">
<div>
<h3 className="mb-4 flex items-center gap-2 font-semibold text-base text-foreground">
@@ -95,7 +95,7 @@ const Footer = () => {
</h3>
<div className="space-y-2.5 text-muted-foreground">
<p className="flex items-center">
<span className="mr-2 rounded bg-muted px-2 py-1 font-mono text-sm">
<span className="mr-2 rounded bg-muted px-2 py-1 text-sm">
$
</span>
<span>amanvarshney.work@gmail.com</span>

View File

@@ -98,11 +98,11 @@ export default function Navbar() {
className={cn(
"fixed top-0 z-[100] w-full transition-all duration-300 ease-in-out",
scrolled
? "border-border border-b bg-background/80 shadow-sm backdrop-blur-md"
? " border- border-border shadow-sm backdrop-blur-md"
: "border-transparent border-b bg-transparent",
)}
>
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8">
<div className="mx-auto flex h-16 items-center justify-between px-4 sm:px-6 lg:px-8">
<Link href="/" className="flex flex-shrink-0 items-center gap-2">
<Image
src="/logo.svg"
@@ -123,7 +123,7 @@ export default function Navbar() {
key={link.href}
href={link.href}
target={link.target}
className="relative flex items-center gap-1.5 rounded-md px-3 py-1.5 font-mono text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-primary"
className="relative flex items-center gap-1.5 rounded-md px-3 py-1.5 text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-primary"
>
{link.icon}
<span>{link.label}</span>
@@ -137,7 +137,7 @@ export default function Navbar() {
<Link
href="https://github.com/sponsors/AmanVarshney01"
target="_blank"
className="inline-flex items-center gap-1.5 rounded-md border border-border bg-muted/90 px-3 py-1.5 font-mono text-muted-foreground text-xs backdrop-blur-sm transition-colors hover:bg-muted hover:text-foreground"
className="inline-flex items-center gap-1.5 rounded-md border border-border bg-muted/90 px-3 py-1.5 text-muted-foreground text-xs backdrop-blur-sm transition-colors hover:bg-muted hover:text-foreground"
title="Sponsor on GitHub"
>
<Heart className="size-3.5" />
@@ -145,7 +145,7 @@ export default function Navbar() {
</Link>
<Link
href="/new"
className="inline-flex items-center gap-1.5 rounded-md border border-primary/50 bg-primary/10 px-3 py-1.5 font-mono text-primary text-xs transition-colors hover:bg-primary/20"
className="inline-flex items-center gap-1.5 rounded-md border border-primary/50 bg-primary/10 px-3 py-1.5 text-primary text-xs transition-colors hover:bg-primary/20"
title="Stack Builder"
>
<Maximize2 className="size-3.5" />
@@ -183,7 +183,7 @@ export default function Navbar() {
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2, ease: "easeInOut" }}
className="fixed inset-0 z-[98] bg-background/50 backdrop-blur-sm lg:hidden"
className=" fixed inset-0 z-[98 backdrop-blur-sm lg:hidden"
onClick={closeMobileMenu}
aria-hidden="true"
/>
@@ -193,7 +193,7 @@ export default function Navbar() {
animate={{ x: 0 }}
exit={{ x: "100%" }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
className="fixed top-0 right-0 bottom-0 z-[99] h-full w-full max-w-xs overflow-y-auto border-border border-l bg-background shadow-lg lg:hidden"
className="fixed top-0 right-0 bottom-0 z-[99] h-full w-full max-w-xs overflow-y-auto border-border border-l shadow-lg lg:hidden"
aria-modal="true"
>
<div className="flex h-16 items-center justify-between border-border border-b px-4">
@@ -218,7 +218,7 @@ export default function Navbar() {
href={link.href}
target={link.target}
onClick={closeMobileMenu}
className="flex items-center gap-3 rounded-md px-3 py-3 font-mono text-base text-muted-foreground transition-colors hover:bg-muted hover:text-primary"
className="flex items-center gap-3 rounded-md px-3 py-3 text-base text-muted-foreground transition-colors hover:bg-muted hover:text-primary"
>
{link.icon ? (
<span className="flex w-5 items-center justify-center">
@@ -236,7 +236,7 @@ export default function Navbar() {
<Link
href="/new"
onClick={closeMobileMenu}
className="flex w-full items-center justify-center gap-2 rounded-md border border-primary/50 bg-primary/10 px-4 py-2.5 font-mono text-primary text-sm transition-colors hover:bg-primary/20"
className="flex w-full items-center justify-center gap-2 rounded-md border border-primary/50 bg-primary/10 px-4 py-2.5 text-primary text-sm transition-colors hover:bg-primary/20"
>
<Maximize2 className="size-4" />
Stack Builder
@@ -245,7 +245,7 @@ export default function Navbar() {
href="https://github.com/sponsors/AmanVarshney01"
target="_blank"
onClick={closeMobileMenu}
className="flex w-full items-center justify-center gap-2 rounded-md border border-border bg-muted/90 px-4 py-2.5 font-mono text-muted-foreground text-sm backdrop-blur-sm transition-colors hover:bg-muted hover:text-foreground"
className="flex w-full items-center justify-center gap-2 rounded-md border border-border bg-muted/90 px-4 py-2.5 text-muted-foreground text-sm backdrop-blur-sm transition-colors hover:bg-muted hover:text-foreground"
>
<Heart className="size-4" />
Sponsor on GitHub

View File

@@ -35,7 +35,7 @@ const NpmPackage = () => {
versionLoading && "animate-pulse",
)}
/>
<span className="font-mono text-muted-foreground text-xl">
<span className=" text-muted-foreground text-xl">
{versionLoading ? "[v?.?.?]" : `[v${version}]`}
</span>
</div>

View File

@@ -54,73 +54,69 @@ export default function SponsorsSection() {
<div className="mb-6 flex flex-wrap items-center justify-between gap-2 sm:flex-nowrap">
<div className="flex items-center gap-2">
<Terminal className="h-5 w-5 text-primary" />
<span className="font-bold font-mono text-lg sm:text-xl">
<span className="font-bold text-lg sm:text-xl">
SPONSORS_DATABASE.JSON
</span>
</div>
<div className="hidden h-px flex-1 bg-border sm:block" />
<span className="w-full text-right font-mono text-muted-foreground text-xs sm:w-auto sm:text-left">
<span className="w-full text-right text-muted-foreground text-xs sm:w-auto sm:text-left">
[{loadingSponsors ? "LOADING..." : sponsors.length} RECORDS]
</span>
</div>
<div className="terminal-block-hover mb-8 rounded border border-border bg-muted/20 p-4">
<div className="mb-8 rounded border border-border p-4">
<div className="flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-foreground">
# Amazing organizations and individuals supporting this project
<span className=" text-foreground">
Amazing organizations and individuals supporting this project
</span>
</div>
<div className="mt-2 flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-muted-foreground">
# Your support helps maintain and improve Better-T-Stack
<span className=" text-muted-foreground">
Your support helps maintain and improve Better-T-Stack
</span>
</div>
</div>
{loadingSponsors ? (
<div className="terminal-block-hover rounded border border-border bg-muted/20 p-8">
<div className="rounded border border-border p-8">
<div className="flex items-center justify-center gap-2">
<div className="h-2 w-2 animate-pulse rounded-full bg-primary" />
<span className="font-mono text-muted-foreground">
LOADING_SPONSORS.EXE
</span>
<span className=" text-muted-foreground">LOADING_SPONSORS.EXE</span>
<div className="h-2 w-2 animate-pulse rounded-full bg-primary" />
</div>
</div>
) : sponsorError ? (
<div className="terminal-block-hover rounded border border-border bg-destructive/10 p-8">
<div className="rounded border border-border bg-destructive/10 p-8">
<div className="flex items-center justify-center gap-2">
<span className="text-destructive"></span>
<span className="font-mono text-destructive">
ERROR: {sponsorError}
</span>
<span className=" text-destructive">ERROR: {sponsorError}</span>
</div>
</div>
) : sponsors.length === 0 ? (
<div className="space-y-4">
<div className="terminal-block-hover rounded border border-border bg-muted/20 p-8">
<div className="rounded border border-border p-8">
<div className="text-center">
<div className="mb-4 flex items-center justify-center gap-2">
<span className="font-mono text-muted-foreground">
<span className=" text-muted-foreground">
NO_SPONSORS_FOUND.NULL
</span>
</div>
<div className="flex items-center justify-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-muted-foreground">
# Be the first to support this project!
<span className=" text-muted-foreground">
Be the first to support this project!
</span>
</div>
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background p-4">
<div className="rounded border border-border p-4">
<a
href="https://github.com/sponsors/AmanVarshney01"
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center gap-2 font-mono text-primary transition-colors hover:text-accent"
className="flex items-center justify-center gap-2 text-primary transition-colors hover:text-accent"
>
<Heart className="h-4 w-4" />
<span>BECOME_SPONSOR.EXE</span>
@@ -138,10 +134,10 @@ export default function SponsorsSection() {
return (
<div
key={entry.sponsor.login}
className="terminal-block-hover rounded border border-border bg-background"
className="rounded border border-border"
style={{ animationDelay: `${index * 50}ms` }}
>
<div className="border-border border-b bg-muted/20 px-3 py-2">
<div className="border-border border-b px-3 py-2">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<div className="ml-auto flex items-center gap-2 text-muted-foreground text-xs">
@@ -159,17 +155,17 @@ export default function SponsorsSection() {
alt={entry.sponsor.name || entry.sponsor.login}
width={100}
height={100}
className="rounded border border-border bg-background transition-colors duration-300"
className="rounded border border-border transition-colors duration-300"
unoptimized
/>
</div>
<div className="min-w-0 flex-1 space-y-2">
<div>
<h3 className="truncate font-mono font-semibold text-foreground text-sm">
<h3 className="truncate font-semibold text-foreground text-sm">
{entry.sponsor.name || entry.sponsor.login}
</h3>
{entry.tierName && (
<p className="font-mono text-primary text-xs">
<p className=" text-primary text-xs">
{entry.tierName}
</p>
)}
@@ -179,7 +175,7 @@ export default function SponsorsSection() {
href={`https://github.com/${entry.sponsor.login}`}
target="_blank"
rel="noopener noreferrer"
className="group flex items-center gap-2 font-mono text-muted-foreground text-xs transition-colors hover:text-primary"
className="group flex items-center gap-2 text-muted-foreground text-xs transition-colors hover:text-primary"
>
<Github className="h-4 w-4" />
<span className="truncate">
@@ -195,7 +191,7 @@ export default function SponsorsSection() {
}
target="_blank"
rel="noopener noreferrer"
className="group flex items-center gap-2 font-mono text-muted-foreground text-xs transition-colors hover:text-primary"
className="group flex items-center gap-2 text-muted-foreground text-xs transition-colors hover:text-primary"
>
<Globe className="h-4 w-4" />
<span className="truncate">
@@ -209,7 +205,7 @@ export default function SponsorsSection() {
</a>
)}
{/* <div className="flex items-center gap-2 font-mono text-muted-foreground text-xs">
{/* <div className="flex items-center gap-2 text-muted-foreground text-xs">
<span className="text-xs">👤</span>
<span>{entry.sponsor.type.toUpperCase()}</span>
</div> */}
@@ -222,12 +218,12 @@ export default function SponsorsSection() {
})}
</div>
<div className="terminal-block-hover rounded border border-border bg-background p-4">
<div className="rounded border border-border p-4">
<a
href="https://github.com/sponsors/AmanVarshney01"
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center gap-2 font-mono text-primary transition-colors hover:text-accent"
className="flex items-center justify-center gap-2 text-primary transition-colors hover:text-accent"
>
<Heart className="h-4 w-4" />
<span>SUPPORT_PROJECT.EXE</span>

View File

@@ -3,7 +3,6 @@
import {
Check,
ClipboardCopy,
Github,
InfoIcon,
RefreshCw,
Settings,
@@ -14,13 +13,11 @@ import {
} from "lucide-react";
import { motion } from "motion/react";
import Image from "next/image";
import Link from "next/link";
import { useTheme } from "next-themes";
import { useQueryStates } from "nuqs";
import type React from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { ThemeToggle } from "@/components/theme-toggle";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
Tooltip,
@@ -37,7 +34,6 @@ import {
} from "@/lib/constant";
import { stackParsers, stackQueryStatesOptions } from "@/lib/stack-url-state";
import { cn } from "@/lib/utils";
import discordLogo from "@/public/icon/discord.svg";
const validateProjectName = (name: string): string | undefined => {
const INVALID_CHARS = ["<", ">", ":", '"', "|", "?", "*"];
@@ -1455,49 +1451,9 @@ const StackBuilder = () => {
<TooltipProvider>
<div
className={cn(
"flex h-svh flex-col overflow-hidden border-border bg-background text-foreground",
"grid grid-cols-1 overflow-hidden border-border text-foreground",
)}
>
<div
className={cn(
"grid w-full flex-shrink-0 grid-cols-2 items-center justify-center border-border border-b bg-background px-2 py-2 sm:grid-cols-3 sm:px-4",
)}
>
<Link href={"/"}>
<div className="mr-auto font-mono text-muted-foreground text-xs">
Home
</div>
</Link>
<div className="mx-auto hidden font-mono text-muted-foreground text-xs sm:block">
Create Better T Stack
</div>
<div className="ml-auto flex space-x-2">
<Link
href={"https://github.com/AmanVarshney01/create-better-t-stack"}
target="_blank"
rel="noopener noreferrer"
className={cn(
"text-muted-foreground transition-colors hover:text-foreground",
)}
title="GitHub Repository"
>
<Github className="h-4 w-4" />
</Link>
<Link
href={"https://discord.gg/ZYsbjpDaM5"}
target="_blank"
rel="noopener noreferrer"
className={cn(
"text-muted-foreground transition-colors hover:text-foreground",
)}
title="Join Discord"
>
<Image src={discordLogo} alt="discord" className="size-4" />{" "}
</Link>
<ThemeToggle />
</div>
</div>
<div className="grid grid-cols-1 overflow-hidden sm:grid-cols-[auto_1fr]">
<div className="flex h-full max-w-full flex-col justify-between border-border border-r p-4 sm:max-w-3xs md:max-w-xs lg:max-w-sm">
<div className="flex flex-col space-y-4">
@@ -1513,7 +1469,7 @@ const StackBuilder = () => {
setStack({ projectName: newValue });
}}
className={cn(
"w-full rounded border bg-background px-2 py-1 font-mono text-sm focus:outline-none",
"w-full rounded border px-2 py-1 text-sm focus:outline-none",
projectNameError
? "border-destructive bg-destructive/10 text-destructive-foreground"
: "border-border focus:border-primary",
@@ -1530,7 +1486,7 @@ const StackBuilder = () => {
<button
type="button"
onClick={resetStack}
className="flex items-center gap-1 rounded border border-border bg-background px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
title="Reset to defaults"
>
<RefreshCw className="h-3 w-3" />
@@ -1539,7 +1495,7 @@ const StackBuilder = () => {
<button
type="button"
onClick={getRandomStack}
className="flex items-center gap-1 rounded border border-border bg-background px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
title="Generate a random stack"
>
<Shuffle className="h-3 w-3" />
@@ -1549,7 +1505,7 @@ const StackBuilder = () => {
<button
type="button"
onClick={loadSavedStack}
className="flex items-center gap-1 rounded border border-border bg-background px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
title="Load saved preferences"
>
<Settings className="h-3 w-3" />
@@ -1559,7 +1515,7 @@ const StackBuilder = () => {
<button
type="button"
onClick={saveCurrentStack}
className="flex items-center gap-1 rounded border border-border bg-background px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
title="Save current preferences"
>
<Star className="h-3 w-3" />
@@ -1568,14 +1524,14 @@ const StackBuilder = () => {
<button
type="button"
onClick={shareToTwitter}
className="flex items-center gap-1 rounded border border-border bg-background px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
title="Share to Twitter"
>
<Share2 className="h-3 w-3" />
Share
</button>
</div>
<div className="relative rounded border border-border bg-background p-2">
<div className="relative rounded border border-border p-2">
<div className="flex">
<span className="mr-2 select-none text-chart-4">$</span>
<code className="block break-all text-muted-foreground text-xs sm:text-sm">
@@ -1625,7 +1581,7 @@ const StackBuilder = () => {
type="button"
key={preset.id}
onClick={() => applyPreset(preset.id)}
className="rounded border border-border bg-background p-2 text-left transition-colors hover:bg-muted"
className="rounded border border-border p-2 text-left transition-colors hover:bg-muted"
title={preset.description}
>
<div className="font-medium text-foreground text-sm">
@@ -1687,7 +1643,7 @@ const StackBuilder = () => {
)}
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-4">
<div className="grid grid-cols-2 gap-3 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-4">
{filteredOptions.map((tech) => {
let isSelected = false;
const category = categoryKey as keyof StackState;

View File

@@ -118,11 +118,11 @@ export default function Testimonials() {
ease: "easeOut",
}}
>
<div className="terminal-block-hover w-full min-w-0 overflow-hidden rounded border border-border bg-background">
<div className="sticky top-0 z-10 border-border border-b bg-muted/20 px-3 py-2">
<div className="w-full min-w-0 overflow-hidden rounded border border-border">
<div className="sticky top-0 z-10 border-border border-b px-3 py-2">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-xs">
<span className=" font-semibold text-xs">
[TWEET_{String(index + 1).padStart(3, "0")}]
</span>
</div>
@@ -141,27 +141,27 @@ export default function Testimonials() {
<div className="mb-6 flex flex-wrap items-center justify-between gap-2 sm:flex-nowrap">
<div className="flex items-center gap-2">
<Terminal className="h-5 w-5 text-primary" />
<span className="font-bold font-mono text-lg sm:text-xl">
<span className="font-bold text-lg sm:text-xl">
DEVELOPER_TESTIMONIALS.LOG
</span>
</div>
<div className="hidden h-px flex-1 bg-border sm:block" />
<span className="w-full text-right font-mono text-muted-foreground text-xs sm:w-auto sm:text-left">
<span className="w-full text-right text-muted-foreground text-xs sm:w-auto sm:text-left">
[{TWEET_IDS.length} ENTRIES]
</span>
</div>
<div className="terminal-block-hover mb-8 rounded border border-border bg-muted/20 p-4">
<div className="mb-8 rounded border border-border p-4">
<div className="flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-foreground">
# Community feedback from X (Twitter)
<span className=" text-foreground">
Community feedback from X (Twitter)
</span>
</div>
<div className="mt-2 flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-muted-foreground">
# Real developers sharing their experience
<span className=" text-muted-foreground">
Real developers sharing their experience
</span>
</div>
</div>

View File

@@ -25,7 +25,6 @@ import {
ChartTooltipContent,
} from "@/components/ui/chart";
import discordLogo from "@/public/icon/discord.svg";
import Navbar from "../_components/navbar";
interface AnalyticsData {
date: string;
@@ -947,40 +946,39 @@ export default function AnalyticsPage() {
const hourlyDistributionData = getHourlyDistributionData();
return (
<div className="terminal-scanlines min-h-screen bg-background font-mono">
<Navbar />
<div className="terminal-matrix-bg container mx-auto max-w-7xl space-y-8 px-4 py-8 pt-28">
<div className="min-h-svh">
<div className="container mx-auto space-y-8 px-4 py-8 pt-16">
<div className="mb-8">
<div className="mb-6 flex flex-wrap items-center justify-between gap-2 sm:flex-nowrap">
<div className="flex items-center gap-2">
<Terminal className="h-5 w-5 text-primary" />
<span className="font-bold font-mono text-lg sm:text-xl">
<span className="font-bold text-lg sm:text-xl">
ANALYTICS_DASHBOARD.EXE
</span>
</div>
<div className="hidden h-px flex-1 bg-border sm:block" />
<span className="w-full text-right font-mono text-muted-foreground text-xs sm:w-auto sm:text-left">
<span className="w-full text-right text-muted-foreground text-xs sm:w-auto sm:text-left">
[{totalProjects} PROJECTS_ANALYZED]
</span>
</div>
<div className="terminal-block-hover rounded rounded-b-none border border-border bg-muted/20 p-4">
<div className="rounded rounded-b-none border border-border p-4">
<div className="flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-foreground">
<span className=" text-foreground">
Analytics from Better-T-Stack CLI usage data
</span>
</div>
<div className="mt-2 flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-muted-foreground">
<span className=" text-muted-foreground">
Uses PostHog - no personal info tracked, runs on each project
creation
</span>
</div>
<div className="mt-2 flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-muted-foreground">
<span className=" text-muted-foreground">
Source:{" "}
<Link
href="https://github.com/amanvarshney01/create-better-t-stack/blob/main/apps/cli/src/utils/analytics.ts"
@@ -1003,7 +1001,7 @@ export default function AnalyticsPage() {
</div>
<div className="mt-2 flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-muted-foreground">
<span className=" text-muted-foreground">
Last updated:{" "}
{loadingLastUpdated
? "CHECKING..."
@@ -1018,23 +1016,27 @@ export default function AnalyticsPage() {
href="https://discord.gg/ZYsbjpDaM5"
target="_blank"
rel="noopener noreferrer"
className="terminal-block-hover block rounded rounded-t-none border border-border border-t-0 bg-background"
className="block rounded rounded-t-none border border-border border-t-0"
>
<div className="flex items-center justify-between p-3">
<div className="flex items-center gap-3">
<Image src={discordLogo} alt="discord" className="h-4 w-4" />
<Image
src={discordLogo}
alt="discord"
className="h-4 w-4 invert-0 dark:invert"
/>
<div>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
DISCORD_NOTIFICATIONS.IRC
</span>
<p className="font-mono text-muted-foreground text-xs">
<p className=" text-muted-foreground text-xs">
Join for LIVE project creation alerts
</p>
</div>
</div>
<div className="flex items-center gap-1 rounded border border-border bg-primary/10 px-2 py-1">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-primary text-xs">
<span className=" font-semibold text-primary text-xs">
JOIN
</span>
</div>
@@ -1044,162 +1046,144 @@ export default function AnalyticsPage() {
<div className="space-y-4">
<div className="mb-4 flex items-center gap-2">
<span className="font-bold font-mono text-lg">
SYSTEM_METRICS.LOG
</span>
<span className="font-bold text-lg">SYSTEM_METRICS.LOG</span>
<div className="h-px flex-1 bg-border" />
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-4">
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center justify-between">
<span className="font-mono font-semibold text-sm">
TOTAL_PROJECTS
</span>
<span className=" font-semibold text-sm">TOTAL_PROJECTS</span>
<Terminal className="h-4 w-4 text-primary" />
</div>
</div>
<div className="p-4">
<div className="font-bold font-mono text-2xl text-primary">
<div className="font-bold text-2xl text-primary">
{totalProjects.toLocaleString()}
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
<p className="mt-1 text-muted-foreground text-xs">
$ ./create-better-t-stack executions
</p>
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center justify-between">
<span className="font-mono font-semibold text-sm">
TOP_FRONTEND
</span>
<span className=" font-semibold text-sm">TOP_FRONTEND</span>
<Cpu className="h-4 w-4 text-primary" />
</div>
</div>
<div className="p-4">
<div className="truncate font-bold font-mono text-accent text-lg">
<div className="truncate font-bold text-accent text-lg">
{mostPopularFrontend}
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
<p className="mt-1 text-muted-foreground text-xs">
$ most_selected_frontend.sh
</p>
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center justify-between">
<span className="font-mono font-semibold text-sm">
TOP_BACKEND
</span>
<span className=" font-semibold text-sm">TOP_BACKEND</span>
<Terminal className="h-4 w-4 text-primary" />
</div>
</div>
<div className="p-4">
<div className="truncate font-bold font-mono text-accent text-lg">
<div className="truncate font-bold text-accent text-lg">
{mostPopularBackend}
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
<p className="mt-1 text-muted-foreground text-xs">
$ most_selected_backend.sh
</p>
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center justify-between">
<span className="font-mono font-semibold text-sm">
TOP_ORM
</span>
<span className=" font-semibold text-sm">TOP_ORM</span>
<Download className="h-4 w-4 text-primary" />
</div>
</div>
<div className="p-4">
<div className="truncate font-bold font-mono text-accent text-lg">
<div className="truncate font-bold text-accent text-lg">
{getORMData().length > 0 ? getORMData()[0].name : "None"}
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
<p className="mt-1 text-muted-foreground text-xs">
$ most_selected_orm.sh
</p>
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center justify-between">
<span className="font-mono font-semibold text-sm">
TOP_API
</span>
<span className=" font-semibold text-sm">TOP_API</span>
<TrendingUp className="h-4 w-4 text-primary" />
</div>
</div>
<div className="p-4">
<div className="truncate font-bold font-mono text-accent text-lg">
<div className="truncate font-bold text-accent text-lg">
{getAPIData().length > 0 ? getAPIData()[0].name : "None"}
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
<p className="mt-1 text-muted-foreground text-xs">
$ most_selected_api.sh
</p>
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center justify-between">
<span className="font-mono font-semibold text-sm">
AUTH_ADOPTION
</span>
<span className=" font-semibold text-sm">AUTH_ADOPTION</span>
<Users className="h-4 w-4 text-primary" />
</div>
</div>
<div className="p-4">
<div className="font-bold font-mono text-2xl text-primary">
<div className="font-bold text-2xl text-primary">
{authEnabledPercent}%
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
<p className="mt-1 text-muted-foreground text-xs">
$ auth_enabled_percentage.sh
</p>
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center justify-between">
<span className="font-mono font-semibold text-sm">
TOP_PKG_MGR
</span>
<span className=" font-semibold text-sm">TOP_PKG_MGR</span>
<Terminal className="h-4 w-4 text-primary" />
</div>
</div>
<div className="p-4">
<div className="truncate font-bold font-mono text-accent text-lg">
<div className="truncate font-bold text-accent text-lg">
{getPackageManagerData().length > 0
? getPackageManagerData()[0].name
: "npm"}
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
<p className="mt-1 text-muted-foreground text-xs">
$ most_used_package_manager.sh
</p>
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center justify-between">
<span className="font-mono font-semibold text-sm">
AVG_DAILY
</span>
<span className=" font-semibold text-sm">AVG_DAILY</span>
<TrendingUp className="h-4 w-4 text-primary" />
</div>
</div>
<div className="p-4">
<div className="font-bold font-mono text-2xl text-primary">
<div className="font-bold text-2xl text-primary">
{avgProjectsPerDay.toFixed(1)}
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
<p className="mt-1 text-muted-foreground text-xs">
$ average_projects_per_day.sh
</p>
</div>
@@ -1209,23 +1193,21 @@ export default function AnalyticsPage() {
<div className="space-y-6">
<div className="mb-4 flex items-center gap-2">
<span className="font-bold font-mono text-lg">
TIMELINE_ANALYSIS.CHARTS
</span>
<span className="font-bold text-lg">TIMELINE_ANALYSIS.CHARTS</span>
<div className="h-px flex-1 bg-border" />
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
PROJECT_TIMELINE.CHART
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Daily project creation timeline from actual data
<p className="mt-1 text-muted-foreground text-xs">
Daily project creation timeline from actual data
</p>
</div>
<div className="p-4">
@@ -1258,16 +1240,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
MONTHLY_TRENDS.CHART
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Monthly project creation trends
<p className="mt-1 text-muted-foreground text-xs">
Monthly project creation trends
</p>
</div>
<div className="p-4">
@@ -1282,7 +1264,7 @@ export default function AnalyticsPage() {
tickLine={false}
tickMargin={10}
axisLine={false}
className="font-mono text-xs"
className=" text-xs"
/>
<YAxis hide />
<ChartTooltip content={<ChartTooltipContent />} />
@@ -1296,16 +1278,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
PLATFORM_DISTRIBUTION.PIE
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Operating system distribution
<p className="mt-1 text-muted-foreground text-xs">
Operating system distribution
</p>
</div>
<div className="p-4">
@@ -1342,16 +1324,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
HOURLY_DISTRIBUTION.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Projects created by hour of day (UTC)
<p className="mt-1 text-muted-foreground text-xs">
Projects created by hour of day (UTC)
</p>
</div>
<div className="p-4">
@@ -1366,7 +1348,7 @@ export default function AnalyticsPage() {
tickLine={false}
tickMargin={10}
axisLine={false}
className="font-mono text-xs"
className=" text-xs"
/>
<YAxis hide />
<ChartTooltip
@@ -1387,26 +1369,26 @@ export default function AnalyticsPage() {
<div className="space-y-6">
<div className="mb-6 flex flex-wrap items-center justify-between gap-2 sm:flex-nowrap">
<div className="flex items-center gap-2">
<span className="font-bold font-mono text-lg sm:text-xl">
<span className="font-bold text-lg sm:text-xl">
STACK_CONFIGURATION.DB
</span>
</div>
<div className="hidden h-px flex-1 bg-border sm:block" />
<span className="w-full text-right font-mono text-muted-foreground text-xs sm:w-auto sm:text-left">
<span className="w-full text-right text-muted-foreground text-xs sm:w-auto sm:text-left">
[CORE_COMPONENTS]
</span>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
POPULAR_STACK_COMBINATIONS.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Most popular frontend + backend combinations
<p className="mt-1 text-muted-foreground text-xs">
Most popular frontend + backend combinations
</p>
</div>
<div className="p-4">
@@ -1421,7 +1403,7 @@ export default function AnalyticsPage() {
tickLine={false}
tickMargin={10}
axisLine={false}
className="font-mono text-xs"
className=" text-xs"
/>
<YAxis hide />
<ChartTooltip content={<ChartTooltipContent />} />
@@ -1435,16 +1417,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
FRONTEND_FRAMEWORKS.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Frontend framework and meta-framework usage
<p className="mt-1 text-muted-foreground text-xs">
Frontend framework and meta-framework usage
</p>
</div>
<div className="p-4">
@@ -1459,7 +1441,7 @@ export default function AnalyticsPage() {
tickLine={false}
tickMargin={10}
axisLine={false}
className="font-mono text-xs"
className=" text-xs"
/>
<YAxis hide />
<ChartTooltip content={<ChartTooltipContent />} />
@@ -1477,16 +1459,16 @@ export default function AnalyticsPage() {
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
BACKEND_FRAMEWORKS.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Backend framework distribution
<p className="mt-1 text-muted-foreground text-xs">
Backend framework distribution
</p>
</div>
<div className="p-4">
@@ -1517,16 +1499,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
DATABASE_DISTRIBUTION.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Database technology distribution
<p className="mt-1 text-muted-foreground text-xs">
Database technology distribution
</p>
</div>
<div className="p-4">
@@ -1557,16 +1539,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
ORM_DISTRIBUTION.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# ORM/Database layer distribution
<p className="mt-1 text-muted-foreground text-xs">
ORM/Database layer distribution
</p>
</div>
<div className="p-4">
@@ -1594,16 +1576,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
DATABASE_HOSTING.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Database hosting service preferences
<p className="mt-1 text-muted-foreground text-xs">
Database hosting service preferences
</p>
</div>
<div className="p-4">
@@ -1634,16 +1616,14 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
API_LAYER.PIE
</span>
<span className=" font-semibold text-sm">API_LAYER.PIE</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# API layer technology distribution
<p className="mt-1 text-muted-foreground text-xs">
API layer technology distribution
</p>
</div>
<div className="p-4">
@@ -1673,16 +1653,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
AUTH_ADOPTION.PIE
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Authentication implementation rate
<p className="mt-1 text-muted-foreground text-xs">
Authentication implementation rate
</p>
</div>
<div className="p-4">
@@ -1718,16 +1698,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
RUNTIME_DISTRIBUTION.PIE
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# JavaScript runtime preference distribution
<p className="mt-1 text-muted-foreground text-xs">
JavaScript runtime preference distribution
</p>
</div>
<div className="p-4">
@@ -1763,16 +1743,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
PROJECT_TYPES.PIE
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Full-stack vs Frontend-only vs Backend-only projects
<p className="mt-1 text-muted-foreground text-xs">
Full-stack vs Frontend-only vs Backend-only projects
</p>
</div>
<div className="p-4">
@@ -1809,16 +1789,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
DATABASE_ORM_COMBINATIONS.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Popular database + ORM combinations
<p className="mt-1 text-muted-foreground text-xs">
Popular database + ORM combinations
</p>
</div>
<div className="p-4">
@@ -1833,7 +1813,7 @@ export default function AnalyticsPage() {
tickLine={false}
tickMargin={10}
axisLine={false}
className="font-mono text-xs"
className=" text-xs"
/>
<YAxis hide />
<ChartTooltip content={<ChartTooltipContent />} />
@@ -1843,16 +1823,14 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
ADDONS_USAGE.BAR
</span>
<span className=" font-semibold text-sm">ADDONS_USAGE.BAR</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Additional features and tooling adoption
<p className="mt-1 text-muted-foreground text-xs">
Additional features and tooling adoption
</p>
</div>
<div className="p-4">
@@ -1867,7 +1845,7 @@ export default function AnalyticsPage() {
tickLine={false}
tickMargin={10}
axisLine={false}
className="font-mono text-xs"
className=" text-xs"
/>
<YAxis hide />
<ChartTooltip content={<ChartTooltipContent />} />
@@ -1884,16 +1862,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
EXAMPLES_USAGE.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Example applications included in projects
<p className="mt-1 text-muted-foreground text-xs">
Example applications included in projects
</p>
</div>
<div className="p-4">
@@ -1908,7 +1886,7 @@ export default function AnalyticsPage() {
tickLine={false}
tickMargin={10}
axisLine={false}
className="font-mono text-xs"
className=" text-xs"
/>
<YAxis hide />
<ChartTooltip content={<ChartTooltipContent />} />
@@ -1928,23 +1906,21 @@ export default function AnalyticsPage() {
<div className="space-y-6">
<div className="mb-4 flex items-center gap-2">
<span className="font-bold font-mono text-lg">
DEV_ENVIRONMENT.CONFIG
</span>
<span className="font-bold text-lg">DEV_ENVIRONMENT.CONFIG</span>
<div className="h-px flex-1 bg-border" />
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
GIT_INITIALIZATION.PIE
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Git repository initialization rate
<p className="mt-1 text-muted-foreground text-xs">
Git repository initialization rate
</p>
</div>
<div className="p-4">
@@ -1977,16 +1953,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
PACKAGE_MANAGER.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Package manager usage distribution
<p className="mt-1 text-muted-foreground text-xs">
Package manager usage distribution
</p>
</div>
<div className="p-4">
@@ -2017,16 +1993,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
INSTALL_PREFERENCE.PIE
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Automatic dependency installation preference
<p className="mt-1 text-muted-foreground text-xs">
Automatic dependency installation preference
</p>
</div>
<div className="p-4">
@@ -2062,16 +2038,16 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
<span className=" font-semibold text-sm">
NODE_VERSIONS.BAR
</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# Node.js version distribution (major versions)
<p className="mt-1 text-muted-foreground text-xs">
Node.js version distribution (major versions)
</p>
</div>
<div className="p-4">
@@ -2086,7 +2062,7 @@ export default function AnalyticsPage() {
tickLine={false}
tickMargin={10}
axisLine={false}
className="font-mono text-xs"
className=" text-xs"
/>
<YAxis hide />
<ChartTooltip content={<ChartTooltipContent />} />
@@ -2097,16 +2073,14 @@ export default function AnalyticsPage() {
</div>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="rounded border border-border">
<div className="border-border border-b px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-primary text-xs"></span>
<span className="font-mono font-semibold text-sm">
CLI_VERSIONS.BAR
</span>
<span className=" font-semibold text-sm">CLI_VERSIONS.BAR</span>
</div>
<p className="mt-1 font-mono text-muted-foreground text-xs">
# CLI version distribution across project creations
<p className="mt-1 text-muted-foreground text-xs">
CLI version distribution across project creations
</p>
</div>
<div className="p-4">
@@ -2121,7 +2095,7 @@ export default function AnalyticsPage() {
tickLine={false}
tickMargin={10}
axisLine={false}
className="font-mono text-xs"
className=" text-xs"
/>
<YAxis hide />
<ChartTooltip content={<ChartTooltipContent />} />

View File

@@ -1,9 +1,32 @@
import { type ReactNode, Suspense } from "react";
"use client";
import { HomeLayout } from "fumadocs-ui/layouts/home";
import { usePathname } from "next/navigation";
import { type ReactNode, useEffect } from "react";
import { baseOptions } from "@/app/layout.config";
export default function Layout({ children }: { children: ReactNode }) {
const pathname = usePathname();
useEffect(() => {
const header = document.querySelector("#nd-nav");
if (!header) return;
const main = document.querySelector("main");
if (!main) return;
if (pathname === "/new") {
header.classList.remove("*:mx-auto", "*:max-w-fd-container");
main.classList.remove("max-w-[1400px]", "mx-auto", "min-h-svh");
} else {
header.classList.add("*:mx-auto", "*:max-w-fd-container");
main.classList.add("max-w-[1400px]", "mx-auto", "min-h-svh");
}
}, [pathname]);
return (
<main className="relative z-10 grid min-h-svh grid-cols-1 grid-rows-[auto_1fr_auto] overflow-hidden">
<Suspense>{children}</Suspense>
</main>
<HomeLayout {...baseOptions}>
<main className="h-full w-full">{children}</main>
</HomeLayout>
);
}

View File

@@ -1,19 +1,20 @@
"use client";
import { motion } from "motion/react";
import { Suspense } from "react";
import StackBuilder from "../_components/stack-builder";
export default function FullScreenStackBuilder() {
return (
<div className="flex h-svh flex-col bg-background">
<Suspense>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.3 }}
className="w-full flex-1"
className="grid h-[calc(100vh-64px)] w-full flex-1 grid-cols-1 overflow-hidden"
>
<StackBuilder />
</motion.div>
</div>
</Suspense>
);
}

View File

@@ -10,12 +10,10 @@ import {
import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
import { TECH_OPTIONS } from "@/lib/constant";
import { cn } from "@/lib/utils";
import discordLogo from "@/public/icon/discord.svg";
import Footer from "./_components/footer";
import PackageIcon from "./_components/icons";
import Navbar from "./_components/navbar";
import NpmPackage from "./_components/npm-package";
import SponsorsSection from "./_components/sponsors-section";
import Testimonials from "./_components/testimonials";
@@ -59,81 +57,9 @@ export default function HomePage() {
setTimeout(() => setCopiedCommand(null), 2000);
};
const frontendOptions = [
...TECH_OPTIONS.webFrontend.filter((option) => option.id !== "none"),
...TECH_OPTIONS.nativeFrontend.filter((option) => option.id !== "none"),
];
const backendOptions = TECH_OPTIONS.backend.filter(
(option) => option.id !== "none",
);
const databaseOptions = TECH_OPTIONS.database.filter(
(option) => option.id !== "none",
);
const runtimeOptions = TECH_OPTIONS.runtime;
const packageManagerOptions = TECH_OPTIONS.packageManager;
const apiOptions = TECH_OPTIONS.api.filter((option) => option.id !== "none");
const ormOptions = TECH_OPTIONS.orm.filter((option) => option.id !== "none");
const dbSetupOptions = TECH_OPTIONS.dbSetup.filter(
(option) => option.id !== "none",
);
const authOptions = TECH_OPTIONS.auth.filter(
(option) => option.id !== "false",
);
const addonsOptions = TECH_OPTIONS.addons;
const examplesOptions = TECH_OPTIONS.examples;
const techStackCategories = [
{
category: "Frontend",
options: frontendOptions,
},
{
category: "Backend",
options: backendOptions,
},
{
category: "Database",
options: databaseOptions,
},
{
category: "Runtime",
options: runtimeOptions,
},
{
category: "API",
options: apiOptions,
},
{
category: "ORM",
options: ormOptions,
},
{
category: "Database Setup",
options: dbSetupOptions,
},
{
category: "Authentication",
options: authOptions,
},
{
category: "Package Managers",
options: packageManagerOptions,
},
{
category: "Addons",
options: addonsOptions,
},
{
category: "Examples",
options: examplesOptions,
},
];
return (
<div className="terminal-scanlines min-h-screen bg-background font-mono">
<Navbar />
<main className="terminal-matrix-bg mx-auto max-w-7xl p-6 pt-28">
<div className="min-h-svh">
<main className="mx-auto px-4 pt-16">
<div className="mb-8 flex items-center justify-center">
<div className="flex flex-wrap items-center justify-center gap-2 sm:gap-4 md:gap-6">
<pre className="ascii-art text-primary text-xs leading-tight sm:text-sm">
@@ -179,30 +105,29 @@ export default function HomePage() {
</div>
<div className="mb-6 text-center">
<p className="mx-auto font-mono text-lg text-muted-foreground">
# Modern CLI for scaffolding end-to-end type-safe TypeScript
projects
<p className="mx-auto text-lg text-muted-foreground">
Modern CLI for scaffolding end-to-end type-safe TypeScript projects
</p>
<p className="mx-auto mt-2 max-w-2xl font-mono text-muted-foreground text-sm">
# Production-ready Customizable Best practices included
<p className="mx-auto mt-2 max-w-2xl text-muted-foreground text-sm">
Production-ready Customizable Best practices included
</p>
<NpmPackage />
</div>
<div className="terminal-block-hover mb-8 rounded border border-border bg-muted/20 p-4">
<div className=" mb-8 rounded border border-border p-4">
<div className="mb-4 flex items-center justify-between">
<div className="flex items-center gap-2">
<Terminal className="h-4 w-4 text-primary" />
<span className="font-semibold text-sm">QUICK_START</span>
</div>
<div className="flex items-center rounded border border-border bg-background p-0.5">
<div className="flex items-center rounded border border-border p-0.5">
{(["bun", "pnpm", "npm"] as const).map((pm) => (
<button
type="button"
key={pm}
onClick={() => setSelectedPM(pm)}
className={cn(
"flex items-center gap-1.5 rounded px-2 py-1 font-mono text-xs transition-colors duration-150",
"flex items-center gap-1.5 rounded px-2 py-1 text-xs transition-colors duration-150",
selectedPM === pm
? "bg-primary/20 text-primary"
: "text-muted-foreground hover:text-foreground",
@@ -216,17 +141,15 @@ export default function HomePage() {
</div>
<div className="space-y-3">
<div className="flex items-center justify-between rounded border border-border bg-background p-3">
<div className="flex items-center justify-between rounded border border-border p-3">
<div className="flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-foreground">
{commands[selectedPM]}
</span>
<span className=" text-foreground">{commands[selectedPM]}</span>
</div>
<button
type="button"
onClick={() => copyCommand(commands[selectedPM], selectedPM)}
className="terminal-block-hover flex items-center gap-1 rounded border border-border bg-muted/20 px-2 py-1 text-xs hover:bg-muted/50"
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-xs hover:bg-muted/50"
>
{copiedCommand === selectedPM ? (
<Check className="h-3 w-3 text-primary" />
@@ -241,14 +164,12 @@ export default function HomePage() {
<div className="mb-12 grid grid-cols-1 gap-4 md:grid-cols-3">
<Link href="/new">
<div className="group terminal-block-hover cursor-pointer rounded border border-border bg-background p-4">
<div className="group cursor-pointer rounded border border-border p-4">
<div className="flex items-center gap-2">
<ChevronRight className="h-4 w-4 text-primary" />
<span className="font-mono font-semibold">
STACK_BUILDER.EXE
</span>
<span className=" font-semibold">STACK_BUILDER.EXE</span>
</div>
<p className="mt-2 font-mono text-muted-foreground text-sm">
<p className="mt-2 text-muted-foreground text-sm">
[EXEC] Interactive configuration wizard
</p>
</div>
@@ -259,22 +180,20 @@ export default function HomePage() {
target="_blank"
rel="noopener noreferrer"
>
<div className="group terminal-block-hover cursor-pointer rounded border border-border bg-background p-4">
<div className="group cursor-pointer rounded border border-border p-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Github className="h-4 w-4 text-primary" />
<span className="font-mono font-semibold">
GITHUB_REPO.GIT
</span>
<span className=" font-semibold">GITHUB_REPO.GIT</span>
</div>
{stars !== null && !isLoadingStars && (
<div className="flex items-center gap-1 rounded border border-border bg-muted/30 px-2 py-1 font-mono text-xs">
<div className="flex items-center gap-1 rounded border border-border bg-muted/30 px-2 py-1 text-xs">
<Star className="h-3 w-3 text-accent" />
{stars}
</div>
)}
</div>
<p className="mt-2 font-mono text-muted-foreground text-sm">
<p className="mt-2 text-muted-foreground text-sm">
[LINK] Star the repository on GitHub
</p>
</div>
@@ -285,131 +204,22 @@ export default function HomePage() {
target="_blank"
rel="noopener noreferrer"
>
<div className="group terminal-block-hover cursor-pointer rounded border border-border bg-background p-4">
<div className="group cursor-pointer rounded border border-border p-4">
<div className="flex items-center gap-2">
<Image src={discordLogo} alt="discord" className="h-4 w-4" />
<span className="font-mono font-semibold">
DISCORD_CHAT.IRC
</span>
<Image
src={discordLogo}
alt="discord"
className="h-4 w-4 invert-0 dark:invert"
/>
<span className=" font-semibold">DISCORD_CHAT.IRC</span>
</div>
<p className="mt-2 font-mono text-muted-foreground text-sm">
<p className="mt-2 text-muted-foreground text-sm">
[JOIN] Connect to developer community
</p>
</div>
</Link>
</div>
<div className="mb-12">
<div className="mb-6 flex flex-wrap items-center justify-between gap-2 sm:flex-nowrap">
<div className="flex items-center gap-2">
<Terminal className="h-5 w-5 text-primary" />
<span className="font-bold font-mono text-lg sm:text-xl">
TECH_STACK_MATRIX.DB
</span>
</div>
<div className="hidden h-px flex-1 bg-border sm:block" />
<span className="w-full text-right font-mono text-muted-foreground text-xs sm:w-auto sm:text-left">
[
{techStackCategories.reduce(
(acc, cat) => acc + cat.options.length,
0,
)}{" "}
PACKAGES]
</span>
</div>
<div className="terminal-block-hover rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-4 py-3">
<div className="flex items-center gap-2">
<Terminal className="h-4 w-4 text-primary" />
<span className="font-mono font-semibold text-sm">
/tech-stack/packages/
</span>
</div>
</div>
<div className="space-y-3 p-4">
{techStackCategories.map((category, categoryIndex) => (
<div key={category.category} className="space-y-2">
<div className="directory-header flex items-center gap-2 rounded px-2 py-2 transition-colors">
<span className="font-mono font-semibold text-foreground text-sm">
{category.category.toLowerCase().replace(/\s+/g, "-")}/
</span>
<span className="font-mono text-muted-foreground text-xs">
({category.options.length} items)
</span>
</div>
<div className="ml-6 grid grid-cols-1 gap-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{category.options.map((option, optionIndex) => (
<div
key={option.id}
className="file-browser-item file-load-animation flex items-center gap-3 rounded border border-border bg-muted/10 px-3 py-2"
style={{
animationDelay: `${
categoryIndex * 100 + optionIndex * 30
}ms`,
}}
>
{option.icon !== "" && (
<Image
src={option.icon}
alt={option.name}
height={16}
width={16}
unoptimized
className="file-icon h-4 w-4 flex-shrink-0"
/>
)}
<span className="flex-1 truncate font-mono text-xs">
{option.name.toLowerCase().replace(/\s+/g, "-")}
</span>
<span className="font-mono text-muted-foreground text-xs opacity-0 transition-opacity group-hover:opacity-100">
-rw-r--r--
</span>
</div>
))}
</div>
</div>
))}
</div>
<div className="border-border border-t bg-muted/20 px-4 py-2">
<div className="flex items-center justify-between text-xs">
<span className="font-mono text-muted-foreground">
$ ls -la /tech-stack/packages/
</span>
<span className="font-mono text-muted-foreground">
{techStackCategories.length} directories,{" "}
{techStackCategories.reduce(
(acc, cat) => acc + cat.options.length,
0,
)}{" "}
files
</span>
</div>
</div>
</div>
</div>
<div className="terminal-block-hover mb-8 rounded border border-border bg-muted/20 p-4">
<div className="mb-2 font-mono font-semibold text-sm">
SYSTEM_INFO.LOG
</div>
<div className="grid grid-cols-1 gap-2 font-mono text-xs md:grid-cols-3">
<div>
<span className="text-primary">OS:</span> TypeScript_Runtime_v5.x
</div>
<div>
<span className="text-primary">ARCH:</span> Full_Stack_Framework
</div>
<div>
<span className="text-primary">STATUS:</span>{" "}
<span className="text-accent">READY</span>
</div>
</div>
</div>
<SponsorsSection />
<Testimonials />
</main>

View File

@@ -26,11 +26,11 @@ export default function ShowcaseItem({
const projectId = `PROJECT_${String(index + 1).padStart(3, "0")}`;
return (
<div className="terminal-block-hover flex h-full flex-col overflow-hidden rounded border border-border bg-background">
<div className="border-border border-b bg-muted/20 px-3 py-2">
<div className="flex h-full flex-col overflow-hidden rounded border border-border">
<div className="border-border border-b px-3 py-2">
<div className="flex items-center gap-2">
<File className="h-3 w-3 text-primary" />
<span className="font-mono font-semibold text-foreground text-xs">
<span className=" font-semibold text-foreground text-xs">
{projectId}.PROJECT
</span>
<div className="ml-auto flex items-center gap-2 text-muted-foreground text-xs">
@@ -52,17 +52,15 @@ export default function ShowcaseItem({
</div>
<div className="flex flex-1 flex-col p-4">
<h3 className="mb-2 font-bold font-mono text-lg text-primary">
{title}
</h3>
<h3 className="mb-2 font-bold text-lg text-primary">{title}</h3>
<p className="mb-4 flex-grow font-mono text-muted-foreground text-sm leading-relaxed">
<p className="mb-4 flex-grow text-muted-foreground text-sm leading-relaxed">
{description}
</p>
<div className="mb-4">
<div className="mb-2 flex items-center gap-2">
<span className="font-mono text-muted-foreground text-xs">
<span className=" text-muted-foreground text-xs">
DEPENDENCIES:
</span>
</div>
@@ -70,7 +68,7 @@ export default function ShowcaseItem({
{tags.map((tag) => (
<span
key={tag}
className="rounded border border-border bg-muted/30 px-2 py-1 font-mono text-foreground text-xs transition-colors hover:bg-muted/50"
className="rounded border border-border bg-muted/30 px-2 py-1 text-foreground text-xs transition-colors hover:bg-muted/50"
>
{tag}
</span>
@@ -85,7 +83,7 @@ export default function ShowcaseItem({
href={liveUrl}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 rounded border border-border bg-primary/10 px-3 py-2 font-mono text-primary text-sm transition-all hover:bg-primary/20 hover:text-primary"
className="flex items-center gap-2 rounded border border-border bg-primary/10 px-3 py-2 text-primary text-sm transition-all hover:bg-primary/20 hover:text-primary"
>
<Monitor className="h-3 w-3" />
<span>LAUNCH_DEMO.EXE</span>
@@ -97,7 +95,7 @@ export default function ShowcaseItem({
href={sourceUrl}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 rounded border border-border bg-muted/20 px-3 py-2 font-mono text-muted-foreground text-sm transition-all hover:bg-muted/40 hover:text-foreground"
className="flex items-center gap-2 rounded border border-border px-3 py-2 text-muted-foreground text-sm transition-all hover:bg-muted/40 hover:text-foreground"
>
<Github className="h-3 w-3" />
<span>VIEW_SOURCE.GIT</span>
@@ -109,12 +107,12 @@ export default function ShowcaseItem({
<div className="border-border border-t pt-2">
<div className="flex items-center gap-2 text-xs">
<span className="text-primary">$</span>
<span className="font-mono text-muted-foreground">
<span className=" text-muted-foreground">
echo &quot;Status: READY&quot;
</span>
<div className="ml-auto flex items-center gap-1">
<div className="h-1 w-1 animate-pulse rounded-full bg-green-400" />
<span className="font-mono text-green-400 text-xs">ONLINE</span>
<span className=" text-green-400 text-xs">ONLINE</span>
</div>
</div>
</div>

View File

@@ -1,7 +1,6 @@
"use client";
import { FolderOpen, Terminal } from "lucide-react";
import Navbar from "../_components/navbar";
import { Terminal } from "lucide-react";
import ShowcaseItem from "./_components/ShowcaseItem";
const showcaseProjects = [
@@ -71,79 +70,61 @@ const showcaseProjects = [
export default function ShowcasePage() {
return (
<>
<Navbar />
<main className="flex min-h-svh flex-col items-center bg-background px-4 pt-24 pb-10 sm:px-6 md:px-8 md:pt-28 lg:pt-32">
<div className="mx-auto w-full max-w-6xl">
<div className="mb-8">
<div className="mb-6 flex items-center gap-2">
<main className="min-h-svh">
<div className="container mx-auto space-y-8 px-4 py-8 pt-16">
<div className="mb-8">
<div className="mb-6 flex flex-wrap items-center justify-between gap-2 sm:flex-nowrap">
<div className="flex items-center gap-2">
<Terminal className="h-4 w-4 text-primary" />
<span className="font-bold font-mono text-lg">
<span className="font-bold text-lg sm:text-xl">
PROJECT_SHOWCASE.EXE
</span>
<div className="h-px flex-1 bg-border" />
<span className="font-mono text-muted-foreground text-xs">
[{showcaseProjects.length} PROJECTS FOUND]
</div>
<div className="h-px flex-1 bg-border" />
<span className=" text-muted-foreground text-xs">
[{showcaseProjects.length} PROJECTS FOUND]
</span>
</div>
<div className="mb-8 rounded border border-border p-4">
<div className="flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className=" text-foreground">
user@dev-machine:~/showcase$ ls -la
</span>
</div>
<div className="terminal-block-hover mb-8 rounded border border-border bg-muted/20 p-4">
<div className="flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-foreground">
user@dev-machine:~/showcase$ ls -la
</span>
</div>
<div className="mt-2 flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-muted-foreground">
# Discover amazing projects built with Better-T-Stack
</span>
</div>
<div className="mt-2 flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-muted-foreground">
# Real-world implementations showcasing stack capabilities
</span>
</div>
<div className="mt-2 flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className=" text-muted-foreground">
Discover amazing projects built with Better-T-Stack
</span>
</div>
<div className="terminal-block-hover rounded border border-border bg-background p-3">
<div className="flex items-center gap-2 font-mono text-sm">
<FolderOpen className="h-4 w-4 text-blue-400" />
<span className="text-foreground">/showcase/projects/</span>
<div className="ml-auto text-muted-foreground text-xs">
drwxr-xr-x {showcaseProjects.length} items
</div>
</div>
</div>
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-3">
{showcaseProjects.map((project, index) => (
<ShowcaseItem key={project.title} {...project} index={index} />
))}
</div>
<div className="mt-8">
<div className="terminal-block-hover rounded border border-border bg-muted/20 p-4">
<div className="flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-muted-foreground">
# Want to showcase your project? Submit via GitHub issues
</span>
</div>
<div className="mt-2 flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className="font-mono text-foreground">
echo &quot;Built something amazing? We&apos;d love to feature
it!&quot;
</span>
</div>
<div className="mt-2 flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className=" text-muted-foreground">
Real-world implementations showcasing stack capabilities
</span>
</div>
</div>
</div>
</main>
</>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-3">
{showcaseProjects.map((project, index) => (
<ShowcaseItem key={project.title} {...project} index={index} />
))}
</div>
<div className="mt-8">
<div className="rounded border border-border p-4">
<div className="flex items-center gap-2 text-sm">
<span className="text-primary">$</span>
<span className=" text-muted-foreground">
Want to showcase your project? Submit via GitHub issues
</span>
</div>
</div>
</div>
</div>
</main>
);
}

View File

@@ -1,4 +1,4 @@
import Features from "components/features";
import * as TabsComponents from "fumadocs-ui/components/tabs";
import defaultMdxComponents from "fumadocs-ui/mdx";
import {
DocsBody,
@@ -7,6 +7,7 @@ import {
DocsTitle,
} from "fumadocs-ui/page";
import { notFound } from "next/navigation";
import { LLMCopyButton, ViewOptions } from "@/components/ai/page-actions";
import { source } from "@/lib/source";
export default async function Page(props: {
@@ -22,8 +23,15 @@ export default async function Page(props: {
<DocsPage toc={page.data.toc} full={page.data.full}>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription>{page.data.description}</DocsDescription>
<div className="flex flex-row items-center gap-2 border-b pt-2 pb-6">
<LLMCopyButton markdownUrl={`${page.url}.mdx`} />
<ViewOptions
markdownUrl={`${page.url}.mdx`}
githubUrl={`https://github.com/amanvarshney01/create-better-t-stack/blob/dev/apps/docs/content/docs/${page.path}`}
/>
</div>
<DocsBody>
<MDX components={{ ...defaultMdxComponents, Features }} />
<MDX components={{ ...defaultMdxComponents, ...TabsComponents }} />
</DocsBody>
</DocsPage>
);

View File

@@ -1,17 +1,18 @@
@import "tailwindcss";
@import "fumadocs-ui/css/shadcn.css";
@import "fumadocs-ui/css/neutral.css";
@import "fumadocs-ui/css/preset.css";
@import "tw-animate-css";
@custom-variant dark (&:where(.dark, .dark *));
/* .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");
} */
:root {
/* --fd-layout-width: 1400px; */
/* --max-w-fh-container: 100%; */
}
.react-tweet-theme {
--tweet-container-margin: 0 !important;
@apply !bg-background !border-none !h-full !border-transparent !w-full;
@apply !bg-fd-background !border-none !h-full !border-transparent !w-full;
max-width: 100% !important;
min-width: 0 !important;
}
@@ -215,15 +216,20 @@
--spacing: 0.25rem;
--shadow-2xs: 0px 4px 6px 0px hsl(240 30% 25% / 0.06);
--shadow-xs: 0px 4px 6px 0px hsl(240 30% 25% / 0.06);
--shadow-sm: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 1px 2px -1px
--shadow-sm:
0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 1px 2px -1px
hsl(240 30% 25% / 0.12);
--shadow: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 1px 2px -1px
--shadow:
0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 1px 2px -1px
hsl(240 30% 25% / 0.12);
--shadow-md: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 2px 4px -1px
--shadow-md:
0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 2px 4px -1px
hsl(240 30% 25% / 0.12);
--shadow-lg: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 4px 6px -1px
--shadow-lg:
0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 4px 6px -1px
hsl(240 30% 25% / 0.12);
--shadow-xl: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 8px 10px -1px
--shadow-xl:
0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 8px 10px -1px
hsl(240 30% 25% / 0.12);
--shadow-2xl: 0px 4px 6px 0px hsl(240 30% 25% / 0.3);
--tracking-normal: 0em;
@@ -278,28 +284,33 @@
--spacing: 0.25rem;
--shadow-2xs: 0px 2px 4px 0px hsl(240 30% 5% / 0.15);
--shadow-xs: 0px 2px 4px 0px hsl(240 30% 5% / 0.15);
--shadow-sm: 0px 4px 8px 0px hsl(240 30% 5% / 0.2), 0px 1px 2px -1px
--shadow-sm:
0px 4px 8px 0px hsl(240 30% 5% / 0.2), 0px 1px 2px -1px
hsl(240 30% 5% / 0.15);
--shadow: 0px 4px 8px 0px hsl(240 30% 5% / 0.2), 0px 1px 2px -1px
--shadow:
0px 4px 8px 0px hsl(240 30% 5% / 0.2), 0px 1px 2px -1px
hsl(240 30% 5% / 0.15);
--shadow-md: 0px 6px 12px 0px hsl(240 30% 5% / 0.25), 0px 2px 4px -1px
--shadow-md:
0px 6px 12px 0px hsl(240 30% 5% / 0.25), 0px 2px 4px -1px
hsl(240 30% 5% / 0.2);
--shadow-lg: 0px 8px 16px 0px hsl(240 30% 5% / 0.3), 0px 4px 6px -1px
--shadow-lg:
0px 8px 16px 0px hsl(240 30% 5% / 0.3), 0px 4px 6px -1px
hsl(240 30% 5% / 0.25);
--shadow-xl: 0px 12px 24px 0px hsl(240 30% 5% / 0.35), 0px 8px 10px -1px
--shadow-xl:
0px 12px 24px 0px hsl(240 30% 5% / 0.35), 0px 8px 10px -1px
hsl(240 30% 5% / 0.3);
--shadow-2xl: 0px 16px 32px 0px hsl(240 30% 5% / 0.4);
}
@layer base {
/* @layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
@apply text-foreground;
letter-spacing: var(--tracking-normal);
}
}
} */
.terminal-cursor {
animation: blink 1s infinite;
@@ -339,10 +350,6 @@
pointer-events: none;
}
.terminal-block-hover {
transition: all 0.2s ease;
}
.terminal-block-hover:hover {
border-color: var(--primary);
box-shadow: 0 0 10px rgba(136, 57, 239, 0.3);

View File

@@ -1,16 +1,61 @@
import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared";
import Image from "next/image";
import discordLogo from "@/public/icon/discord.svg";
import mainLogo from "@/public/logo.svg";
export const logo = (
<>
<Image
alt="better-t-stack"
src={mainLogo}
className="w-8"
aria-label="better-t-stack"
/>
</>
);
/**
* Shared layout configurations
*
* you can configure layouts individually from:
* Home Layout: app/(home)/layout.tsx
* Docs Layout: app/docs/layout.tsx
*/
export const baseOptions: BaseLayoutProps = {
nav: {
title: "Better-T-Stack",
enabled: false,
title: (
<>
{logo}
<span className="font-medium [.uwu_&]:hidden [header_&]:text-[15px]">
Better T Stack
</span>
</>
),
// enabled: false,
},
links: [
{
text: "Docs",
url: "/docs",
},
{
text: "Builder",
url: "/new",
},
{
text: "Analytics",
url: "/analytics",
},
{
text: "Showcase",
url: "/showcase",
},
{
text: (
<Image
src={discordLogo}
alt="discord"
className="size-5 invert-0 dark:invert"
/>
),
url: "https://discord.gg/ZYsbjpDaM5",
external: true,
secondary: true,
},
],
githubUrl: "https://github.com/AmanVarshney01/create-better-t-stack",
};

View File

@@ -0,0 +1,183 @@
"use client";
import { cva } from "class-variance-authority";
import { buttonVariants } from "fumadocs-ui/components/ui/button";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "fumadocs-ui/components/ui/popover";
import { useCopyButton } from "fumadocs-ui/utils/use-copy-button";
import {
Check,
ChevronDown,
Copy,
ExternalLinkIcon,
MessageCircleIcon,
} from "lucide-react";
import { useMemo, useState } from "react";
import { cn } from "../../../lib/cn";
const cache = new Map<string, string>();
export function LLMCopyButton({
/**
* A URL to fetch the raw Markdown/MDX content of page
*/
markdownUrl,
}: {
markdownUrl: string;
}) {
const [isLoading, setLoading] = useState(false);
const [checked, onClick] = useCopyButton(async () => {
const cached = cache.get(markdownUrl);
if (cached) return navigator.clipboard.writeText(cached);
setLoading(true);
try {
await navigator.clipboard.write([
new ClipboardItem({
"text/plain": fetch(markdownUrl).then(async (res) => {
const content = await res.text();
cache.set(markdownUrl, content);
return content;
}),
}),
]);
} finally {
setLoading(false);
}
});
return (
<button
disabled={isLoading}
className={cn(
buttonVariants({
color: "secondary",
size: "sm",
className: "gap-2 [&_svg]:size-3.5 [&_svg]:text-fd-muted-foreground",
}),
)}
onClick={onClick}
>
{checked ? <Check /> : <Copy />}
Copy Markdown
</button>
);
}
const optionVariants = cva(
"inline-flex items-center gap-2 rounded-lg p-2 text-sm hover:bg-fd-accent hover:text-fd-accent-foreground [&_svg]:size-4",
);
export function ViewOptions({
markdownUrl,
githubUrl,
}: {
/**
* A URL to the raw Markdown/MDX content of page
*/
markdownUrl: string;
/**
* Source file URL on GitHub
*/
githubUrl: string;
}) {
const items = useMemo(() => {
const fullMarkdownUrl =
typeof window !== "undefined"
? new URL(markdownUrl, window.location.origin)
: "loading";
const q = `Read ${fullMarkdownUrl}, I want to ask questions about it.`;
return [
{
title: "Open in GitHub",
href: githubUrl,
icon: (
<svg fill="currentColor" role="img" viewBox="0 0 24 24">
<title>GitHub</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
),
},
{
title: "Open in ChatGPT",
href: `https://chatgpt.com/?${new URLSearchParams({
hints: "search",
q,
})}`,
icon: (
<svg
role="img"
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<title>OpenAI</title>
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" />
</svg>
),
},
{
title: "Open in Claude",
href: `https://claude.ai/new?${new URLSearchParams({
q,
})}`,
icon: (
<svg
fill="currentColor"
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<title>Anthropic</title>
<path d="M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z" />
</svg>
),
},
{
title: "Open in T3 Chat",
href: `https://t3.chat/new?${new URLSearchParams({
q,
})}`,
icon: <MessageCircleIcon />,
},
];
}, [githubUrl, markdownUrl]);
return (
<Popover>
<PopoverTrigger
className={cn(
buttonVariants({
color: "secondary",
size: "sm",
className: "gap-2",
}),
)}
>
Open
<ChevronDown className="size-3.5 text-fd-muted-foreground" />
</PopoverTrigger>
<PopoverContent className="flex flex-col overflow-auto">
{items.map((item) => (
<a
key={item.href}
href={item.href}
rel="noreferrer noopener"
target="_blank"
className={cn(optionVariants())}
>
{item.icon}
{item.title}
<ExternalLinkIcon className="ms-auto size-3.5 text-fd-muted-foreground" />
</a>
))}
</PopoverContent>
</Popover>
);
}

View File

@@ -31,7 +31,7 @@ export function ThemeToggle({ className }: { className?: string }) {
disabled
aria-label="Toggle theme (loading)"
>
<span className="block h-3 w-3 rounded-full bg-background shadow-lg ring-0" />
<span className="block h-3 w-3 rounded-full shadow-lg ring-0" />
</button>
);
}
@@ -48,7 +48,7 @@ export function ThemeToggle({ className }: { className?: string }) {
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none flex h-3 w-3 items-center justify-center rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
"pointer-events-none flex h-3 w-3 items-center justify-center rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
)}
>
{isChecked ? (

View File

@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
"$schema": "https://biomejs.dev/schemas/2.1.2/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",

View File

@@ -4,17 +4,17 @@
"": {
"name": "better-t-stack",
"devDependencies": {
"@biomejs/biome": "2.0.0",
"@biomejs/biome": "2.1.2",
"@changesets/cli": "^2.29.5",
"husky": "^9.1.7",
"lint-staged": "^16.1.2",
"turbo": "^2.5.4",
"turbo": "^2.5.5",
"typescript": "5.8.3",
},
},
"apps/cli": {
"name": "create-better-t-stack",
"version": "2.25.9",
"version": "2.26.3",
"bin": {
"create-better-t-stack": "dist/index.js",
},
@@ -221,23 +221,23 @@
"@babel/types": ["@babel/types@7.28.1", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ=="],
"@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" }, "bin": { "biome": "bin/biome" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="],
"@biomejs/biome": ["@biomejs/biome@2.1.2", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.1.2", "@biomejs/cli-darwin-x64": "2.1.2", "@biomejs/cli-linux-arm64": "2.1.2", "@biomejs/cli-linux-arm64-musl": "2.1.2", "@biomejs/cli-linux-x64": "2.1.2", "@biomejs/cli-linux-x64-musl": "2.1.2", "@biomejs/cli-win32-arm64": "2.1.2", "@biomejs/cli-win32-x64": "2.1.2" }, "bin": { "biome": "bin/biome" } }, "sha512-yq8ZZuKuBVDgAS76LWCfFKHSYIAgqkxVB3mGVVpOe2vSkUTs7xG46zXZeNPRNVjiJuw0SZ3+J2rXiYx0RUpfGg=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.0.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QvqWYtFFhhxdf8jMAdJzXW+Frc7X8XsnHQLY+TBM1fnT1TfeV/v9vsFI5L2J7GH6qN1+QEEJ19jHibCY2Ypplw=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.1.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-leFAks64PEIjc7MY/cLjE8u5OcfBKkcDB0szxsWUB4aDfemBep1WVKt0qrEyqZBOW8LPHzrFMyDl3FhuuA0E7g=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.0.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-5JFhls1EfmuIH4QGFPlNpxJQFC6ic3X1ltcoLN+eSRRIPr6H/lUS1ttuD0Fj7rPgPhZqopK/jfH8UVj/1hIsQw=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.1.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-Nmmv7wRX5Nj7lGmz0FjnWdflJg4zii8Ivruas6PBKzw5SJX/q+Zh2RfnO+bBnuKLXpj8kiI2x2X12otpH6a32A=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-BAH4QVi06TzAbVchXdJPsL0Z/P87jOfes15rI+p3EX9/EGTfIjaQ9lBVlHunxcmoptaA5y1Hdb9UYojIhmnjIw=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.1.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-NWNy2Diocav61HZiv2enTQykbPP/KrA/baS7JsLSojC7Xxh2nl9IczuvE5UID7+ksRy2e7yH7klm/WkA72G1dw=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Bxsz8ki8+b3PytMnS5SgrGV+mbAWwIxI3ydChb/d1rURlJTMdxTTq5LTebUnlsUWAX6OvJuFeiVq9Gjn1YbCyA=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.1.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-qgHvafhjH7Oca114FdOScmIKf1DlXT1LqbOrrbR30kQDLFPEOpBG0uzx6MhmsrmhGiCFCr2obDamu+czk+X0HQ=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-09PcOGYTtkopWRm6mZ/B6Mr6UHdkniUgIG/jLBv+2J8Z61ezRE+xQmpi3yNgUrFIAU4lPA9atg7mhvE/5Bo7Wg=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.1.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Km/UYeVowygTjpX6sGBzlizjakLoMQkxWbruVZSNE6osuSI63i4uCeIL+6q2AJlD3dxoiBJX70dn1enjQnQqwA=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-tiQ0ABxMJb9I6GlfNp0ulrTiQSFacJRJO8245FFwE3ty3bfsfxlU/miblzDIi+qNrgGsLq5wIZcVYGp4c+HXZA=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.1.2", "", { "os": "linux", "cpu": "x64" }, "sha512-xlB3mU14ZUa3wzLtXfmk2IMOGL+S0aHFhSix/nssWS/2XlD27q+S6f0dlQ8WOCbYoXcuz8BCM7rCn2lxdTrlQA=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.0.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-vrTtuGu91xNTEQ5ZcMJBZuDlqr32DWU1r14UfePIGndF//s2WUAmer4FmgoPgruo76rprk37e8S2A2c0psXdxw=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.1.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-G8KWZli5ASOXA3yUQgx+M4pZRv3ND16h77UsdunUL17uYpcL/UC7RkWTdkfvMQvogVsAuz5JUcBDjgZHXxlKoA=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.0.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2USVQ0hklNsph/KIR72ZdeptyXNnQ3JdzPn3NbjI4Sna34CnxeiYAaZcZzXPDl5PYNFBivV4xmvT3Z3rTmyDBg=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.1.2", "", { "os": "win32", "cpu": "x64" }, "sha512-9zajnk59PMpjBkty3bK2IrjUsUHvqe9HWwyAWQBjGLE7MIBjbX2vwv1XPEhmO2RRuGoTkVx3WCanHrjAytICLA=="],
"@changesets/apply-release-plan": ["@changesets/apply-release-plan@7.0.12", "", { "dependencies": { "@changesets/config": "^3.1.1", "@changesets/get-version-range-type": "^0.4.0", "@changesets/git": "^3.0.4", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "detect-indent": "^6.0.0", "fs-extra": "^7.0.1", "lodash.startcase": "^4.4.0", "outdent": "^0.5.0", "prettier": "^2.7.1", "resolve-from": "^5.0.0", "semver": "^7.5.3" } }, "sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ=="],
@@ -2217,19 +2217,19 @@
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"turbo": ["turbo@2.5.4", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.4", "turbo-darwin-arm64": "2.5.4", "turbo-linux-64": "2.5.4", "turbo-linux-arm64": "2.5.4", "turbo-windows-64": "2.5.4", "turbo-windows-arm64": "2.5.4" }, "bin": { "turbo": "bin/turbo" } }, "sha512-kc8ZibdRcuWUG1pbYSBFWqmIjynlD8Lp7IB6U3vIzvOv9VG+6Sp8bzyeBWE3Oi8XV5KsQrznyRTBPvrf99E4mA=="],
"turbo": ["turbo@2.5.5", "", { "optionalDependencies": { "turbo-darwin-64": "2.5.5", "turbo-darwin-arm64": "2.5.5", "turbo-linux-64": "2.5.5", "turbo-linux-arm64": "2.5.5", "turbo-windows-64": "2.5.5", "turbo-windows-arm64": "2.5.5" }, "bin": { "turbo": "bin/turbo" } }, "sha512-eZ7wI6KjtT1eBqCnh2JPXWNUAxtoxxfi6VdBdZFvil0ychCOTxbm7YLRBi1JSt7U3c+u3CLxpoPxLdvr/Npr3A=="],
"turbo-darwin-64": ["turbo-darwin-64@2.5.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ah6YnH2dErojhFooxEzmvsoZQTMImaruZhFPfMKPBq8sb+hALRdvBNLqfc8NWlZq576FkfRZ/MSi4SHvVFT9PQ=="],
"turbo-darwin-64": ["turbo-darwin-64@2.5.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-RYnTz49u4F5tDD2SUwwtlynABNBAfbyT2uU/brJcyh5k6lDLyNfYKdKmqd3K2ls4AaiALWrFKVSBsiVwhdFNzQ=="],
"turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2+Nx6LAyuXw2MdXb7pxqle3MYignLvS7OwtsP9SgtSBaMlnNlxl9BovzqdYAgkUW3AsYiQMJ/wBRb7d+xemM5A=="],
"turbo-darwin-arm64": ["turbo-darwin-arm64@2.5.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Tk+ZeSNdBobZiMw9aFypQt0DlLsWSFWu1ymqsAdJLuPoAH05qCfYtRxE1pJuYHcJB5pqI+/HOxtJoQ40726Btw=="],
"turbo-linux-64": ["turbo-linux-64@2.5.4", "", { "os": "linux", "cpu": "x64" }, "sha512-5May2kjWbc8w4XxswGAl74GZ5eM4Gr6IiroqdLhXeXyfvWEdm2mFYCSWOzz0/z5cAgqyGidF1jt1qzUR8hTmOA=="],
"turbo-linux-64": ["turbo-linux-64@2.5.5", "", { "os": "linux", "cpu": "x64" }, "sha512-2/XvMGykD7VgsvWesZZYIIVXMlgBcQy+ZAryjugoTcvJv8TZzSU/B1nShcA7IAjZ0q7OsZ45uP2cOb8EgKT30w=="],
"turbo-linux-arm64": ["turbo-linux-arm64@2.5.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-/2yqFaS3TbfxV3P5yG2JUI79P7OUQKOUvAnx4MV9Bdz6jqHsHwc9WZPpO4QseQm+NvmgY6ICORnoVPODxGUiJg=="],
"turbo-linux-arm64": ["turbo-linux-arm64@2.5.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-DW+8CjCjybu0d7TFm9dovTTVg1VRnlkZ1rceO4zqsaLrit3DgHnN4to4uwyuf9s2V/BwS3IYcRy+HG9BL596Iw=="],
"turbo-windows-64": ["turbo-windows-64@2.5.4", "", { "os": "win32", "cpu": "x64" }, "sha512-EQUO4SmaCDhO6zYohxIjJpOKRN3wlfU7jMAj3CgcyTPvQR/UFLEKAYHqJOnJtymbQmiiM/ihX6c6W6Uq0yC7mA=="],
"turbo-windows-64": ["turbo-windows-64@2.5.5", "", { "os": "win32", "cpu": "x64" }, "sha512-q5p1BOy8ChtSZfULuF1BhFMYIx6bevXu4fJ+TE/hyNfyHJIfjl90Z6jWdqAlyaFLmn99X/uw+7d6T/Y/dr5JwQ=="],
"turbo-windows-arm64": ["turbo-windows-arm64@2.5.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-oQ8RrK1VS8lrxkLriotFq+PiF7iiGgkZtfLKF4DDKsmdbPo0O9R2mQxm7jHLuXraRCuIQDWMIw6dpcr7Iykf4A=="],
"turbo-windows-arm64": ["turbo-windows-arm64@2.5.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-AXbF1KmpHUq3PKQwddMGoKMYhHsy5t1YBQO8HZ04HLMR0rWv9adYlQ8kaeQJTko1Ay1anOBFTqaxfVOOsu7+1Q=="],
"tw-animate-css": ["tw-animate-css@1.3.5", "", {}, "sha512-t3u+0YNoloIhj1mMXs779P6MO9q3p3mvGn4k1n3nJPqJw/glZcuijG2qTSN4z4mgNRfW5ZC3aXJFLwDtiipZXA=="],

View File

@@ -15,11 +15,11 @@
"deploy:web": "turbo run --filter=web deploy"
},
"devDependencies": {
"@biomejs/biome": "2.0.0",
"@biomejs/biome": "2.1.2",
"@changesets/cli": "^2.29.5",
"husky": "^9.1.7",
"lint-staged": "^16.1.2",
"turbo": "^2.5.4",
"turbo": "^2.5.5",
"typescript": "5.8.3"
},
"lint-staged": {