@hailer/mcp 1.1.13 → 1.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/.context-watchdog.json +1 -0
- package/.claude/.session-checked +1 -0
- package/.claude/CLAUDE.md +370 -0
- package/.claude/agents/agent-ada-skill-builder.md +94 -0
- package/.claude/agents/agent-alejandro-function-fields.md +342 -0
- package/.claude/agents/agent-bjorn-config-audit.md +103 -0
- package/.claude/agents/agent-builder-agent-creator.md +130 -0
- package/.claude/agents/agent-code-simplifier.md +53 -0
- package/.claude/agents/agent-dmitri-activity-crud.md +159 -0
- package/.claude/agents/agent-giuseppe-app-builder.md +208 -0
- package/.claude/agents/agent-gunther-mcp-tools.md +39 -0
- package/.claude/agents/agent-helga-workflow-config.md +204 -0
- package/.claude/agents/agent-igor-activity-mover-automation.md +125 -0
- package/.claude/agents/agent-ingrid-doc-templates.md +261 -0
- package/.claude/agents/agent-ivan-monolith.md +154 -0
- package/.claude/agents/agent-kenji-data-reader.md +86 -0
- package/.claude/agents/agent-lars-code-inspector.md +102 -0
- package/.claude/agents/agent-marco-mockup-builder.md +110 -0
- package/.claude/agents/agent-marcus-api-documenter.md +323 -0
- package/.claude/agents/agent-marketplace-publisher.md +280 -0
- package/.claude/agents/agent-marketplace-reviewer.md +309 -0
- package/.claude/agents/agent-permissions-handler.md +208 -0
- package/.claude/agents/agent-simple-writer.md +48 -0
- package/.claude/agents/agent-svetlana-code-review.md +171 -0
- package/.claude/agents/agent-tanya-test-runner.md +333 -0
- package/.claude/agents/agent-ui-designer.md +100 -0
- package/.claude/agents/agent-viktor-sql-insights.md +212 -0
- package/.claude/agents/agent-web-search.md +55 -0
- package/.claude/agents/agent-yevgeni-discussions.md +45 -0
- package/.claude/agents/agent-zara-zapier.md +159 -0
- package/.claude/agents/ragnar.md +68 -0
- package/.claude/commands/app-squad.md +135 -0
- package/.claude/commands/audit-squad.md +158 -0
- package/.claude/commands/autoplan.md +563 -0
- package/.claude/commands/cleanup-squad.md +98 -0
- package/.claude/commands/config-squad.md +106 -0
- package/.claude/commands/crud-squad.md +87 -0
- package/.claude/commands/data-squad.md +97 -0
- package/.claude/commands/debug-squad.md +303 -0
- package/.claude/commands/doc-squad.md +65 -0
- package/.claude/commands/handoff.md +137 -0
- package/.claude/commands/health.md +49 -0
- package/.claude/commands/help.md +29 -0
- package/.claude/commands/help:agents.md +151 -0
- package/.claude/commands/help:commands.md +78 -0
- package/.claude/commands/help:faq.md +79 -0
- package/.claude/commands/help:plugins.md +50 -0
- package/.claude/commands/help:skills.md +93 -0
- package/.claude/commands/help:tools.md +75 -0
- package/.claude/commands/hotfix-squad.md +112 -0
- package/.claude/commands/integration-squad.md +82 -0
- package/.claude/commands/janitor-squad.md +167 -0
- package/.claude/commands/learn-auto.md +120 -0
- package/.claude/commands/learn.md +120 -0
- package/.claude/commands/mcp-list.md +27 -0
- package/.claude/commands/onboard-squad.md +140 -0
- package/.claude/commands/plan-workspace.md +732 -0
- package/.claude/commands/prd.md +130 -0
- package/.claude/commands/project-status.md +82 -0
- package/.claude/commands/publish.md +138 -0
- package/.claude/commands/recap.md +69 -0
- package/.claude/commands/restore.md +64 -0
- package/.claude/commands/review-squad.md +152 -0
- package/.claude/commands/save.md +24 -0
- package/.claude/commands/stats.md +19 -0
- package/.claude/commands/swarm.md +210 -0
- package/.claude/commands/tool-builder.md +39 -0
- package/.claude/commands/ws-pull.md +44 -0
- package/.claude/skills/SDK-activity-patterns/SKILL.md +428 -0
- package/.claude/skills/SDK-document-templates/SKILL.md +1033 -0
- package/.claude/skills/SDK-function-fields/SKILL.md +542 -0
- package/.claude/skills/SDK-generate-skill/SKILL.md +92 -0
- package/.claude/skills/SDK-init-skill/SKILL.md +127 -0
- package/.claude/skills/SDK-insight-queries/SKILL.md +787 -0
- package/.claude/skills/SDK-ws-config-skill/SKILL.md +1139 -0
- package/.claude/skills/agent-structure/SKILL.md +98 -0
- package/.claude/skills/api-documentation-patterns/SKILL.md +474 -0
- package/.claude/skills/chrome-mcp-reference/SKILL.md +370 -0
- package/.claude/skills/delegation-routing/SKILL.md +202 -0
- package/.claude/skills/frontend-design/SKILL.md +254 -0
- package/.claude/skills/hailer-activity-mover/SKILL.md +213 -0
- package/.claude/skills/hailer-api-client/SKILL.md +518 -0
- package/.claude/skills/hailer-app-builder/SKILL.md +1440 -0
- package/.claude/skills/hailer-apps-pictures/SKILL.md +269 -0
- package/.claude/skills/hailer-design-system/SKILL.md +231 -0
- package/.claude/skills/hailer-monolith-automations/SKILL.md +686 -0
- package/.claude/skills/hailer-permissions-system/SKILL.md +121 -0
- package/.claude/skills/hailer-project-protocol/SKILL.md +488 -0
- package/.claude/skills/hailer-rest-api/SKILL.md +61 -0
- package/.claude/skills/hailer-rest-api/hailer-activities.md +184 -0
- package/.claude/skills/hailer-rest-api/hailer-admin.md +473 -0
- package/.claude/skills/hailer-rest-api/hailer-calendar.md +256 -0
- package/.claude/skills/hailer-rest-api/hailer-feed.md +249 -0
- package/.claude/skills/hailer-rest-api/hailer-insights.md +195 -0
- package/.claude/skills/hailer-rest-api/hailer-messaging.md +276 -0
- package/.claude/skills/hailer-rest-api/hailer-workflows.md +283 -0
- package/.claude/skills/insight-join-patterns/SKILL.md +174 -0
- package/.claude/skills/integration-patterns/SKILL.md +421 -0
- package/.claude/skills/json-only-output/SKILL.md +72 -0
- package/.claude/skills/lsp-setup/SKILL.md +160 -0
- package/.claude/skills/mcp-direct-tools/SKILL.md +153 -0
- package/.claude/skills/optional-parameters/SKILL.md +72 -0
- package/.claude/skills/publish-hailer-app/SKILL.md +221 -0
- package/.claude/skills/testing-patterns/SKILL.md +630 -0
- package/.claude/skills/tool-builder/SKILL.md +250 -0
- package/.claude/skills/tool-parameter-usage/SKILL.md +126 -0
- package/.claude/skills/tool-response-verification/SKILL.md +92 -0
- package/.claude/skills/zapier-hailer-patterns/SKILL.md +581 -0
- package/.opencode/agent/agent-ada-skill-builder.md +35 -0
- package/.opencode/agent/agent-alejandro-function-fields.md +39 -0
- package/.opencode/agent/agent-bjorn-config-audit.md +36 -0
- package/.opencode/agent/agent-builder-agent-creator.md +39 -0
- package/.opencode/agent/agent-code-simplifier.md +31 -0
- package/.opencode/agent/agent-dmitri-activity-crud.md +40 -0
- package/.opencode/agent/agent-giuseppe-app-builder.md +37 -0
- package/.opencode/agent/agent-gunther-mcp-tools.md +39 -0
- package/.opencode/agent/agent-helga-workflow-config.md +204 -0
- package/.opencode/agent/agent-igor-activity-mover-automation.md +46 -0
- package/.opencode/agent/agent-ingrid-doc-templates.md +39 -0
- package/.opencode/agent/agent-ivan-monolith.md +46 -0
- package/.opencode/agent/agent-kenji-data-reader.md +53 -0
- package/.opencode/agent/agent-lars-code-inspector.md +28 -0
- package/.opencode/agent/agent-marco-mockup-builder.md +42 -0
- package/.opencode/agent/agent-marcus-api-documenter.md +53 -0
- package/.opencode/agent/agent-marketplace-publisher.md +44 -0
- package/.opencode/agent/agent-marketplace-reviewer.md +42 -0
- package/.opencode/agent/agent-permissions-handler.md +50 -0
- package/.opencode/agent/agent-simple-writer.md +45 -0
- package/.opencode/agent/agent-svetlana-code-review.md +39 -0
- package/.opencode/agent/agent-tanya-test-runner.md +57 -0
- package/.opencode/agent/agent-ui-designer.md +56 -0
- package/.opencode/agent/agent-viktor-sql-insights.md +34 -0
- package/.opencode/agent/agent-web-search.md +42 -0
- package/.opencode/agent/agent-yevgeni-discussions.md +37 -0
- package/.opencode/agent/agent-zara-zapier.md +53 -0
- package/.opencode/commands/app-squad.md +135 -0
- package/.opencode/commands/audit-squad.md +158 -0
- package/.opencode/commands/autoplan.md +563 -0
- package/.opencode/commands/cleanup-squad.md +98 -0
- package/.opencode/commands/config-squad.md +106 -0
- package/.opencode/commands/crud-squad.md +87 -0
- package/.opencode/commands/data-squad.md +97 -0
- package/.opencode/commands/debug-squad.md +303 -0
- package/.opencode/commands/doc-squad.md +65 -0
- package/.opencode/commands/handoff.md +137 -0
- package/.opencode/commands/health.md +49 -0
- package/.opencode/commands/help-agents.md +151 -0
- package/.opencode/commands/help-commands.md +32 -0
- package/.opencode/commands/help-faq.md +29 -0
- package/.opencode/commands/help-plugins.md +28 -0
- package/.opencode/commands/help-skills.md +7 -0
- package/.opencode/commands/help-tools.md +40 -0
- package/.opencode/commands/help.md +28 -0
- package/.opencode/commands/hotfix-squad.md +112 -0
- package/.opencode/commands/integration-squad.md +82 -0
- package/.opencode/commands/janitor-squad.md +167 -0
- package/.opencode/commands/learn-auto.md +120 -0
- package/.opencode/commands/learn.md +120 -0
- package/.opencode/commands/mcp-list.md +27 -0
- package/.opencode/commands/onboard-squad.md +140 -0
- package/.opencode/commands/plan-workspace.md +732 -0
- package/.opencode/commands/prd.md +131 -0
- package/.opencode/commands/project-status.md +82 -0
- package/.opencode/commands/publish.md +138 -0
- package/.opencode/commands/recap.md +69 -0
- package/.opencode/commands/restore.md +64 -0
- package/.opencode/commands/review-squad.md +152 -0
- package/.opencode/commands/save.md +24 -0
- package/.opencode/commands/stats.md +19 -0
- package/.opencode/commands/swarm.md +210 -0
- package/.opencode/commands/tool-builder.md +39 -0
- package/.opencode/commands/ws-pull.md +44 -0
- package/.opencode/opencode.json +21 -0
- package/package.json +1 -1
- package/scripts/postinstall.cjs +64 -0
- package/scripts/test-hal-tools.ts +154 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hailer-apps-pictures
|
|
3
|
+
description: Pattern for fetching and displaying images from Hailer in React apps
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
triggers: When building Hailer apps that need to display images from activities or insights
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Hailer Apps Image Handling
|
|
9
|
+
|
|
10
|
+
Pattern for fetching and displaying images from Hailer in React apps.
|
|
11
|
+
|
|
12
|
+
## Image URL Format
|
|
13
|
+
|
|
14
|
+
Hailer serves images from this endpoint:
|
|
15
|
+
```
|
|
16
|
+
https://api.hailer.com/image/hires/{imageId}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### URL Patterns
|
|
20
|
+
|
|
21
|
+
**Correct formats (use these):**
|
|
22
|
+
- `https://api.hailer.com/image/hires/{imageId}` - High-resolution images, works without authentication
|
|
23
|
+
- `https://api.hailer.com/image/thumbnail/{imageId}` - Thumbnail version for lists/grids
|
|
24
|
+
|
|
25
|
+
**Wrong formats (don't use):**
|
|
26
|
+
- `https://app.hailer.com/api/files/{imageId}` - CORS issues in browsers
|
|
27
|
+
- `https://api.hailer.com/files/{imageId}` - Authentication required, may fail in apps
|
|
28
|
+
- `https://api.hailer.com/image/{imageId}` - Missing size parameter
|
|
29
|
+
|
|
30
|
+
### Utility Function
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
function getImageUrl(imageId: string, size: 'hires' | 'thumbnail' = 'hires'): string {
|
|
34
|
+
return `https://api.hailer.com/image/${size}/${imageId}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Usage
|
|
38
|
+
const url = getImageUrl('abc123', 'hires'); // https://api.hailer.com/image/hires/abc123
|
|
39
|
+
const thumbUrl = getImageUrl('abc123', 'thumbnail'); // https://api.hailer.com/image/thumbnail/abc123
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Extracting imageId from Activity Fields
|
|
43
|
+
|
|
44
|
+
Image IDs typically come from file fields in activities. Extract them from the activity structure:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// From a file field in an activity
|
|
48
|
+
const fileField = activity.fields.image_file; // e.g., { id: "file_xyz", name: "photo.jpg" }
|
|
49
|
+
const imageId = fileField?.id;
|
|
50
|
+
|
|
51
|
+
// From insight data with embedded URLs
|
|
52
|
+
const imageUrl = item.mainProductImageUrl; // e.g., "https://api.hailer.com/image/hires/abc123"
|
|
53
|
+
const imageId = imageUrl.split('/').pop(); // Extract from end of URL
|
|
54
|
+
|
|
55
|
+
// From JSON array of IDs
|
|
56
|
+
const imageIds = JSON.parse(item.allPictures); // ["id1", "id2", "id3"]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Data Structure
|
|
60
|
+
|
|
61
|
+
Product/activity images typically come from insights with two fields:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
interface WithImages {
|
|
65
|
+
mainProductImageUrl: string; // Full URL to main image
|
|
66
|
+
allPictures: string; // JSON string: '["id1", "id2", "id3"]'
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## HailerImage Component
|
|
71
|
+
|
|
72
|
+
Create a wrapper component for CORS handling and error states:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
// components/HailerImage.tsx
|
|
76
|
+
import { Image, ImageProps, Icon } from '@chakra-ui/react';
|
|
77
|
+
import { FaImage } from 'react-icons/fa6';
|
|
78
|
+
import { useState, useEffect } from 'react';
|
|
79
|
+
import { useHailer } from '../hailer/use-hailer';
|
|
80
|
+
|
|
81
|
+
interface HailerImageProps extends Omit<ImageProps, 'src'> {
|
|
82
|
+
hailerImageUrl?: string;
|
|
83
|
+
fallbackIcon?: boolean;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const HailerImage = ({
|
|
87
|
+
hailerImageUrl,
|
|
88
|
+
fallbackIcon = true,
|
|
89
|
+
alt = 'Image',
|
|
90
|
+
...imageProps
|
|
91
|
+
}: HailerImageProps) => {
|
|
92
|
+
const { inside, hailer } = useHailer(); // ← CORRECT: Destructure from useHailer()
|
|
93
|
+
const [blobUrl, setBlobUrl] = useState<string | null>(null);
|
|
94
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
95
|
+
const [isError, setIsError] = useState(false);
|
|
96
|
+
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
const loadImage = async () => {
|
|
99
|
+
if (!hailerImageUrl) {
|
|
100
|
+
setIsError(true);
|
|
101
|
+
setIsLoading(false);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!hailer?.ready) {
|
|
106
|
+
setIsLoading(true);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const isHailerApiUrl = hailerImageUrl.includes('api.hailer.com');
|
|
112
|
+
const isLocalDevelopment = window.location.hostname === 'localhost';
|
|
113
|
+
|
|
114
|
+
if (isLocalDevelopment && isHailerApiUrl) {
|
|
115
|
+
// CORS blocks api.hailer.com in localhost
|
|
116
|
+
console.log('Local development: Hailer images blocked by CORS. Will work in production.');
|
|
117
|
+
setIsError(true);
|
|
118
|
+
setIsLoading(false);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
setBlobUrl(hailerImageUrl);
|
|
123
|
+
setIsError(false);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error('Error loading image from Hailer:', error);
|
|
126
|
+
setIsError(true);
|
|
127
|
+
} finally {
|
|
128
|
+
setIsLoading(false);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
loadImage();
|
|
133
|
+
|
|
134
|
+
return () => {
|
|
135
|
+
if (blobUrl) {
|
|
136
|
+
URL.revokeObjectURL(blobUrl);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}, [hailerImageUrl, hailer?.ready]);
|
|
140
|
+
|
|
141
|
+
if (isLoading || isError || !blobUrl) {
|
|
142
|
+
return fallbackIcon ? (
|
|
143
|
+
<Icon as={FaImage} color="gray.200" {...imageProps} />
|
|
144
|
+
) : null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<Image
|
|
149
|
+
{...imageProps}
|
|
150
|
+
src={blobUrl}
|
|
151
|
+
alt={alt}
|
|
152
|
+
onError={() => setIsError(true)}
|
|
153
|
+
/>
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Usage: Single Image
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
<HailerImage
|
|
162
|
+
hailerImageUrl={product.mainProductImageUrl}
|
|
163
|
+
loading="lazy"
|
|
164
|
+
objectFit="cover"
|
|
165
|
+
maxW="100%"
|
|
166
|
+
h="auto"
|
|
167
|
+
aspectRatio={1}
|
|
168
|
+
alt="Product image"
|
|
169
|
+
/>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Usage: Image Carousel
|
|
173
|
+
|
|
174
|
+
For multiple images stored as JSON array of IDs:
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
const ProductImageCarousel = ({ allPictures, mainImageUrl }: Props) => {
|
|
178
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
179
|
+
|
|
180
|
+
// Parse JSON string to array of IDs
|
|
181
|
+
const imageIds = useMemo(() => {
|
|
182
|
+
if (!allPictures) return [];
|
|
183
|
+
try {
|
|
184
|
+
const parsed = JSON.parse(allPictures);
|
|
185
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
186
|
+
} catch {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
}, [allPictures]);
|
|
190
|
+
|
|
191
|
+
const hasMultiple = imageIds.length > 1;
|
|
192
|
+
|
|
193
|
+
// Construct URL from ID
|
|
194
|
+
const getCurrentUrl = () => {
|
|
195
|
+
if (imageIds.length === 0) return mainImageUrl || '';
|
|
196
|
+
const id = imageIds[currentIndex];
|
|
197
|
+
return id ? `https://api.hailer.com/image/hires/${id}` : mainImageUrl || '';
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const goNext = () => setCurrentIndex(i => (i + 1) % imageIds.length);
|
|
201
|
+
const goPrev = () => setCurrentIndex(i => (i - 1 + imageIds.length) % imageIds.length);
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<Box position="relative">
|
|
205
|
+
<Image src={getCurrentUrl()} alt="Product" objectFit="contain" />
|
|
206
|
+
|
|
207
|
+
{hasMultiple && (
|
|
208
|
+
<>
|
|
209
|
+
<IconButton
|
|
210
|
+
icon={<FaChevronLeft />}
|
|
211
|
+
onClick={goPrev}
|
|
212
|
+
position="absolute"
|
|
213
|
+
left={2}
|
|
214
|
+
top="50%"
|
|
215
|
+
transform="translateY(-50%)"
|
|
216
|
+
/>
|
|
217
|
+
<IconButton
|
|
218
|
+
icon={<FaChevronRight />}
|
|
219
|
+
onClick={goNext}
|
|
220
|
+
position="absolute"
|
|
221
|
+
right={2}
|
|
222
|
+
top="50%"
|
|
223
|
+
transform="translateY(-50%)"
|
|
224
|
+
/>
|
|
225
|
+
<Text textAlign="center">
|
|
226
|
+
{currentIndex + 1} / {imageIds.length}
|
|
227
|
+
</Text>
|
|
228
|
+
</>
|
|
229
|
+
)}
|
|
230
|
+
</Box>
|
|
231
|
+
);
|
|
232
|
+
};
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Fetching Image Data from Insights
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// In App.tsx or data fetching hook
|
|
239
|
+
const fetchProducts = async () => {
|
|
240
|
+
const data = await hailer.api.public.insight.dataAsObject(PRODUCT_INSIGHT_KEY);
|
|
241
|
+
|
|
242
|
+
return data.map(item => ({
|
|
243
|
+
// ... other fields
|
|
244
|
+
mainProductImageUrl: item.mainProductImageUrl || '',
|
|
245
|
+
allPictures: item.allPictures || '[]',
|
|
246
|
+
}));
|
|
247
|
+
};
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Key Points
|
|
251
|
+
|
|
252
|
+
| Aspect | Details |
|
|
253
|
+
|--------|---------|
|
|
254
|
+
| **URL Format** | `https://api.hailer.com/image/hires/{imageId}` |
|
|
255
|
+
| **CORS** | Blocked in localhost, works in production |
|
|
256
|
+
| **Fallback** | Use `FaImage` icon from react-icons/fa6 |
|
|
257
|
+
| **Performance** | Use `loading="lazy"` for catalog images |
|
|
258
|
+
| **Multiple Images** | Store as JSON array of IDs, construct URLs on demand |
|
|
259
|
+
| **Memory** | Revoke blob URLs on component cleanup |
|
|
260
|
+
|
|
261
|
+
## Dependencies
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{
|
|
265
|
+
"@chakra-ui/react": "^2.x",
|
|
266
|
+
"react-icons": "^5.x",
|
|
267
|
+
"@hailer/app-sdk": "^2.x"
|
|
268
|
+
}
|
|
269
|
+
```
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hailer-design-system
|
|
3
|
+
description: Chakra UI v2 theme, colors, icons, and component patterns for Hailer apps
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
triggers: Build app, UI components, styling, theme, colors, icons, buttons, forms
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Hailer Design System
|
|
9
|
+
|
|
10
|
+
Chakra UI v2 with custom Hailer theme.
|
|
11
|
+
|
|
12
|
+
**Full reference:** Read `docs/design-system/HAILER_DESIGN_SYSTEM.md` for comprehensive documentation (all icons, all components, full examples).
|
|
13
|
+
|
|
14
|
+
## Setup
|
|
15
|
+
|
|
16
|
+
The `react-ts` scaffold template already includes the design system at `src/hailer/theme/`. **Do NOT copy from other projects.**
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
// Already set up by scaffold in main.tsx
|
|
20
|
+
import { ChakraProvider } from '@chakra-ui/react';
|
|
21
|
+
import { theme } from './hailer/theme/theme';
|
|
22
|
+
|
|
23
|
+
<ChakraProvider theme={theme}>
|
|
24
|
+
<App />
|
|
25
|
+
</ChakraProvider>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Colors
|
|
31
|
+
|
|
32
|
+
**Let theme handle colors automatically.** Rarely specify manually.
|
|
33
|
+
|
|
34
|
+
| Use | Color |
|
|
35
|
+
|-----|-------|
|
|
36
|
+
| Primary action | `colorScheme="green"` |
|
|
37
|
+
| Secondary action | `colorScheme="blue"` |
|
|
38
|
+
| Destructive | `colorScheme="red"` |
|
|
39
|
+
| Neutral | `colorScheme="gray"` |
|
|
40
|
+
|
|
41
|
+
**Semantic tokens (auto light/dark):**
|
|
42
|
+
- `subtleText` - Muted text
|
|
43
|
+
- `bodyText` - Main text
|
|
44
|
+
- `chakra-body-bg` - Page background
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Buttons
|
|
49
|
+
|
|
50
|
+
**Variants:**
|
|
51
|
+
- `solid` (default) - For 1-2 button groups
|
|
52
|
+
- `outline` - For 3+ buttons in a series
|
|
53
|
+
- `ghost` - Subtle secondary actions
|
|
54
|
+
|
|
55
|
+
**Critical rules:**
|
|
56
|
+
- Max 2 color schemes per button group
|
|
57
|
+
- Right-align button groups (`justify="flex-end"`)
|
|
58
|
+
- Primary action on the RIGHT
|
|
59
|
+
- Add Hailer icon to primary button
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
// Two buttons - correct
|
|
63
|
+
<HStack spacing={3} justify="flex-end">
|
|
64
|
+
<Button colorScheme="gray">Cancel</Button>
|
|
65
|
+
<Button colorScheme="green">Save</Button>
|
|
66
|
+
</HStack>
|
|
67
|
+
|
|
68
|
+
// 3+ buttons - use outline
|
|
69
|
+
<HStack spacing={3}>
|
|
70
|
+
<Button variant="outline" colorScheme="green" leftIcon={<HailerPlus />}>Create</Button>
|
|
71
|
+
<Button variant="outline" colorScheme="gray">Export</Button>
|
|
72
|
+
<Button variant="outline" colorScheme="gray">Filter</Button>
|
|
73
|
+
</HStack>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Icons
|
|
79
|
+
|
|
80
|
+
**CRITICAL: Only use Hailer icons. Never external libraries.**
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
import { HailerPlus, HailerSettings } from './hailer/theme/icons';
|
|
84
|
+
|
|
85
|
+
<HailerPlus boxSize={6} />
|
|
86
|
+
<Button leftIcon={<HailerPlus />}>Add</Button>
|
|
87
|
+
<IconButton icon={<HailerSettings />} aria-label="Settings" />
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Common icons:**
|
|
91
|
+
- Actions: `HailerPlus`, `HailerEdit`, `HailerTrash`, `HailerSave`
|
|
92
|
+
- Navigation: `HailerChevron`, `HailerMenu`, `HailerSearch`
|
|
93
|
+
- Status: `HailerWarning`, `HailerInfo`, `HailerTick`
|
|
94
|
+
- Objects: `HailerUser`, `HailerCalendar`, `HailerFile`, `HailerActivities`
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Typography
|
|
99
|
+
|
|
100
|
+
| Size | Use |
|
|
101
|
+
|------|-----|
|
|
102
|
+
| `2xl` | Page title |
|
|
103
|
+
| `xl` | Section header |
|
|
104
|
+
| `lg` | Subsection |
|
|
105
|
+
| `md` | Card headers |
|
|
106
|
+
| `sm` | Labels |
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
<Heading size="2xl">Page Title</Heading>
|
|
110
|
+
<Text fontSize="sm" color="subtleText">Caption</Text>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Spacing
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
<Box p={8} maxW="1400px" mx="auto"> // Page container
|
|
119
|
+
<VStack spacing={6} align="stretch"> // Section spacing
|
|
120
|
+
{/* Content */}
|
|
121
|
+
</VStack>
|
|
122
|
+
</Box>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Forms
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
<FormControl isInvalid={hasError}>
|
|
131
|
+
<FormLabel>Field Label</FormLabel>
|
|
132
|
+
<Input placeholder="Enter text..." />
|
|
133
|
+
<FormHelperText>Helper text</FormHelperText>
|
|
134
|
+
<FormErrorMessage>Error message</FormErrorMessage>
|
|
135
|
+
</FormControl>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Selection controls:** Only green colorScheme for Checkbox, Radio, Switch.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Tables
|
|
143
|
+
|
|
144
|
+
**CRITICAL: Use Chakra Table components, not HTML.**
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
<TableContainer>
|
|
148
|
+
<Table variant="simple" size="md">
|
|
149
|
+
<Thead>
|
|
150
|
+
<Tr>
|
|
151
|
+
<Th>Name</Th>
|
|
152
|
+
<Th isNumeric>Count</Th>
|
|
153
|
+
</Tr>
|
|
154
|
+
</Thead>
|
|
155
|
+
<Tbody>
|
|
156
|
+
<Tr>
|
|
157
|
+
<Td>Item</Td>
|
|
158
|
+
<Td isNumeric>42</Td>
|
|
159
|
+
</Tr>
|
|
160
|
+
</Tbody>
|
|
161
|
+
</Table>
|
|
162
|
+
</TableContainer>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Modals
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
<Modal isOpen={isOpen} onClose={onClose} size="md">
|
|
171
|
+
<ModalOverlay />
|
|
172
|
+
<ModalContent>
|
|
173
|
+
<ModalHeader>Title</ModalHeader>
|
|
174
|
+
<ModalCloseButton />
|
|
175
|
+
<ModalBody>Content</ModalBody>
|
|
176
|
+
<ModalFooter>
|
|
177
|
+
<Button onClick={onClose}>Cancel</Button>
|
|
178
|
+
<Button colorScheme="green">Save</Button>
|
|
179
|
+
</ModalFooter>
|
|
180
|
+
</ModalContent>
|
|
181
|
+
</Modal>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Feedback
|
|
187
|
+
|
|
188
|
+
**Toast:**
|
|
189
|
+
```tsx
|
|
190
|
+
toast({
|
|
191
|
+
description: "Your changes have been saved.",
|
|
192
|
+
status: "success",
|
|
193
|
+
duration: 3000,
|
|
194
|
+
isClosable: true
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Alert:**
|
|
199
|
+
```tsx
|
|
200
|
+
<Alert status="error">
|
|
201
|
+
<AlertIcon />
|
|
202
|
+
<AlertDescription>Something went wrong.</AlertDescription>
|
|
203
|
+
</Alert>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Stats
|
|
209
|
+
|
|
210
|
+
**Always use Stat components, not manual Box/Text:**
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
<Stat>
|
|
214
|
+
<StatLabel>Total Users</StatLabel>
|
|
215
|
+
<StatNumber>1,234</StatNumber>
|
|
216
|
+
<StatHelpText>
|
|
217
|
+
<StatArrow type="increase" />
|
|
218
|
+
23%
|
|
219
|
+
</StatHelpText>
|
|
220
|
+
</Stat>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Content Tone
|
|
226
|
+
|
|
227
|
+
- Clear, supportive, human
|
|
228
|
+
- Use contractions ("you're", "we'll")
|
|
229
|
+
- Never blame the user
|
|
230
|
+
- Warm success messages: "Your changes have been saved."
|
|
231
|
+
- Helpful errors: "We couldn't save your changes. Please try again."
|