Skip to content

soyaaroncervantes/react-template

Repository files navigation

react-template

A personal React starter template built with modern tooling, file-based routing, and a component system based on Material Design 3.

Version License

Stack

Layer Technology
Framework React 19 + TypeScript 6
Build Vite 8
Routing TanStack Router (file-based)
Server state TanStack Query
HTTP client superagent + superagent-prefix
Client state Zustand + zustand-slices
UI / Design system @m3e/react (Material Design 3)
Linting & formatting Biome
Testing Vitest + Testing Library
Package manager Bun

Getting started

bun install
cp .env.example .env
bun dev

Environment variables

Variable Description
VITE_APP_NAME Application name
VITE_API_URL Base URL for the API client

Scripts

Command Description
bun dev Start the dev server
bun build Type-check and build for production
bun preview Preview the production build
bun test Run tests
bun test:ui Run tests with the Vitest UI
bun test:coverage Run tests with coverage
bun lint Lint src/ with Biome
bun format Format src/ with Biome
bun check Lint + format src/ with Biome

Project structure

src/
├── core/
│   ├── app.tsx           # Entry point — router + React root
│   ├── clients/          # HTTP client (http-client.ts, api.stores.ts)
│   ├── layouts/          # Reusable layout components (BaseLayout)
│   ├── providers/        # AppProvider, QueryProvider, StoreProvider, ThemeProvider
│   ├── routes/           # File-based routes (__root, _rootLayout)
│   └── stores/           # Zustand store setup (app.store, devtools.store)
├── features/
│   └── theme/
│       ├── components/   # Theme component system (Card, Text, Icon, Button)
│       ├── theme.module.css
│       └── theme.stores.ts
└── shared/
    └── base.types.ts

Theme components

Components are exposed through a single Theme namespace:

import { Theme } from '@/features/theme/components'

<Theme.Text variant="display" size="large">Hello</Theme.Text>
<Theme.Button>Click me</Theme.Button>
<Theme.Icon>home</Theme.Icon>

<Card>
  <Card.Header>Title</Card.Header>
  <Card.Content>Body</Card.Content>
  <Card.Footer>Footer</Card.Footer>
  <Card.Actions>Actions</Card.Actions>
</Card>

The color scheme (light, dark, auto) is managed via useThemeStore. The auto mode resolves to the user's OS preference via getPreferredColorScheme().

import { useThemeStore } from '@/features/theme/theme.stores'

const { theme, setTheme } = useThemeStore()
setTheme('dark') // 'light' | 'dark' | 'auto'

Debugging

The project includes a VSCode debug configuration for Chrome. Press F5 to start the dev server and attach the debugger.

Breakpoints in .tsx files work out of the box. The Start project task (bun dev) runs automatically before the debugger attaches.

HTTP client

HTTP requests are made with superagent. The createApiClient factory creates a typed Agent with optional domain prefix via superagent-prefix.

import { createApiClient } from '@/core/clients/http-client'

const client = createApiClient('https://api.example.com')
const res = await client.get('/users').query({ page: 1 })

Clients are stored in Zustand via apiClientsSlice and accessed with the useApiClients hook:

import { useApiClients } from '@/core/clients/api.stores'

const { add, getClient, remove } = useApiClients()

const domain = 'https://api.example.com'
add(domain)
const client = getClient(domain)

Releases

Releases follow Conventional Commits. Tags are pushed manually and GitHub Actions automatically publishes a GitHub Release with generated notes.

To create a new release, follow the Windsurf workflow at .windsurf/workflows/release.md.