### 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.