Angular Best Practices for PastCare
Project Location
- Frontend:
/home/reuben/Documents/workspace/past-care-spring-frontend/
- NEVER create Angular files in the backend directory
Mobile-First & Responsive Design (MANDATORY)
All components MUST be:
- Mobile-first: CSS for mobile first, then media queries for larger screens
- Responsive: Work across mobile, tablet, desktop
- Theme-aware: Support light and dark themes using CSS variables
/* Mobile styles first (default) */
.component {
padding: 1rem;
flex-direction: column;
}
/* Tablet and up */
@media (min-width: 768px) {
.component {
padding: 1.5rem;
flex-direction: row;
}
}
/* Desktop and up */
@media (min-width: 1024px) {
.component {
padding: 2rem;
}
}
Color Palette (EXACT COLORS ONLY)
Primary Colors:
- Primary Purple Gradient:
linear-gradient(135deg, #667eea 0%, #764ba2 100%) - buttons, FAB, main actions
- Secondary Purple:
linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%) - advanced features
- Accent Green:
#10b981, #34d399 - success states, verified badges
- Accent Orange:
#f59e0b, #f97316 - warnings, pending states
- Accent Blue:
#3b82f6, #2563eb - information
- Danger Red:
#ef4444, #dc2626 - delete, errors
Neutral Colors:
- Text primary:
#1f2937
- Text secondary:
#6b7280
- Text muted:
#9ca3af
- Border default:
#e5e7eb
- Background light:
#f9fafb
Border Radius Hierarchy
- Page containers:
1.25rem (20px)
- Cards:
1rem (16px)
- Form inputs/buttons:
0.75rem (12px)
- Tags/badges:
0.5rem (8px)
- Pills:
9999px
- Circular:
50%
Spacing System
Padding:
- Page container:
1.5rem
- Cards:
1.25rem to 1.5rem
- Form fields:
0.75rem
- Primary buttons:
0.75rem 1.5rem
Gaps:
- Primary:
1rem (default)
- Compact:
0.5rem
- Wide:
1.5rem to 2rem
Form Field Validation Pattern
// Signal for backend errors
backendFieldErrors = signal<Record<string, string[]>>({});
private parseAndSetBackendFieldErrors(error: any): void {
const fieldErrors: Record<string, string[]> = {};
if (error.error && typeof error.error === 'object') {
for (const key of Object.keys(error.error)) {
if (['message', 'status', 'timestamp', 'path', 'error'].includes(key)) continue;
const value = error.error[key];
if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'string') {
fieldErrors[key] = value;
}
}
}
this.backendFieldErrors.set(fieldErrors);
}
getBackendFieldErrors(fieldName: string): string[] {
return this.backendFieldErrors()[fieldName] || [];
}
@for (error of getBackendFieldErrors('fieldName'); track error) {
<div class="error-message backend-error">{{ error }}</div>
}
CSS Class Naming (BEM)
- Block:
.member-card
- Element:
.member-card__header
- Modifier:
.member-card--selected
- State:
.is-active, .is-disabled, .has-error
PrimeNG Overrides
::ng-deep .p-focus {
box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1) !important;
}
Critical Rules
- ALWAYS use purple gradient for primary actions
- ALWAYS maintain 1rem base gap
- NEVER create custom colors
- ALWAYS include focus states
- NEVER exceed 0.3s for animations
- ALWAYS follow border-radius hierarchy
- ALWAYS use flexbox/grid gaps (not margins)
- NEVER use inline styles
1---2name: angular-best-practices-23description: Angular and frontend development guidelines for PastCare. Use when writing or reviewing Angular code.4---5
6# Angular Best Practices for PastCare
7
8## Project Location
9- Frontend: `/home/reuben/Documents/workspace/past-care-spring-frontend/`
10- NEVER create Angular files in the backend directory
11
12## Mobile-First & Responsive Design (MANDATORY)
13
14All components MUST be:
151. **Mobile-first**: CSS for mobile first, then media queries for larger screens
162. **Responsive**: Work across mobile, tablet, desktop
173. **Theme-aware**: Support light and dark themes using CSS variables
18
19```css
20/* Mobile styles first (default) */
21.component {
22 padding: 1rem;
23 flex-direction: column;
24}
25
26/* Tablet and up */
27@media (min-width: 768px) {
28 .component {
29 padding: 1.5rem;
30 flex-direction: row;
31 }
32}
33
34/* Desktop and up */
35@media (min-width: 1024px) {
36 .component {
37 padding: 2rem;
38 }
39}
40```
41
42## Color Palette (EXACT COLORS ONLY)
43
44**Primary Colors:**
45- Primary Purple Gradient: `linear-gradient(135deg, #667eea 0%, #764ba2 100%)` - buttons, FAB, main actions
46- Secondary Purple: `linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%)` - advanced features
47- Accent Green: `#10b981`, `#34d399` - success states, verified badges
48- Accent Orange: `#f59e0b`, `#f97316` - warnings, pending states
49- Accent Blue: `#3b82f6`, `#2563eb` - information
50- Danger Red: `#ef4444`, `#dc2626` - delete, errors
51
52**Neutral Colors:**
53- Text primary: `#1f2937`
54- Text secondary: `#6b7280`
55- Text muted: `#9ca3af`
56- Border default: `#e5e7eb`
57- Background light: `#f9fafb`
58
59## Border Radius Hierarchy
60
61- Page containers: `1.25rem` (20px)
62- Cards: `1rem` (16px)
63- Form inputs/buttons: `0.75rem` (12px)
64- Tags/badges: `0.5rem` (8px)
65- Pills: `9999px`
66- Circular: `50%`
67
68## Spacing System
69
70**Padding:**
71- Page container: `1.5rem`
72- Cards: `1.25rem` to `1.5rem`
73- Form fields: `0.75rem`
74- Primary buttons: `0.75rem 1.5rem`
75
76**Gaps:**
77- Primary: `1rem` (default)
78- Compact: `0.5rem`
79- Wide: `1.5rem` to `2rem`
80
81## Form Field Validation Pattern
82
83```typescript
84// Signal for backend errors
85backendFieldErrors = signal<Record<string, string[]>>({});
86
87private parseAndSetBackendFieldErrors(error: any): void {
88 const fieldErrors: Record<string, string[]> = {};
89 if (error.error && typeof error.error === 'object') {
90 for (const key of Object.keys(error.error)) {
91 if (['message', 'status', 'timestamp', 'path', 'error'].includes(key)) continue;
92 const value = error.error[key];
93 if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'string') {
94 fieldErrors[key] = value;
95 }
96 }
97 }
98 this.backendFieldErrors.set(fieldErrors);
99}
100
101getBackendFieldErrors(fieldName: string): string[] {
102 return this.backendFieldErrors()[fieldName] || [];
103}
104```
105
106```html
107@for (error of getBackendFieldErrors('fieldName'); track error) {
108 <div class="error-message backend-error">{{ error }}</div>
109}
110```
111
112## CSS Class Naming (BEM)
113
114- Block: `.member-card`
115- Element: `.member-card__header`
116- Modifier: `.member-card--selected`
117- State: `.is-active`, `.is-disabled`, `.has-error`
118
119## PrimeNG Overrides
120
121```css
122::ng-deep .p-focus {
123 box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1) !important;
124}
125```
126
127## Critical Rules
128
1291. ALWAYS use purple gradient for primary actions
1302. ALWAYS maintain 1rem base gap
1313. NEVER create custom colors
1324. ALWAYS include focus states
1335. NEVER exceed 0.3s for animations
1346. ALWAYS follow border-radius hierarchy
1357. ALWAYS use flexbox/grid gaps (not margins)
1368. NEVER use inline styles