### Quick Start Commands
Source: https://github.com/tamagui/takeout-free/blob/main/README.md
Commands to initialize the project, start backend services, and launch the development server.
```bash
bun install
bun backend # start docker services (postgres, zero)
bun dev # start web dev server at http://localhost:8092
```
--------------------------------
### Docker Compose for Local Development
Source: https://context7.com/tamagui/takeout-free/llms.txt
Sets up PostgreSQL and Zero sync services for local development. Ensure PostgreSQL is healthy before starting other services.
```yaml
# docker-compose.yml
services:
pgdb:
image: pgvector/pgvector:pg16
ports:
- 5533:5432
environment:
POSTGRES_USER: user
POSTGRES_DB: postgres
POSTGRES_PASSWORD: password
command: |
postgres
-c wal_level=logical
-c max_wal_senders=10
-c max_replication_slots=5
migrate:
image: node:24-slim
depends_on:
pgdb:
condition: service_healthy
environment:
ZERO_UPSTREAM_DB: postgresql://user:password@pgdb:5432/postgres
ZERO_CVR_DB: postgresql://user:password@pgdb:5432/zero_cvr
ZERO_CHANGE_DB: postgresql://user:password@pgdb:5432/zero_cdb
command: node migrate-dist.js
zero:
image: "rocicorp/zero:${ZERO_VERSION}"
depends_on:
migrate:
condition: service_completed_successfully
environment:
ZERO_UPSTREAM_DB: postgresql://user:password@pgdb:5432/postgres
ZERO_MUTATE_URL: http://host.docker.internal:8081/api/zero/push
ZERO_QUERY_URL: http://host.docker.internal:8081/api/zero/pull
ports:
- "4948:4848"
```
--------------------------------
### Run Takeout Free development commands
Source: https://context7.com/tamagui/takeout-free/llms.txt
Use these commands to manage dependencies, start backend services, run development servers, and execute database migrations.
```bash
# Install dependencies
bun install
# Start backend services (postgres, zero sync)
bun backend
# Start web development server at http://localhost:8092
bun dev
# Run iOS simulator
bun ios
# Run Android emulator
bun android
# Run database migrations
bun migrate
# Generate Zero types after schema changes
bun zero:generate
# Run tests
bun test:unit
bun test:integration
```
--------------------------------
### Define Post Schema, Permissions, and Mutations
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Defines the `post` schema, server-side permissions, and mutations including an example of logging an event on post creation.
```typescript
// src/data/models/post.ts
import { boolean, number, string, table } from '@rocicorp/zero'
import { mutations, serverWhere } from 'on-zero'
export const schema = table('post')
.columns({
id: string(),
userId: string(),
caption: string().optional(),
createdAt: number(),
})
.primaryKey('id')
const permissions = serverWhere('post', (q, auth) => {
return q.cmp('userId', auth?.id || '')
})
export const mutate = mutations(schema, permissions, {
insert: async (ctx, post: Post) => {
await ctx.tx.mutate.post.insert(post)
if (ctx.server) {
ctx.server.asyncTasks.push(() =>
ctx.server.actions.analyticsActions().logEvent(ctx.authData.id, 'post_created')
)
}
},
})
```
--------------------------------
### Tamagui Shorthand for Padding and Gap
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Apply spacing tokens to padding and gap properties using shorthands like 'p' and 'gap'. This example demonstrates using $4 for padding and $2 for gap.
```tsx
```
--------------------------------
### Tamagui Shorthand for Width and Height
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Set dimensions for components using size tokens with shorthand properties like 'width' and 'height'. This example uses $10 for width and $6 for height.
```tsx
```
--------------------------------
### Tamagui Shorthand for Z-Index
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Control the stacking order of elements using the 'z' shorthand property with z-index tokens. This example sets the z-index to $3.
```tsx
```
--------------------------------
### Implement Client-Side Authentication Hook
Source: https://context7.com/tamagui/takeout-free/llms.txt
Provides a custom hook for managing authentication state and user data in React components. Includes a usage example for a profile page with logout functionality.
```typescript
// src/features/auth/client/authClient.ts
import { createBetterAuthClient } from '@take-out/better-auth-utils'
import { useMemo } from 'react'
import type { AuthData } from 'on-zero'
const betterAuthClient = createBetterAuthClient({
baseURL: 'http://localhost:8081',
plugins: [],
onAuthError: (error) => {
console.error('Auth error:', error.message)
},
})
export const useAuth = () => {
const auth = betterAuthClient.useAuth()
const authData = useMemo((): AuthData | null => {
if (!auth?.user?.id) return null
return {
id: auth.user.id,
role: auth.user.role,
}
}, [auth?.user?.id, auth?.user?.role])
return {
...auth,
authClient: betterAuthClient.authClient,
authData,
isLoggedIn: auth.state === 'logged-in',
}
}
// Usage in component
function ProfilePage() {
const { user, isLoggedIn, authClient } = useAuth()
const handleLogout = async () => {
await authClient.signOut()
}
if (!isLoggedIn) return
return (
Welcome, {user.name}
)
}
```
--------------------------------
### Tamagui Shorthand for Border Radius
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Apply border radius using the 'rounded' shorthand property with available radius tokens. This example uses $4 for the border radius.
```tsx
```
--------------------------------
### Run Android Emulator
Source: https://github.com/tamagui/takeout-free/blob/main/README.md
Launches the Android emulator for development.
```bash
bun android # run in emulator
```
--------------------------------
### Run iOS Simulator
Source: https://github.com/tamagui/takeout-free/blob/main/README.md
Launches the iOS simulator for development.
```bash
bun ios # run in simulator
```
--------------------------------
### Configure Better Auth Server
Source: https://context7.com/tamagui/takeout-free/llms.txt
Initializes the Better Auth server with database hooks, plugins, and session settings. Requires database configuration and appropriate plugin imports.
```typescript
// src/features/auth/server/authServer.ts
import { expo } from '@better-auth/expo'
import { betterAuth } from 'better-auth'
import { admin, bearer, jwt, magicLink } from 'better-auth/plugins'
import { database } from '~/database/database'
export const authServer = betterAuth({
database,
session: {
freshAge: 2 * 24 * 60 * 60 * 1000, // 2 days
storeSessionInDatabase: true,
},
emailAndPassword: {
enabled: true,
},
trustedOrigins: [
'https://example.com',
'http://localhost:8081',
'myapp://',
],
databaseHooks: {
user: {
create: {
async after(user) {
// Create initial user state after signup
await database.query(
'INSERT INTO "userPublic" (id, name) VALUES ($1, $2)',
[user.id, user.name]
)
},
},
},
},
plugins: [
jwt({
jwt: { expirationTime: '3y' },
jwks: { keyPairConfig: { alg: 'EdDSA', crv: 'Ed25519' } },
}),
bearer(),
expo(), // React Native support
magicLink({
sendMagicLink: async ({ email, url }) => {
// Send magic link email
console.info('Magic link:', url)
},
}),
admin(),
],
})
```
--------------------------------
### Use useQuery with a Query Function
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Demonstrates how to fetch data using the `useQuery` hook with a defined query function and parameters.
```tsx
import { useQuery } from '~/zero/client'
import { allPosts } from '~/data/queries/post'
const [posts, status] = useQuery(allPosts, { limit: 20 })
```
--------------------------------
### Project Directory Structure
Source: https://github.com/tamagui/takeout-free/blob/main/README.md
Overview of the file organization for the Takeout Free project.
```text
takeout-free/
├── app/ # File-based routing (One router)
│ ├── (app)/ # Authenticated routes
│ │ ├── auth/ # Login flows
│ │ └── home/ # Main app tabs
│ └── api/ # API routes
├── src/
│ ├── features/ # Feature modules (auth, todo, theme)
│ ├── interface/ # Reusable UI components
│ ├── database/ # Database schema and migrations
│ ├── data/ # Zero schema, models, and queries
│ ├── zero/ # Real-time sync configuration
│ ├── server/ # Server-side code
│ └── tamagui/ # Theme configuration
├── scripts/ # CI/CD and helper scripts
├── docs/ # Documentation
└── assets/ # Images, fonts, splash screens
```
--------------------------------
### Configure and use Zero client
Source: https://context7.com/tamagui/takeout-free/llms.txt
Initialize the Zero client for real-time synchronization and use the provided hooks for reactive data fetching and optimistic mutations.
```tsx
// src/zero/client.tsx
import { createZeroClient } from 'on-zero'
import { schema } from '~/data/schema'
import { models } from '~/data/generated/models'
import * as groupedQueries from '~/data/generated/groupedQueries'
export const {
usePermission,
useQuery,
getQuery,
zero,
ProvideZero,
zeroEvents,
} = createZeroClient({
models,
schema,
groupedQueries,
})
// Usage in components
import { useQuery, zero } from '~/zero/client'
import { todosByUserId } from '~/data/queries/todo'
function TodoList() {
const [todos, { type }] = useQuery(
todosByUserId,
{ userId: 'user-123', limit: 50 },
{ enabled: true }
)
const isLoading = type === 'unknown'
// Optimistic mutation - updates UI immediately
const addTodo = () => {
zero.mutate.todo.insert({
id: crypto.randomUUID(),
userId: 'user-123',
text: 'New task',
completed: false,
createdAt: Date.now(),
})
}
return (
{todos?.map(todo =>
{todo.text}
)}
)
}
```
--------------------------------
### Common Development Commands
Source: https://github.com/tamagui/takeout-free/blob/main/README.md
Standard commands for development, code quality, testing, database management, and deployment.
```bash
# development
bun dev # start web + mobile dev server
bun ios # run iOS simulator
bun android # run Android emulator
bun backend # start docker services
# code quality
bun check # typescript type checking
bun lint # run oxlint
bun lint:fix # auto-fix linting issues
# testing
bun test:unit # unit tests
bun test:integration # integration tests
# database
bun migrate # build and run migrations
# deployment
bun ci --dry-run # run full CI pipeline without deploy
bun ci # full CI/CD with deployment
```
--------------------------------
### useQuery Patterns
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Illustrates different ways to use the `useQuery` hook, including with parameters, options, and conditional execution.
```tsx
// with params
useQuery(queryFn, { param1, param2 })
// with params + options
useQuery(queryFn, { param1, param2 }, { enabled: true })
// conditional - only runs when enabled is true
const [data] = useQuery(userById, { userId }, { enabled: Boolean(userId) })
```
--------------------------------
### Development Environment Configuration
Source: https://context7.com/tamagui/takeout-free/llms.txt
Configure environment variables for development, including authentication secrets, API URLs, and Zero sync settings. Ensure storage credentials are set for S3/R2.
```bash
# .env.development
BETTER_AUTH_SECRET=dev-secret-at-least-32-characters-long
BETTER_AUTH_URL=http://localhost:8081
ONE_SERVER_URL=http://localhost:8081
# Zero sync configuration
ZERO_UPSTREAM_DB=postgresql://user:password@localhost:5533/postgres
ZERO_CVR_DB=postgresql://user:password@localhost:5533/zero_cvr
ZERO_CHANGE_DB=postgresql://user:password@localhost:5533/zero_cdb
VITE_ZERO_HOSTNAME=localhost:4948
# Storage (S3/R2)
CLOUDFLARE_R2_ENDPOINT=https://account.r2.cloudflarestorage.com
CLOUDFLARE_R2_ACCESS_KEY=your-access-key
CLOUDFLARE_R2_SECRET_KEY=your-secret-key
```
--------------------------------
### Configure Zero Server and Mutation Endpoint
Source: https://context7.com/tamagui/takeout-free/llms.txt
Sets up the Zero server instance and defines a POST endpoint for handling authenticated mutations. Requires the Better Auth server instance for request validation.
```typescript
// src/zero/server.ts
import { createZeroServer } from 'on-zero/server'
import { models } from '~/data/generated/models'
import { queries } from '~/data/generated/syncedQueries'
import { schema } from '~/data/schema'
import { createServerActions } from '~/data/server/createServerActions'
export const zeroServer = createZeroServer({
schema,
models,
createServerActions,
queries,
database: process.env.ZERO_UPSTREAM_DB,
defaultAllowAdminRole: 'all',
})
// app/api/zero/push+api.tsx - Mutation endpoint
import { getAuthDataFromRequest } from '@take-out/better-auth-utils/server'
import { authServer } from '~/features/auth/server/authServer'
import { zeroServer } from '~/zero/server'
import type { Endpoint } from 'one'
export const POST: Endpoint = async (request) => {
const authData = await getAuthDataFromRequest(authServer, request)
const { response } = await zeroServer.handleMutationRequest({
authData,
request,
})
return Response.json(response)
}
```
--------------------------------
### Using the useMedia Hook
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Import and use the 'useMedia' hook to conditionally render components or apply styles based on active media queries.
```tsx
import { useMedia } from 'tamagui'
const media = useMedia()
if (media.lg) {
// Render for large screens
}
```
--------------------------------
### Environment Variable Configuration
Source: https://github.com/tamagui/takeout-free/blob/main/README.md
Key environment variables required for authentication, server, database, and storage configuration.
```bash
# authentication
BETTER_AUTH_SECRET=
BETTER_AUTH_URL=
# server
ONE_SERVER_URL=
# zero
ZERO_UPSTREAM_DB=
ZERO_CVR_DB=
ZERO_CHANGE_DB=
# storage (S3/R2)
CLOUDFLARE_R2_ENDPOINT=
CLOUDFLARE_R2_ACCESS_KEY=
CLOUDFLARE_R2_SECRET_KEY=
```
--------------------------------
### Regenerating Files with On-Zero
Source: https://github.com/tamagui/takeout-free/blob/main/src/data/generated/README.md
Run this command to regenerate files. Use the `--watch` flag for continuous regeneration during development.
```bash
bun on-zero generate
```
```bash
bun on-zero generate --watch
```
--------------------------------
### Run Database Migrations
Source: https://github.com/tamagui/takeout-free/blob/main/README.md
Executes database migrations after updating schema files.
```bash
bun migrate
```
--------------------------------
### Define ZQL Queries for Todos
Source: https://context7.com/tamagui/takeout-free/llms.txt
Create reactive queries for todos with filtering, ordering, and permissions. Use `useQuery` hook for server-side permissions and related data loading.
```typescript
// src/data/queries/todo.ts
import { serverWhere, zql } from 'on-zero'
const permission = serverWhere('todo', (_, auth) => {
return _.cmp('userId', auth?.id || '')
})
// Basic query with filtering and ordering
export const todosByUserId = (props: { userId: string; limit?: number }) => {
return zql.todo
.where(permission)
.where('userId', props.userId)
.orderBy('createdAt', 'desc')
.limit(props.limit ?? 100)
}
// Single item query
export const todoById = (props: { todoId: string }) => {
return zql.todo.where(permission).where('id', props.todoId).one()
}
// Query with related data
export const userWithTodos = (props: { userId: string }) => {
return zql.userPublic
.where('id', props.userId)
.one()
.related('todos', (q) =>
q.orderBy('createdAt', 'desc').limit(20)
)
.related('state', (q) => q.one())
}
// Cursor-based pagination
export const todosPaginated = (props: {
pageSize: number
cursor?: { id: string; createdAt: number } | null
}) => {
let query = zql.todo
.orderBy('createdAt', 'desc')
.orderBy('id', 'desc')
.limit(props.pageSize)
if (props.cursor) {
query = query.start(props.cursor)
}
return query
}
```
--------------------------------
### Cursor-Based Pagination Query
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Implements cursor-based pagination for posts using `.start()` with `createdAt` and `id` for stable ordering.
```typescript
export const postsPaginated = (props: {
pageSize: number
cursor?: { id: string; createdAt: number } | null
}) => {
let query = zql.post
.orderBy('createdAt', 'desc')
.orderBy('id', 'desc')
.limit(props.pageSize)
if (props.cursor) {
query = query.start(props.cursor)
}
return query
}
```
--------------------------------
### Optimize Authentication Queries
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Use useAuth() for query parameters to avoid waterfalls, reserving useUser() for full profile data.
```tsx
const { user } = useUser() // queries database, waits
const [posts] = useQuery(postsByUserId, { userId: user?.id || '' })
```
```tsx
const { user } = useAuth() // available immediately from jwt
const [posts] = useQuery(postsByUserId, { userId: user?.id || '' })
```
--------------------------------
### Define a Post Query with Permissions
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Defines a query for all posts, applying server-side permissions and ordering. Use with `useQuery` on the client.
```typescript
// src/data/queries/post.ts
import { serverWhere, zql } from 'on-zero'
const permission = serverWhere('post', () => true)
export const allPosts = (props: { limit?: number }) => {
return zql.post
.where(permission)
.orderBy('createdAt', 'desc')
.limit(props.limit || 20)
}
```
--------------------------------
### Importing Queries from Generated Data
Source: https://github.com/tamagui/takeout-free/blob/main/src/data/generated/README.md
Use this pattern to import queries from the generated data folder. Ensure queries are written as plain functions in `../queries/`.
```typescript
import { channelMessages } from '~/data/queries/message'
```
--------------------------------
### App Root Layout with Providers
Source: https://context7.com/tamagui/takeout-free/llms.txt
Configures the application root with necessary providers for Tamagui, SafeArea, and platform-specific rendering. Uses Slot and Stack for routing and YStack for web layout.
```tsx
// app/_layout.tsx
import { Slot, Stack } from 'one'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { YStack } from 'tamagui'
import { TamaguiRootProvider } from '~/tamagui/TamaguiRootProvider'
export function Layout() {
return (
{process.env.VITE_PLATFORM === 'web' ? (
) : (
)}
)
}
```
--------------------------------
### Queueing Async Tasks
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Demonstrates how to defer slow operations like sending push notifications out of the transaction using `server.asyncTasks`.
```typescript
if (ctx.server) {
ctx.server.asyncTasks.push(async () => {
await ctx.server.actions.sendPushNotification(message)
})
}
```
--------------------------------
### Responsive Style Props
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Apply styles conditionally based on screen size using media query prefixes like '$md' and '$lg'.
```tsx
// As style props (prefix with $)
// Multiple breakpoints
```
--------------------------------
### Accessing Theme Colors
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Use the '$' prefix to access theme colors for background and text.
```tsx
```
--------------------------------
### Client-Side Mutation Calls
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Shows how to call generated mutations for insert, update, and delete operations on the client.
```tsx
zero.mutate.post.insert(post)
zero.mutate.post.update(post)
zero.mutate.post.delete(post)
```
--------------------------------
### Applying Animations
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Use the 'animation' prop with duration-based or named presets to animate component transitions.
```tsx
```
--------------------------------
### Call Mutations with Optimistic or Server-Confirmed Modes
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Choose between immediate optimistic UI updates or awaiting server confirmation.
```tsx
// optimistic - updates UI immediately
zero.mutate.post.update(post)
// wait for server confirmation
const result = await zero.mutate.post.update(post).server
```
--------------------------------
### Applying Themes
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Nest Theme components to apply and combine themes. Special props like 'inverse' and 'reset' offer additional control.
```tsx
// Apply a theme
// Themes nest and combine automatically
// Special props
{/* Swaps light ↔ dark */}
{/* Reverts to grandparent theme */}
```
--------------------------------
### Todo Feed Page Layout
Source: https://context7.com/tamagui/takeout-free/llms.txt
This component renders a todo list page using Tamagui. It integrates the `useTodos` hook to fetch and manage todo items, and uses custom `Input` and `Button` components for adding and interacting with todos. It displays a spinner while loading.
```tsx
// app/(app)/home/(tabs)/feed/index.tsx
import { useState } from 'react'
import { isWeb, ScrollView, SizableText, Spinner, Theme, XStack, YStack } from 'tamagui'
import { useTodos } from '~/features/todo/useTodos'
import { Button } from '~/interface/buttons/Button'
import { Input } from '~/interface/forms/Input'
export const HomePage = () => {
const { todos, isLoading, addTodo, toggleTodo, deleteTodo } = useTodos()
const [newTodoText, setNewTodoText] = useState('')
const handleAddTodo = () => {
if (!newTodoText.trim()) return
addTodo(newTodoText.trim())
setNewTodoText('')
}
return (
{isLoading ? (
) : (
{todos.map((todo) => (
toggleTodo(todo.id, !todo.completed)}
/>
{todo.text}
))}
)}
)
}
```
--------------------------------
### Define Server-Side Query Permissions
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Creates a server-side permission check for posts, allowing admins or posts owned by the authenticated user.
```typescript
const permission = serverWhere('post', (q, auth) => {
if (auth?.role === 'admin') return true
return q.cmp('userId', auth?.id || '')
})
```
--------------------------------
### Design Cache-Friendly Queries
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Align query structures between index and detail pages to leverage local cache hits.
```ts
// feedPosts - used on index, includes everything detail page needs
export const feedPosts = (props: { limit: number }) => {
return zql.post
.where(permission)
.limit(props.limit)
.related('user', (q) => q.one())
.related('comments', (q) =>
q.limit(50).related('user', (u) => u.one())
)
}
// postDetail - used on detail page, same shape
export const postDetail = (props: { postId: string }) => {
return zql.post
.where(permission)
.where('id', props.postId)
.one()
.related('user', (q) => q.one())
.related('comments', (q) =>
q.limit(50).related('user', (u) => u.one())
)
}
```
--------------------------------
### Define data models with Zero schema
Source: https://context7.com/tamagui/takeout-free/llms.txt
Define table structures, primary keys, and server-side permissions. Use the mutations helper to auto-generate CRUD operations with integrated permission checks.
```typescript
// src/data/models/todo.ts
import { boolean, number, string, table } from '@rocicorp/zero'
import { mutations, serverWhere } from 'on-zero'
import type { TableInsertRow } from 'on-zero'
export type Todo = TableInsertRow
export const schema = table('todo')
.columns({
id: string(),
userId: string(),
text: string(),
completed: boolean(),
createdAt: number(),
})
.primaryKey('id')
// Server-side permission: users can only access their own todos
const permissions = serverWhere('todo', (_, auth) => {
return _.cmp('userId', auth?.id || '')
})
// Auto-generates insert, update, delete mutations with permission checks
export const mutate = mutations(schema, permissions)
// Custom mutation with server-side logic
export const mutateWithHooks = mutations(schema, permissions, {
insert: async (ctx, todo: Todo) => {
await ctx.tx.mutate.todo.insert(todo)
// Server-only async tasks run after transaction commits
if (ctx.server) {
ctx.server.asyncTasks.push(() =>
ctx.server.actions.analyticsActions().logEvent(ctx.authData.id, 'todo_created')
)
}
},
})
```
--------------------------------
### Input Component Props for Mobile Keyboards
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Utilize inputMode and enterKeyHint props on the Input component for enhanced mobile keyboard experiences. These props are new in v2.
```tsx
```
--------------------------------
### Custom useTodos Hook for Todo Management
Source: https://context7.com/tamagui/takeout-free/llms.txt
This hook encapsulates todo-related queries and mutations, providing a clean interface for components. It requires authentication context and uses a zero-client for data operations. Ensure `userId` is available before performing operations.
```typescript
// src/features/todo/useTodos.ts
import { useMemo } from 'react'
import { todosByUserId } from '~/data/queries/todo'
import { useAuth } from '~/features/auth/client/authClient'
import { useQuery, zero } from '~/zero/client'
export interface Todo {
id: string
userId: string
text: string
completed: boolean
createdAt: number
}
export function useTodos() {
const auth = useAuth()
const userId = auth?.user?.id
const [todos, { type }] = useQuery(
todosByUserId,
{ userId: userId || '' },
{ enabled: Boolean(userId) },
)
const isLoading = type === 'unknown'
const sortedTodos = useMemo(() => {
if (!todos) return []
return [...todos] as Todo[]
}, [todos])
const addTodo = (text: string) => {
if (!userId) return
zero.mutate.todo.insert({
id: crypto.randomUUID(),
userId,
text,
completed: false,
createdAt: Date.now(),
})
}
const toggleTodo = (todoId: string, completed: boolean) => {
zero.mutate.todo.update({ id: todoId, completed })
}
const deleteTodo = (todoId: string) => {
zero.mutate.todo.delete({ id: todoId })
}
return { todos: sortedTodos, isLoading, addTodo, toggleTodo, deleteTodo }
}
```
--------------------------------
### Generate Types
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Regenerate types after schema changes.
```bash
bun tko zero generate
```
--------------------------------
### Server Actions for Mutations
Source: https://context7.com/tamagui/takeout-free/llms.txt
Defines server-side actions for analytics and user management. These actions can be invoked from mutations for background tasks like logging events or sending emails.
```typescript
// src/data/server/createServerActions.ts
import { analyticsActions } from './actions/analyticsActions'
import { userActions } from './actions/userActions'
export const createServerActions = () => {
return {
analyticsActions,
userActions,
}
}
export type ServerActions = ReturnType
// src/data/server/actions/analyticsActions.ts
export const analyticsActions = () => ({
logEvent: async (userId: string, eventName: string) => {
console.log(`[analytics] ${eventName} for user ${userId}`)
// Send to analytics service
},
})
// src/data/server/actions/userActions.ts
export const userActions = () => ({
sendWelcomeEmail: async (email: string) => {
// Send welcome email
},
})
```
--------------------------------
### Styled Button Component with Variants
Source: https://context7.com/tamagui/takeout-free/llms.txt
A customizable Button component built with Tamagui's styled API. It supports various visual variants like 'default', 'outlined', 'transparent', and 'floating', each with distinct styling and hover/press effects. Ensure Tamagui is set up in your project.
```tsx
// src/interface/buttons/Button.tsx
import { Button as TamaguiButton, styled, type GetProps } from 'tamagui'
export const Button = styled(TamaguiButton, {
render: 'button',
borderWidth: 0,
cursor: 'pointer',
focusVisibleStyle: {
outlineWidth: 2,
outlineStyle: 'solid',
outlineColor: '$color8',
},
variants: {
variant: {
default: {
bg: '$color3',
hoverStyle: { bg: '$color4' },
pressStyle: { bg: '$color2', opacity: 0.8 },
},
outlined: {
bg: 'transparent',
borderWidth: 2,
borderColor: '$color6',
hoverStyle: { borderColor: '$color8' },
},
transparent: {
bg: 'transparent',
hoverStyle: { bg: '$color2' },
},
floating: {
bg: '$color4',
shadowColor: '$shadow2',
shadowRadius: 5,
hoverStyle: { bg: '$color5' },
},
},
},
defaultVariants: {
variant: 'default',
},
})
```
--------------------------------
### Implement Deterministic Mutations
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Mutations must be deterministic to ensure consistency between client and server. Generate non-deterministic values like IDs or timestamps on the client before calling the mutation.
```ts
async insert(ctx, post) {
await ctx.tx.mutate.post.insert({
...post,
id: randomId(), // different on each run!
createdAt: Date.now() // different timing!
})
}
```
```ts
async insert(ctx, post) {
// client generates id and timestamp once, passes to mutation
await ctx.tx.mutate.post.insert(post)
// server-only side effects are fine
if (ctx.server) {
await ctx.server.actions.sendEmail(post)
}
}
```
--------------------------------
### Define Public Database Schema with Drizzle ORM
Source: https://context7.com/tamagui/takeout-free/llms.txt
Define PostgreSQL tables exposed to Zero/client using Drizzle ORM. Includes user, user state, and todo tables with appropriate fields and indexes.
```typescript
// src/database/schema-public.ts
import { boolean, index, pgTable, text, timestamp } from 'drizzle-orm/pg-core'
export const userPublic = pgTable(
'userPublic',
{
id: text('id').primaryKey(),
name: text('name'),
username: text('username'),
image: text('image'),
joinedAt: timestamp('joinedAt', { mode: 'string' }).defaultNow().notNull(),
},
(table) => [
index('userPublic_username_idx').on(table.username),
],
)
export const userState = pgTable('userState', {
userId: text('userId').primaryKey(),
darkMode: boolean('darkMode').notNull().default(false),
})
export const todo = pgTable(
'todo',
{
id: text('id').primaryKey(),
userId: text('userId').notNull(),
text: text('text').notNull(),
completed: boolean('completed').notNull().default(false),
createdAt: timestamp('createdAt', { mode: 'string' }).defaultNow().notNull(),
},
(table) => [
index('todo_userId_idx').on(table.userId),
],
)
```
--------------------------------
### Define Relationships Between Tables
Source: https://context7.com/tamagui/takeout-free/llms.txt
Configure one-to-one and one-to-many relationships using the Zero relationships API. This enables the `.related()` method for efficient data loading.
```typescript
// src/data/relationships.ts
import { relationships } from '@rocicorp/zero'
import * as tables from './generated/tables'
export const userRelationships = relationships(tables.userPublic, ({ many, one }) => ({
state: one({
sourceField: ['id'],
destSchema: tables.userState,
destField: ['userId'],
}),
todos: many({
sourceField: ['id'],
destSchema: tables.todo,
destField: ['userId'],
}),
}))
export const todoRelationships = relationships(tables.todo, ({ one }) => ({
user: one({
sourceField: ['userId'],
destSchema: tables.userPublic,
destField: ['id'],
}),
}))
export const allRelationships = [
userRelationships,
todoRelationships,
]
```
--------------------------------
### Implement Soft Deletes
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Use a boolean flag for soft deletes and filter queries accordingly.
```ts
// mutation
async delete(ctx, { id }) {
await ctx.tx.mutate.post.update({ id, deleted: true })
}
// queries filter deleted
.where('deleted', false)
```
--------------------------------
### Styled Input Component
Source: https://context7.com/tamagui/takeout-free/llms.txt
A styled Input component using Tamagui, featuring predefined height, size, and placeholder text color. It also includes a focus visible style for accessibility. This component is ready to be used in forms.
```tsx
// src/interface/forms/Input.tsx
import { Input as TamaguiInput, styled } from 'tamagui'
export const Input = styled(TamaguiInput, {
height: 50,
size: '$5',
borderWidth: 0.5,
placeholderTextColor: '$color8',
focusVisibleStyle: {
outlineWidth: 3,
outlineStyle: 'solid',
outlineColor: '$background04',
},
})
```
--------------------------------
### Perform Server-Side Filtering
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Use server-side filtering with exists() instead of fetching data to the client to perform filtering.
```tsx
const [blockedUsers] = useQuery(blockedByMe, { userId })
const blockedIds = blockedUsers.map(b => b.blockedId)
const [posts] = useQuery(postsFiltered, { blockedUserIds: blockedIds })
```
```ts
// filter server-side with exists()
const notBlocked = serverWhere('post', (q, auth) => {
if (!auth?.id) return true
return q.not(q.exists('authorBlockedBy', (b) => b.where('blockerId', auth.id)))
})
export const feedPosts = () => zql.post.where(notBlocked)
```
--------------------------------
### Define Reusable Server-Side Permissions
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Extracts a reusable permission to `src/data/where/notBlockedByViewer.ts` which filters posts not blocked by the viewer.
```typescript
// src/data/where/notBlockedByViewer.ts
export const notBlockedByViewer = serverWhere('post', (q, auth) => {
if (!auth?.id) return true
return q.not(q.exists('authorBlockedBy', (block) =>
block.where('blockerId', auth.id)
))
})
```
--------------------------------
### Image Component Usage in Tamagui
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Use the Image component for displaying images with web-aligned properties like src and objectFit. This is a new component in v2.
```tsx
```
--------------------------------
### Importing Types from Generated Data
Source: https://github.com/tamagui/takeout-free/blob/main/src/data/generated/README.md
While importing types directly from generated files is possible, it's preferred to re-export them from `../types.ts` for better maintainability.
```typescript
import type { Message } from '~/data/generated/types'
```
```typescript
import type { Message } from '~/data/types'
```
--------------------------------
### Button Default Props Configuration
Source: https://github.com/tamagui/takeout-free/blob/main/docs/tamagui.md
Custom default props for the Button component, including font family, cursor, and focus styles. Ensure these are applied when using the Button.
```tsx
{
fontFamily: '$mono',
cursor: 'default',
focusVisibleStyle: {
outlineWidth: 3,
outlineStyle: 'solid',
outlineColor: '$background04',
}
}
```
--------------------------------
### Define Relationship for Exists()
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Adds a `many` relationship definition in `src/data/relationships.ts` required for the `exists()` permission check.
```typescript
// post -> block via post.userId = block.blockedId
authorBlockedBy: many({
sourceField: ['userId'],
destSchema: tables.block,
destField: ['blockedId'],
})
```
--------------------------------
### Include Related Data with .related()
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Fetches a post along with its user and recent comments, including the comment author's user data.
```typescript
export const postWithComments = (props: { postId: string }) => {
return zql.post
.where('id', props.postId)
.one()
.related('user', (q) => q.one())
.related('comments', (q) =>
q.orderBy('createdAt', 'desc')
.limit(50)
.related('user', (u) => u.one())
)
}
```
--------------------------------
### Mutation Context Type
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Defines the `MutatorContext` type, outlining available properties like transaction, authentication data, and server-specific actions.
```typescript
type MutatorContext = {
tx: Transaction
authData: AuthData | null
environment: 'server' | 'client'
can: (where, obj) => Promise
server?: {
actions: ServerActions
asyncTasks: AsyncAction[] // runs after transaction commits
}
}
```
--------------------------------
### Define Relationships for .related()
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Defines the `user` and `comments` relationships for the `post` schema in `src/data/relationships.ts`.
```typescript
export const postRelationships = relationships(tables.post, ({ one, many }) => ({
user: one({
sourceField: ['userId'],
destSchema: tables.userPublic,
destField: ['id'],
}),
comments: many({
sourceField: ['id'],
destSchema: tables.comment,
destField: ['postId'],
}),
}))
```
--------------------------------
### Prevent N+1 Queries in Lists
Source: https://github.com/tamagui/takeout-free/blob/main/docs/zero.md
Avoid querying related data inside child components. Use query relations to load data upfront.
```tsx
function PostCard({ post }) {
const [author] = useQuery(userById, { userId: post.userId }) // N+1!
return
{author?.username}
}
```
```ts
// include relation in query
export const feedPosts = () => {
return zql.post.related('user', (q) => q.one())
}
function PostCard({ post }) {
return
{post.user?.username}
// already loaded
}
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.