mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
feat(web): design overhaul
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
462
apps/web/content/docs/cli-commands.mdx
Normal file
462
apps/web/content/docs/cli-commands.mdx
Normal 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.
|
||||
334
apps/web/content/docs/faq.mdx
Normal file
334
apps/web/content/docs/faq.mdx
Normal 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).*
|
||||
@@ -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)
|
||||
|
||||
236
apps/web/content/docs/installation.mdx
Normal file
236
apps/web/content/docs/installation.mdx
Normal 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
|
||||
@@ -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
1
apps/web/lib/cn.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { twMerge as cn } from "tailwind-merge";
|
||||
@@ -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 |
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 />} />
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 "Status: READY"
|
||||
</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>
|
||||
|
||||
@@ -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 "Built something amazing? We'd love to feature
|
||||
it!"
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
};
|
||||
|
||||
183
apps/web/src/components/ai/page-actions.tsx
Normal file
183
apps/web/src/components/ai/page-actions.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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 ? (
|
||||
|
||||
@@ -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",
|
||||
|
||||
38
bun.lock
38
bun.lock
@@ -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=="],
|
||||
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user