Skip to content

Commit 5ba65b8

Browse files
Enhance .continue/rules with comprehensive TanStack Start, TypeScript, and accessibility guidance (#68)
This PR significantly enhances the `.continue/rules` directory with comprehensive guidance based on the improvements suggested for the Copilot instructions. The changes expand developer guidance for TanStack Start, TypeScript, React Query, Zod, Tailwind, and Shadcn/ui while maintaining the existing structure and adding practical, AI-friendly examples. ## Key Enhancements ### 🚀 TanStack Start Routing Improvements - **Loader/Action Conventions**: Added comprehensive examples for typing loader and action returns with proper TypeScript integration - **Error and Loading Boundaries**: Implemented ErrorBoundary and PendingBoundary usage patterns with practical examples - **Loader-First Data Flow**: Detailed guidance on when to use loaders vs React Query to avoid redundant fetching ```typescript // Example: Properly typed loader with boundaries export const Route = createFileRoute('/users/$id')({ loader: async ({ params }): Promise<User> => { const userIdSchema = z.object({ id: z.string() }) const { id } = userIdSchema.parse(params) return fetchUser(id) }, errorComponent: ({ error }) => ( <ErrorDisplay error={error} /> ), pendingComponent: () => <LoadingSpinner />, component: UserDetail, }) ``` ### 📦 Import Aliasing and Project Structure - **Path Mapping**: Enhanced import patterns with `@/` aliasing best practices - **Clean Imports**: Examples showing preference for aliased imports over relative paths - **Module Organization**: Improved guidance on component and utility organization ### ♿ Accessibility and ARIA Best Practices - **ARIA Implementation**: Comprehensive examples for accessible components - **Focus Management**: Keyboard navigation and focus management patterns - **Semantic HTML**: Guidelines for proper HTML semantics before ARIA ```typescript // Example: Accessible form with proper ARIA <form onSubmit={handleSubmit} aria-labelledby="form-title"> <h2 id="form-title">User Registration</h2> <input id="email" type="email" aria-describedby="email-error" aria-invalid={errors.email ? 'true' : 'false'} /> </form> ``` ### 🔍 TypeScript and Zod Integration - **Type Derivation**: Enhanced patterns for deriving TypeScript types from Zod schemas - **Schema Organization**: Comprehensive examples for centralized schema management - **Validation Patterns**: Practical examples for API validation and external data handling ### 🧪 Testing Guidelines (New) - **React Testing Library**: Patterns for testing user behavior over implementation - **TanStack Router Testing**: Examples for testing route components with mocked loaders - **Custom Hook Testing**: Comprehensive patterns for testing hooks and utilities ## Files Updated - **`file-structure-frameworks.md`**: Enhanced with TanStack Start patterns, import aliasing, and boundaries - **`validation-zod.md`**: Expanded with comprehensive examples and type derivation patterns - **`state-management.md`**: Updated with loader-first data flow guidance - **`styling-ui-guidelines.md`**: Enhanced with accessibility and ARIA best practices - **`mcp-app-demo-standards.md`**: Improved TypeScript patterns and React component examples - **`testing-guidelines.md`**: New file with comprehensive testing patterns ## Benefits ✅ **Actionable Guidance**: 30+ practical, copy-paste ready TypeScript examples ✅ **AI-Friendly**: Maintains existing structure while improving clarity for AI assistants ✅ **Comprehensive Coverage**: Addresses all modern React development patterns ✅ **Accessibility Focus**: Ensures inclusive development practices ✅ **Type Safety**: Emphasizes proper TypeScript usage throughout the stack The enhancements maintain backward compatibility while significantly improving the developer experience and code quality guidance for the MCP App Demo project. <!-- START COPILOT CODING AGENT TIPS --> --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: nickytonline <833231+nickytonline@users.noreply.github.com>
1 parent 06bf6cf commit 5ba65b8

6 files changed

Lines changed: 566 additions & 4 deletions

File tree

.continue/rules/file-structure-frameworks.md

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,98 @@ You are an expert in TanStack Start routing and modern React project organizatio
1515
• Use bracket notation like `[id].tsx` for dynamic routes
1616
• Use `_layout.tsx` files for shared layouts across route groups
1717

18-
## Route File Structure
18+
## Route File Structure and Patterns
1919

2020
• Export `loader` functions for data fetching before route renders
2121
• Export `action` functions for handling form submissions and mutations
2222
• Export `meta` objects for page metadata (title, description, etc.)
2323
• Keep route components focused on layout and data orchestration
2424
• Extract complex logic into custom hooks or utility functions
2525

26+
### Loader and Action Typing
27+
28+
• Always type loader and action returns explicitly for better type safety
29+
• Use Zod schemas for validating loader parameters and action inputs
30+
• Leverage `useLoaderData()` with proper typing for accessing loader data
31+
32+
```typescript
33+
// ✅ Good: Properly typed loader with validation
34+
export const Route = createFileRoute('/users/$id')({
35+
loader: async ({ params }): Promise<User> => {
36+
const userIdSchema = z.object({ id: z.string() })
37+
const { id } = userIdSchema.parse(params)
38+
return fetchUser(id)
39+
},
40+
component: UserDetail,
41+
})
42+
43+
function UserDetail() {
44+
const user = Route.useLoaderData() // Automatically typed as User
45+
return <div>{user.name}</div>
46+
}
47+
```
48+
49+
### Loader-First Data Flow
50+
51+
• Prefer loaders over React Query for initial page data to avoid redundant fetching
52+
• Use React Query only for data that needs frequent updates or client-side caching
53+
• Implement loader-first pattern to ensure data is available before component renders
54+
55+
```typescript
56+
// ✅ Good: Loader-first approach
57+
export const Route = createFileRoute('/dashboard')({
58+
loader: async (): Promise<DashboardData> => {
59+
// Fetch initial data in loader
60+
return {
61+
user: await fetchUser(),
62+
metrics: await fetchMetrics(),
63+
}
64+
},
65+
component: Dashboard,
66+
})
67+
68+
// ❌ Avoid: Redundant React Query when loader data is sufficient
69+
function Dashboard() {
70+
const data = Route.useLoaderData()
71+
// Don't use React Query here if loader data is sufficient
72+
return <DashboardView data={data} />
73+
}
74+
```
75+
76+
### Error and Loading Boundaries
77+
78+
• Use ErrorBoundary for handling route-level errors gracefully
79+
• Implement PendingBoundary for loading states during navigation
80+
• Provide meaningful error messages and recovery options
81+
82+
```typescript
83+
// ✅ Good: Route with error and pending boundaries
84+
export const Route = createFileRoute('/users/$id')({
85+
loader: async ({ params }) => {
86+
try {
87+
return await fetchUser(params.id)
88+
} catch (error) {
89+
throw new Error(`Failed to load user: ${error.message}`)
90+
}
91+
},
92+
errorComponent: ({ error }) => (
93+
<div className="text-center p-6">
94+
<h2 className="text-xl font-semibold text-red-600 mb-2">Error</h2>
95+
<p className="text-gray-600">{error.message}</p>
96+
<Link to="/users" className="text-blue-600 hover:underline mt-4 inline-block">
97+
Back to Users
98+
</Link>
99+
</div>
100+
),
101+
pendingComponent: () => (
102+
<div className="flex items-center justify-center p-6">
103+
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
104+
</div>
105+
),
106+
component: UserDetail,
107+
})
108+
```
109+
26110
## Component Organization
27111
28112
• Keep shared UI components in `src/components`
@@ -45,7 +129,27 @@ You are an expert in TanStack Start routing and modern React project organizatio
45129
• Prefer named exports for utilities and hooks
46130
• Use default exports for React components
47131
• Implement proper module boundaries between features
48-
• Use path mapping for clean import statements when necessary
132+
• Use path mapping (`@/`) for clean import statements - configured in tsconfig.json
133+
134+
### Import Aliasing Best Practices
135+
136+
• Use `@/components` for importing UI components
137+
• Use `@/lib` for utilities, schemas, and helper functions
138+
• Use `@/hooks` for custom React hooks
139+
• Use `@/contexts` for React Context providers
140+
• Always prefer aliased imports over relative paths for better maintainability
141+
142+
```typescript
143+
// ✅ Good: Clean aliased imports
144+
import { Button } from '@/components/ui/button'
145+
import { userSchema } from '@/lib/schemas'
146+
import { useLocalStorage } from '@/hooks/useLocalStorage'
147+
import { UserProvider } from '@/contexts/UserContext'
148+
149+
// ❌ Avoid: Relative path imports for shared code
150+
import { Button } from '../../../components/ui/button'
151+
import { userSchema } from '../../lib/schemas'
152+
```
49153
50154
## File Naming Conventions
51155

.continue/rules/mcp-app-demo-standards.md

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,50 @@ You are an expert in TypeScript, React, TanStack Start, Vite, Tailwind CSS, and
99

1010
## Technology Stack
1111

12-
• This project uses TypeScript, Vite, TanStack Start, Tailwind CSS, and Shadcn/ui components
12+
• This project uses TypeScript, Vite, TanStack Start, Tailwind CSS, Shadcn/ui components, Zod validation, and React Query
1313
• All AI-generated code must follow these technologies and existing linting/Prettier rules
14-
• Run `npm run lint:fix` before committing any changes
14+
• Run `npm run check` for formatting and linting before committing any changes
1515
• Follow the established project structure and conventions
16+
• Use import aliasing (`@/`) for clean, maintainable imports
1617

1718
## Type Safety
1819

1920
• Never introduce the `any` type - use proper generics or let TypeScript infer types
2021
• Use explicit type annotations for function parameters and return types where beneficial
2122
• Leverage TypeScript's strict mode for maximum type safety
2223
• Use type guards for runtime type checking when needed
24+
• Derive all types from Zod schemas to maintain consistency between runtime validation and compile-time types
25+
26+
### TypeScript Best Practices
27+
28+
• Prefer type inference when TypeScript can reliably determine the type
29+
• Use union types and discriminated unions for complex state modeling
30+
• Implement proper error handling with typed error objects
31+
• Use generic constraints to create reusable, type-safe utilities
32+
33+
```typescript
34+
// ✅ Good: Proper typing with interface
35+
interface UserProps {
36+
id: string
37+
name: string
38+
email?: string
39+
onUpdate: (user: User) => void
40+
}
41+
42+
// ✅ Good: Type inference where appropriate
43+
const users = await fetchUsers() // Let TypeScript infer User[]
44+
45+
// ✅ Good: Generic constraints for reusable utilities
46+
function createApiResponse<T extends Record<string, unknown>>(
47+
data: T,
48+
status: 'success' | 'error' = 'success'
49+
): ApiResponse<T> {
50+
return { data, status, timestamp: Date.now() }
51+
}
52+
53+
// ❌ Bad: Using any type
54+
const data: any = await fetchData()
55+
```
2356

2457
## Code Quality
2558

@@ -34,3 +67,46 @@ You are an expert in TypeScript, React, TanStack Start, Vite, Tailwind CSS, and
3467
• Keep functions and components focused on a single responsibility
3568
• Use meaningful names for variables, functions, and components
3669
• Implement proper error handling for all operations
70+
• Write self-documenting code that clearly expresses intent
71+
• Follow established patterns for testing when tests exist in the project
72+
73+
### React Component Patterns
74+
75+
• Use function components with TypeScript for all new components
76+
• Implement proper prop typing with interfaces or type definitions
77+
• Use hooks appropriately for state management and side effects
78+
• Follow the component composition pattern over prop drilling
79+
80+
```typescript
81+
// ✅ Good: Well-typed function component
82+
interface ButtonProps {
83+
children: React.ReactNode
84+
onClick: () => void
85+
variant?: 'primary' | 'secondary'
86+
disabled?: boolean
87+
}
88+
89+
export default function Button({
90+
children,
91+
onClick,
92+
variant = 'primary',
93+
disabled = false
94+
}: ButtonProps) {
95+
return (
96+
<button
97+
onClick={onClick}
98+
disabled={disabled}
99+
className={cn(buttonVariants({ variant }), disabled && 'opacity-50')}
100+
>
101+
{children}
102+
</button>
103+
)
104+
}
105+
106+
// ✅ Good: Custom hook for shared logic
107+
function useToggle(initialValue = false) {
108+
const [value, setValue] = useState(initialValue)
109+
const toggle = useCallback(() => setValue(prev => !prev), [])
110+
return [value, toggle] as const
111+
}
112+
```

.continue/rules/state-management.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,50 @@ You are an expert in React state management patterns and modern React developmen
2323
• Use mutations for server state changes with optimistic updates when appropriate
2424
• Configure appropriate cache times and stale-while-revalidate policies
2525

26+
### Loader-First Data Flow Pattern
27+
28+
• Prefer route loaders over React Query for initial page data to avoid redundant fetching
29+
• Use React Query for data that needs frequent updates, real-time syncing, or client-side caching
30+
• Combine loaders with React Query strategically - loaders for initial data, queries for dynamic updates
31+
• Avoid unnecessary API calls by leveraging loader data when appropriate
32+
33+
```typescript
34+
// ✅ Good: Loader-first approach for initial data
35+
export const Route = createFileRoute('/dashboard')({
36+
loader: async (): Promise<DashboardData> => {
37+
// Load critical initial data in the loader
38+
return {
39+
user: await fetchUser(),
40+
metrics: await fetchDashboardMetrics(),
41+
}
42+
},
43+
component: Dashboard,
44+
})
45+
46+
function Dashboard() {
47+
const initialData = Route.useLoaderData()
48+
49+
// Use React Query only for data that needs frequent updates
50+
const { data: liveMetrics } = useQuery({
51+
queryKey: ['live-metrics'],
52+
queryFn: fetchLiveMetrics,
53+
initialData: initialData.metrics,
54+
refetchInterval: 30000, // Update every 30 seconds
55+
})
56+
57+
return <DashboardView user={initialData.user} metrics={liveMetrics} />
58+
}
59+
60+
// ❌ Avoid: Redundant fetching when loader data is sufficient
61+
function BadDashboard() {
62+
// Don't use React Query if loader already provides the data
63+
const { data: user } = useQuery({
64+
queryKey: ['user'],
65+
queryFn: fetchUser, // Redundant if loader already fetched this
66+
})
67+
}
68+
```
69+
2670
## Local Component State
2771
2872
• Use `useState` for simple local component state

.continue/rules/styling-ui-guidelines.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,108 @@ You are an expert in Tailwind CSS and Shadcn/ui component development.
3939
• Use consistent border radius and shadow patterns
4040
• Follow accessibility guidelines for color contrast and focus states
4141

42+
## Accessibility and ARIA Best Practices
43+
44+
• Implement proper ARIA labels and descriptions for interactive elements
45+
• Use semantic HTML elements before adding ARIA attributes
46+
• Ensure all interactive elements are keyboard accessible
47+
• Maintain proper color contrast ratios (4.5:1 for normal text, 3:1 for large text)
48+
• Provide alternative text for images and visual content
49+
• Use proper heading hierarchy (h1, h2, h3) for screen readers
50+
51+
### Accessibility Implementation Examples
52+
53+
```typescript
54+
// ✅ Good: Accessible button with proper ARIA
55+
<Button
56+
onClick={handleSubmit}
57+
disabled={isLoading}
58+
aria-label="Submit user registration form"
59+
aria-describedby="submit-help"
60+
>
61+
{isLoading ? 'Submitting...' : 'Submit'}
62+
</Button>
63+
<div id="submit-help" className="sr-only">
64+
This will create your account and send a confirmation email
65+
</div>
66+
67+
// ✅ Good: Accessible form with proper labeling
68+
<form onSubmit={handleSubmit} aria-labelledby="form-title">
69+
<h2 id="form-title">User Registration</h2>
70+
<div className="space-y-4">
71+
<div>
72+
<label htmlFor="email" className="block text-sm font-medium">
73+
Email Address <span aria-hidden="true">*</span>
74+
</label>
75+
<input
76+
id="email"
77+
type="email"
78+
required
79+
aria-describedby="email-error"
80+
aria-invalid={errors.email ? 'true' : 'false'}
81+
className="w-full p-2 border rounded focus:ring-2 focus:ring-primary"
82+
/>
83+
{errors.email && (
84+
<div id="email-error" role="alert" className="text-red-600 text-sm">
85+
{errors.email}
86+
</div>
87+
)}
88+
</div>
89+
</div>
90+
</form>
91+
92+
// ✅ Good: Accessible navigation with skip link
93+
<nav aria-label="Main navigation">
94+
<a href="#main-content" className="sr-only focus:not-sr-only">
95+
Skip to main content
96+
</a>
97+
<ul role="list">
98+
<li><Link to="/" aria-current={pathname === '/' ? 'page' : undefined}>Home</Link></li>
99+
<li><Link to="/about">About</Link></li>
100+
</ul>
101+
</nav>
102+
```
103+
104+
### Focus Management and Keyboard Navigation
105+
106+
• Ensure proper focus management when content changes dynamically
107+
• Implement logical tab order throughout the application
108+
• Provide visible focus indicators that meet accessibility standards
109+
• Use `focus-visible` for keyboard-only focus indication
110+
111+
```typescript
112+
// ✅ Good: Accessible modal with focus management
113+
function AccessibleModal({ isOpen, onClose, children }) {
114+
const modalRef = useRef<HTMLDivElement>(null)
115+
116+
useEffect(() => {
117+
if (isOpen && modalRef.current) {
118+
modalRef.current.focus()
119+
}
120+
}, [isOpen])
121+
122+
return (
123+
<Dialog open={isOpen} onOpenChange={onClose}>
124+
<DialogContent
125+
ref={modalRef}
126+
tabIndex={-1}
127+
aria-labelledby="modal-title"
128+
aria-describedby="modal-description"
129+
className="focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"
130+
>
131+
<DialogHeader>
132+
<DialogTitle id="modal-title">Confirm Action</DialogTitle>
133+
<DialogDescription id="modal-description">
134+
This action cannot be undone.
135+
</DialogDescription>
136+
</DialogHeader>
137+
{children}
138+
</DialogContent>
139+
</Dialog>
140+
)
141+
}
142+
```
143+
42144
## Custom Styling Guidelines
43145

44146
• Avoid writing custom CSS unless absolutely necessary

0 commit comments

Comments
 (0)