@hustle-together/api-dev-tools 3.6.5 → 3.10.0
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/README.md +5599 -258
- package/bin/cli.js +395 -20
- package/commands/README.md +459 -71
- package/commands/hustle-api-continue.md +158 -0
- package/commands/{api-create.md → hustle-api-create.md} +35 -15
- package/commands/{api-env.md → hustle-api-env.md} +4 -4
- package/commands/{api-interview.md → hustle-api-interview.md} +1 -1
- package/commands/{api-research.md → hustle-api-research.md} +3 -3
- package/commands/hustle-api-sessions.md +149 -0
- package/commands/{api-status.md → hustle-api-status.md} +16 -16
- package/commands/{api-verify.md → hustle-api-verify.md} +2 -2
- package/commands/hustle-combine.md +763 -0
- package/commands/hustle-ui-create-page.md +933 -0
- package/commands/hustle-ui-create.md +825 -0
- package/hooks/api-workflow-check.py +545 -21
- package/hooks/cache-research.py +337 -0
- package/hooks/check-api-routes.py +168 -0
- package/hooks/check-playwright-setup.py +103 -0
- package/hooks/check-storybook-setup.py +81 -0
- package/hooks/detect-interruption.py +165 -0
- package/hooks/enforce-a11y-audit.py +202 -0
- package/hooks/enforce-brand-guide.py +241 -0
- package/hooks/enforce-documentation.py +60 -8
- package/hooks/enforce-freshness.py +184 -0
- package/hooks/enforce-page-components.py +186 -0
- package/hooks/enforce-page-data-schema.py +155 -0
- package/hooks/enforce-questions-sourced.py +146 -0
- package/hooks/enforce-schema-from-interview.py +248 -0
- package/hooks/enforce-ui-disambiguation.py +108 -0
- package/hooks/enforce-ui-interview.py +130 -0
- package/hooks/generate-manifest-entry.py +1161 -0
- package/hooks/session-logger.py +297 -0
- package/hooks/session-startup.py +160 -15
- package/hooks/track-scope-coverage.py +220 -0
- package/hooks/track-tool-use.py +81 -1
- package/hooks/update-api-showcase.py +149 -0
- package/hooks/update-registry.py +352 -0
- package/hooks/update-ui-showcase.py +212 -0
- package/package.json +8 -3
- package/templates/BRAND_GUIDE.md +299 -0
- package/templates/CLAUDE-SECTION.md +56 -24
- package/templates/SPEC.json +640 -0
- package/templates/api-dev-state.json +217 -161
- package/templates/api-showcase/_components/APICard.tsx +153 -0
- package/templates/api-showcase/_components/APIModal.tsx +375 -0
- package/templates/api-showcase/_components/APIShowcase.tsx +231 -0
- package/templates/api-showcase/_components/APITester.tsx +522 -0
- package/templates/api-showcase/page.tsx +41 -0
- package/templates/component/Component.stories.tsx +172 -0
- package/templates/component/Component.test.tsx +237 -0
- package/templates/component/Component.tsx +86 -0
- package/templates/component/Component.types.ts +55 -0
- package/templates/component/index.ts +15 -0
- package/templates/dev-tools/_components/DevToolsLanding.tsx +320 -0
- package/templates/dev-tools/page.tsx +10 -0
- package/templates/page/page.e2e.test.ts +218 -0
- package/templates/page/page.tsx +42 -0
- package/templates/performance-budgets.json +58 -0
- package/templates/registry.json +13 -0
- package/templates/settings.json +90 -0
- package/templates/shared/HeroHeader.tsx +261 -0
- package/templates/shared/index.ts +1 -0
- package/templates/ui-showcase/_components/PreviewCard.tsx +315 -0
- package/templates/ui-showcase/_components/PreviewModal.tsx +676 -0
- package/templates/ui-showcase/_components/UIShowcase.tsx +262 -0
- package/templates/ui-showcase/page.tsx +26 -0
- package/demo/hustle-together/blog/gemini-vs-claude-widgets.html +0 -959
- package/demo/hustle-together/blog/interview-driven-api-development.html +0 -1146
- package/demo/hustle-together/blog/tdd-for-ai.html +0 -982
- package/demo/hustle-together/index.html +0 -1312
- package/demo/workflow-demo-v3.5-backup.html +0 -5008
- package/demo/workflow-demo.html +0 -6202
|
@@ -1,160 +1,52 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.
|
|
2
|
+
"version": "3.10.0",
|
|
3
3
|
"created_at": null,
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
4
|
+
"workflow": null,
|
|
5
|
+
"_workflow_options": ["api-create", "combine-api", "ui-create-component", "ui-create-page"],
|
|
6
|
+
"active_endpoint": null,
|
|
7
|
+
"active_element": null,
|
|
8
|
+
"endpoints": {},
|
|
9
|
+
"elements": {},
|
|
10
|
+
"combine_config": {
|
|
11
|
+
"_comment": "Configuration for combine-api workflow",
|
|
12
|
+
"mode": null,
|
|
13
|
+
"_mode_options": ["api", "ui"],
|
|
14
|
+
"source_elements": [],
|
|
15
|
+
"_source_elements_example": [
|
|
16
|
+
{ "type": "api", "name": "openai", "registry_ref": "apis.openai" },
|
|
17
|
+
{ "type": "api", "name": "wordpress", "registry_ref": "apis.wordpress" }
|
|
18
|
+
],
|
|
19
|
+
"flow_type": null,
|
|
20
|
+
"_flow_type_options": ["sequential", "parallel", "conditional"],
|
|
21
|
+
"error_strategy": null,
|
|
22
|
+
"_error_strategy_options": ["fail-fast", "partial", "retry"],
|
|
23
|
+
"orchestration": {
|
|
24
|
+
"input_mapping": {},
|
|
25
|
+
"output_mapping": {},
|
|
26
|
+
"transforms": []
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"ui_config": {
|
|
30
|
+
"_comment": "Configuration for ui-create-* workflows",
|
|
31
|
+
"mode": null,
|
|
32
|
+
"_mode_options": ["component", "page"],
|
|
33
|
+
"use_brand_guide": false,
|
|
34
|
+
"component_type": null,
|
|
35
|
+
"_component_type_options": ["atom", "molecule", "organism", "template"],
|
|
36
|
+
"page_type": null,
|
|
37
|
+
"_page_type_options": ["landing", "dashboard", "form", "list", "detail", "auth"],
|
|
38
|
+
"accessibility_level": null,
|
|
39
|
+
"_accessibility_level_options": ["AA", "AAA"],
|
|
40
|
+
"data_sources": [],
|
|
41
|
+
"variants": [],
|
|
42
|
+
"sizes": []
|
|
43
|
+
},
|
|
7
44
|
"turn_count": 0,
|
|
8
45
|
"last_turn_timestamp": null,
|
|
9
46
|
"research_queries": [],
|
|
10
47
|
"prompt_detections": [],
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
"status": "not_started",
|
|
14
|
-
"clarified": null,
|
|
15
|
-
"search_variations": [],
|
|
16
|
-
"user_question_asked": false,
|
|
17
|
-
"user_selected": null,
|
|
18
|
-
"phase_exit_confirmed": false,
|
|
19
|
-
"last_question_type": null,
|
|
20
|
-
"description": "Pre-research disambiguation to clarify ambiguous requests"
|
|
21
|
-
},
|
|
22
|
-
"scope": {
|
|
23
|
-
"status": "not_started",
|
|
24
|
-
"confirmed": false,
|
|
25
|
-
"user_question_asked": false,
|
|
26
|
-
"user_confirmed": false,
|
|
27
|
-
"phase_exit_confirmed": false,
|
|
28
|
-
"last_question_type": null,
|
|
29
|
-
"description": "Initial scope understanding and confirmation"
|
|
30
|
-
},
|
|
31
|
-
"research_initial": {
|
|
32
|
-
"status": "not_started",
|
|
33
|
-
"sources": [],
|
|
34
|
-
"summary_shown": false,
|
|
35
|
-
"user_question_asked": false,
|
|
36
|
-
"user_approved": false,
|
|
37
|
-
"phase_exit_confirmed": false,
|
|
38
|
-
"last_question_type": null,
|
|
39
|
-
"description": "Context7/WebSearch research for live documentation"
|
|
40
|
-
},
|
|
41
|
-
"interview": {
|
|
42
|
-
"status": "not_started",
|
|
43
|
-
"questions": [],
|
|
44
|
-
"user_question_count": 0,
|
|
45
|
-
"structured_question_count": 0,
|
|
46
|
-
"decisions": {},
|
|
47
|
-
"user_question_asked": false,
|
|
48
|
-
"user_completed": false,
|
|
49
|
-
"phase_exit_confirmed": false,
|
|
50
|
-
"last_question_type": null,
|
|
51
|
-
"description": "Structured interview about requirements (generated FROM research)"
|
|
52
|
-
},
|
|
53
|
-
"research_deep": {
|
|
54
|
-
"status": "not_started",
|
|
55
|
-
"sources": [],
|
|
56
|
-
"proposed_searches": [],
|
|
57
|
-
"approved_searches": [],
|
|
58
|
-
"executed_searches": [],
|
|
59
|
-
"skipped_searches": [],
|
|
60
|
-
"proposals_shown": false,
|
|
61
|
-
"user_question_asked": false,
|
|
62
|
-
"user_approved": false,
|
|
63
|
-
"phase_exit_confirmed": false,
|
|
64
|
-
"last_question_type": null,
|
|
65
|
-
"description": "Deep dive based on interview answers (adaptive, not shotgun)"
|
|
66
|
-
},
|
|
67
|
-
"schema_creation": {
|
|
68
|
-
"status": "not_started",
|
|
69
|
-
"schema_file": null,
|
|
70
|
-
"fields_count": 0,
|
|
71
|
-
"schema_shown": false,
|
|
72
|
-
"user_question_asked": false,
|
|
73
|
-
"user_confirmed": false,
|
|
74
|
-
"phase_exit_confirmed": false,
|
|
75
|
-
"last_question_type": null,
|
|
76
|
-
"description": "Zod schema creation from research"
|
|
77
|
-
},
|
|
78
|
-
"environment_check": {
|
|
79
|
-
"status": "not_started",
|
|
80
|
-
"keys_required": [],
|
|
81
|
-
"keys_found": [],
|
|
82
|
-
"keys_missing": [],
|
|
83
|
-
"env_shown": false,
|
|
84
|
-
"user_question_asked": false,
|
|
85
|
-
"user_ready": false,
|
|
86
|
-
"phase_exit_confirmed": false,
|
|
87
|
-
"last_question_type": null,
|
|
88
|
-
"description": "API key and environment verification"
|
|
89
|
-
},
|
|
90
|
-
"tdd_red": {
|
|
91
|
-
"status": "not_started",
|
|
92
|
-
"test_file": null,
|
|
93
|
-
"test_count": 0,
|
|
94
|
-
"test_scenarios": [],
|
|
95
|
-
"matrix_shown": false,
|
|
96
|
-
"user_question_asked": false,
|
|
97
|
-
"user_approved": false,
|
|
98
|
-
"phase_exit_confirmed": false,
|
|
99
|
-
"last_question_type": null,
|
|
100
|
-
"description": "Write failing tests first"
|
|
101
|
-
},
|
|
102
|
-
"tdd_green": {
|
|
103
|
-
"status": "not_started",
|
|
104
|
-
"implementation_file": null,
|
|
105
|
-
"all_tests_passing": false,
|
|
106
|
-
"phase_exit_confirmed": false,
|
|
107
|
-
"last_question_type": null,
|
|
108
|
-
"description": "Minimal implementation to pass tests"
|
|
109
|
-
},
|
|
110
|
-
"verify": {
|
|
111
|
-
"status": "not_started",
|
|
112
|
-
"gaps_found": 0,
|
|
113
|
-
"gaps_fixed": 0,
|
|
114
|
-
"gaps_skipped": 0,
|
|
115
|
-
"intentional_omissions": [],
|
|
116
|
-
"re_research_done": false,
|
|
117
|
-
"gap_analysis_shown": false,
|
|
118
|
-
"user_question_asked": false,
|
|
119
|
-
"user_decided": false,
|
|
120
|
-
"user_decision": null,
|
|
121
|
-
"phase_exit_confirmed": false,
|
|
122
|
-
"last_question_type": null,
|
|
123
|
-
"description": "Re-research after Green to verify implementation matches docs"
|
|
124
|
-
},
|
|
125
|
-
"tdd_refactor": {
|
|
126
|
-
"status": "not_started",
|
|
127
|
-
"phase_exit_confirmed": false,
|
|
128
|
-
"last_question_type": null,
|
|
129
|
-
"description": "Code cleanup while keeping tests green"
|
|
130
|
-
},
|
|
131
|
-
"documentation": {
|
|
132
|
-
"status": "not_started",
|
|
133
|
-
"files_updated": [],
|
|
134
|
-
"manifest_updated": false,
|
|
135
|
-
"openapi_updated": false,
|
|
136
|
-
"research_cached": false,
|
|
137
|
-
"checklist_shown": false,
|
|
138
|
-
"user_question_asked": false,
|
|
139
|
-
"user_confirmed": false,
|
|
140
|
-
"phase_exit_confirmed": false,
|
|
141
|
-
"last_question_type": null,
|
|
142
|
-
"description": "Update manifests, OpenAPI, cache research"
|
|
143
|
-
},
|
|
144
|
-
"completion": {
|
|
145
|
-
"status": "not_started",
|
|
146
|
-
"all_tests_passing": false,
|
|
147
|
-
"coverage_100_percent": false,
|
|
148
|
-
"typescript_compiles": false,
|
|
149
|
-
"docs_updated": false,
|
|
150
|
-
"commit_ready": false,
|
|
151
|
-
"files_created": [],
|
|
152
|
-
"files_modified": [],
|
|
153
|
-
"phase_exit_confirmed": false,
|
|
154
|
-
"last_question_type": null,
|
|
155
|
-
"description": "Final verification - all tests pass, docs complete, ready for commit"
|
|
156
|
-
}
|
|
157
|
-
},
|
|
48
|
+
"decisions_history": [],
|
|
49
|
+
"reground_history": [],
|
|
158
50
|
"manifest_generation": {
|
|
159
51
|
"last_run": null,
|
|
160
52
|
"manifest_generated": false,
|
|
@@ -166,14 +58,178 @@
|
|
|
166
58
|
"results": "src/app/api-test/test-results.json"
|
|
167
59
|
}
|
|
168
60
|
},
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
61
|
+
"_endpoint_template": {
|
|
62
|
+
"_comment": "This is a template for new endpoints - copy when creating a new workflow",
|
|
63
|
+
"started_at": null,
|
|
64
|
+
"status": "not_started",
|
|
65
|
+
"library": null,
|
|
66
|
+
"enforce_freshness": true,
|
|
67
|
+
"freshness_threshold_days": 7,
|
|
68
|
+
"scope": {
|
|
69
|
+
"discovered_features": [],
|
|
70
|
+
"implemented_features": [],
|
|
71
|
+
"deferred_features": [],
|
|
72
|
+
"coverage_percent": 0
|
|
73
|
+
},
|
|
74
|
+
"session": {
|
|
75
|
+
"interrupted_at": null,
|
|
76
|
+
"interrupted_phase": null,
|
|
77
|
+
"recovery_checkpoint": null
|
|
78
|
+
},
|
|
79
|
+
"phases": {
|
|
80
|
+
"disambiguation": {
|
|
81
|
+
"status": "not_started",
|
|
82
|
+
"clarified": null,
|
|
83
|
+
"search_variations": [],
|
|
84
|
+
"user_question_asked": false,
|
|
85
|
+
"user_selected": null,
|
|
86
|
+
"phase_exit_confirmed": false,
|
|
87
|
+
"last_question_type": null,
|
|
88
|
+
"description": "Pre-research disambiguation to clarify ambiguous requests"
|
|
89
|
+
},
|
|
90
|
+
"scope": {
|
|
91
|
+
"status": "not_started",
|
|
92
|
+
"confirmed": false,
|
|
93
|
+
"user_question_asked": false,
|
|
94
|
+
"user_confirmed": false,
|
|
95
|
+
"phase_exit_confirmed": false,
|
|
96
|
+
"last_question_type": null,
|
|
97
|
+
"description": "Initial scope understanding and confirmation"
|
|
98
|
+
},
|
|
99
|
+
"research_initial": {
|
|
100
|
+
"status": "not_started",
|
|
101
|
+
"sources": [],
|
|
102
|
+
"summary_shown": false,
|
|
103
|
+
"user_question_asked": false,
|
|
104
|
+
"user_approved": false,
|
|
105
|
+
"phase_exit_confirmed": false,
|
|
106
|
+
"last_question_type": null,
|
|
107
|
+
"description": "Context7/WebSearch research for live documentation"
|
|
108
|
+
},
|
|
109
|
+
"interview": {
|
|
110
|
+
"status": "not_started",
|
|
111
|
+
"questions": [],
|
|
112
|
+
"user_question_count": 0,
|
|
113
|
+
"structured_question_count": 0,
|
|
114
|
+
"decisions": {},
|
|
115
|
+
"user_question_asked": false,
|
|
116
|
+
"user_completed": false,
|
|
117
|
+
"phase_exit_confirmed": false,
|
|
118
|
+
"last_question_type": null,
|
|
119
|
+
"description": "Structured interview about requirements (generated FROM research)"
|
|
120
|
+
},
|
|
121
|
+
"research_deep": {
|
|
122
|
+
"status": "not_started",
|
|
123
|
+
"sources": [],
|
|
124
|
+
"proposed_searches": [],
|
|
125
|
+
"approved_searches": [],
|
|
126
|
+
"executed_searches": [],
|
|
127
|
+
"skipped_searches": [],
|
|
128
|
+
"proposals_shown": false,
|
|
129
|
+
"user_question_asked": false,
|
|
130
|
+
"user_approved": false,
|
|
131
|
+
"phase_exit_confirmed": false,
|
|
132
|
+
"last_question_type": null,
|
|
133
|
+
"description": "Deep dive based on interview answers (adaptive, not shotgun)"
|
|
134
|
+
},
|
|
135
|
+
"schema_creation": {
|
|
136
|
+
"status": "not_started",
|
|
137
|
+
"schema_file": null,
|
|
138
|
+
"fields_count": 0,
|
|
139
|
+
"schema_shown": false,
|
|
140
|
+
"user_question_asked": false,
|
|
141
|
+
"user_confirmed": false,
|
|
142
|
+
"phase_exit_confirmed": false,
|
|
143
|
+
"last_question_type": null,
|
|
144
|
+
"description": "Zod schema creation from research"
|
|
145
|
+
},
|
|
146
|
+
"environment_check": {
|
|
147
|
+
"status": "not_started",
|
|
148
|
+
"keys_required": [],
|
|
149
|
+
"keys_found": [],
|
|
150
|
+
"keys_missing": [],
|
|
151
|
+
"env_shown": false,
|
|
152
|
+
"user_question_asked": false,
|
|
153
|
+
"user_ready": false,
|
|
154
|
+
"phase_exit_confirmed": false,
|
|
155
|
+
"last_question_type": null,
|
|
156
|
+
"description": "API key and environment verification"
|
|
157
|
+
},
|
|
158
|
+
"tdd_red": {
|
|
159
|
+
"status": "not_started",
|
|
160
|
+
"test_file": null,
|
|
161
|
+
"test_count": 0,
|
|
162
|
+
"test_scenarios": [],
|
|
163
|
+
"matrix_shown": false,
|
|
164
|
+
"user_question_asked": false,
|
|
165
|
+
"user_approved": false,
|
|
166
|
+
"phase_exit_confirmed": false,
|
|
167
|
+
"last_question_type": null,
|
|
168
|
+
"description": "Write failing tests first"
|
|
169
|
+
},
|
|
170
|
+
"tdd_green": {
|
|
171
|
+
"status": "not_started",
|
|
172
|
+
"implementation_file": null,
|
|
173
|
+
"all_tests_passing": false,
|
|
174
|
+
"phase_exit_confirmed": false,
|
|
175
|
+
"last_question_type": null,
|
|
176
|
+
"description": "Minimal implementation to pass tests"
|
|
177
|
+
},
|
|
178
|
+
"verify": {
|
|
179
|
+
"status": "not_started",
|
|
180
|
+
"gaps_found": 0,
|
|
181
|
+
"gaps_fixed": 0,
|
|
182
|
+
"gaps_skipped": 0,
|
|
183
|
+
"intentional_omissions": [],
|
|
184
|
+
"re_research_done": false,
|
|
185
|
+
"gap_analysis_shown": false,
|
|
186
|
+
"user_question_asked": false,
|
|
187
|
+
"user_decided": false,
|
|
188
|
+
"user_decision": null,
|
|
189
|
+
"phase_exit_confirmed": false,
|
|
190
|
+
"last_question_type": null,
|
|
191
|
+
"description": "Re-research after Green to verify implementation matches docs"
|
|
192
|
+
},
|
|
193
|
+
"tdd_refactor": {
|
|
194
|
+
"status": "not_started",
|
|
195
|
+
"phase_exit_confirmed": false,
|
|
196
|
+
"last_question_type": null,
|
|
197
|
+
"description": "Code cleanup while keeping tests green"
|
|
198
|
+
},
|
|
199
|
+
"documentation": {
|
|
200
|
+
"status": "not_started",
|
|
201
|
+
"files_updated": [],
|
|
202
|
+
"manifest_updated": false,
|
|
203
|
+
"openapi_updated": false,
|
|
204
|
+
"research_cached": false,
|
|
205
|
+
"checklist_shown": false,
|
|
206
|
+
"user_question_asked": false,
|
|
207
|
+
"user_confirmed": false,
|
|
208
|
+
"phase_exit_confirmed": false,
|
|
209
|
+
"last_question_type": null,
|
|
210
|
+
"description": "Update manifests, OpenAPI, cache research"
|
|
211
|
+
},
|
|
212
|
+
"completion": {
|
|
213
|
+
"status": "not_started",
|
|
214
|
+
"all_tests_passing": false,
|
|
215
|
+
"coverage_100_percent": false,
|
|
216
|
+
"typescript_compiles": false,
|
|
217
|
+
"docs_updated": false,
|
|
218
|
+
"commit_ready": false,
|
|
219
|
+
"files_created": [],
|
|
220
|
+
"files_modified": [],
|
|
221
|
+
"phase_exit_confirmed": false,
|
|
222
|
+
"last_question_type": null,
|
|
223
|
+
"description": "Final verification - all tests pass, docs complete, ready for commit"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
"verification": {
|
|
227
|
+
"all_sources_fetched": false,
|
|
228
|
+
"schema_matches_docs": false,
|
|
229
|
+
"tests_cover_params": false,
|
|
230
|
+
"all_tests_passing": false,
|
|
231
|
+
"coverage_percent": null,
|
|
232
|
+
"post_green_verification": false
|
|
233
|
+
}
|
|
234
|
+
}
|
|
179
235
|
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
interface RegistryAPI {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
route: string;
|
|
7
|
+
schemas?: string;
|
|
8
|
+
tests?: string;
|
|
9
|
+
methods?: string[];
|
|
10
|
+
created_at?: string;
|
|
11
|
+
status?: string;
|
|
12
|
+
combines?: string[];
|
|
13
|
+
flow_type?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface APICardProps {
|
|
17
|
+
id: string;
|
|
18
|
+
type: 'api' | 'combined';
|
|
19
|
+
data: RegistryAPI;
|
|
20
|
+
onClick: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* API Card Component
|
|
25
|
+
*
|
|
26
|
+
* Displays a preview card for an API in the showcase grid.
|
|
27
|
+
* Hustle Together branding with boxy 90s style.
|
|
28
|
+
* Hover: Solid red shadow (4px 4px 0 #BA0C2F), no border change.
|
|
29
|
+
*
|
|
30
|
+
* Created with Hustle API Dev Tools (v3.9.2)
|
|
31
|
+
*/
|
|
32
|
+
export function APICard({ id, type, data, onClick }: APICardProps) {
|
|
33
|
+
// Method badge colors
|
|
34
|
+
const methodColors: Record<string, string> = {
|
|
35
|
+
GET: 'border-green-600 bg-green-50 text-green-700 dark:bg-green-900/30 dark:text-green-400',
|
|
36
|
+
POST: 'border-blue-600 bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400',
|
|
37
|
+
PUT: 'border-yellow-600 bg-yellow-50 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400',
|
|
38
|
+
PATCH: 'border-orange-600 bg-orange-50 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400',
|
|
39
|
+
DELETE: 'border-red-600 bg-red-50 text-red-700 dark:bg-red-900/30 dark:text-red-400',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Status colors
|
|
43
|
+
const statusColors: Record<string, string> = {
|
|
44
|
+
complete: 'bg-green-500',
|
|
45
|
+
'in-progress': 'bg-yellow-500',
|
|
46
|
+
error: 'bg-red-500',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const methods = data.methods || ['POST'];
|
|
50
|
+
const status = data.status || 'complete';
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<button
|
|
54
|
+
onClick={onClick}
|
|
55
|
+
className="group relative flex flex-col overflow-hidden border-2 border-black bg-white text-left transition-all hover:shadow-[4px_4px_0_#BA0C2F] focus:outline-none focus:ring-2 focus:ring-[#BA0C2F] focus:ring-offset-2 dark:border-gray-700 dark:bg-gray-900"
|
|
56
|
+
>
|
|
57
|
+
{/* Header */}
|
|
58
|
+
<div className="flex items-start justify-between border-b-2 border-black p-4 dark:border-gray-700">
|
|
59
|
+
<div className="flex-1">
|
|
60
|
+
{/* Type Badge */}
|
|
61
|
+
<div className="mb-2 flex items-center gap-2">
|
|
62
|
+
{type === 'combined' ? (
|
|
63
|
+
<span className="border border-purple-600 bg-purple-50 px-2 py-0.5 text-xs font-bold uppercase tracking-wide text-purple-700 dark:bg-purple-900/30 dark:text-purple-400">
|
|
64
|
+
Combined API
|
|
65
|
+
</span>
|
|
66
|
+
) : (
|
|
67
|
+
<span className="border border-black bg-gray-100 px-2 py-0.5 text-xs font-bold uppercase tracking-wide text-black dark:border-gray-600 dark:bg-gray-800 dark:text-white">
|
|
68
|
+
API Endpoint
|
|
69
|
+
</span>
|
|
70
|
+
)}
|
|
71
|
+
{/* Status Dot */}
|
|
72
|
+
<span
|
|
73
|
+
className={`h-2.5 w-2.5 rounded-full ${statusColors[status] || 'bg-gray-400'}`}
|
|
74
|
+
title={status}
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
{/* Name */}
|
|
79
|
+
<h3 className="font-bold text-black group-hover:text-[#BA0C2F] dark:text-white">
|
|
80
|
+
{data.name || id}
|
|
81
|
+
</h3>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
{/* Arrow Icon */}
|
|
85
|
+
<svg
|
|
86
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
87
|
+
width="20"
|
|
88
|
+
height="20"
|
|
89
|
+
viewBox="0 0 24 24"
|
|
90
|
+
fill="none"
|
|
91
|
+
stroke="currentColor"
|
|
92
|
+
strokeWidth="2.5"
|
|
93
|
+
strokeLinecap="round"
|
|
94
|
+
strokeLinejoin="round"
|
|
95
|
+
className="text-gray-400 transition-all group-hover:translate-x-1 group-hover:text-[#BA0C2F]"
|
|
96
|
+
>
|
|
97
|
+
<path d="M5 12h14" />
|
|
98
|
+
<path d="m12 5 7 7-7 7" />
|
|
99
|
+
</svg>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
{/* Body */}
|
|
103
|
+
<div className="flex flex-1 flex-col p-4">
|
|
104
|
+
{/* Description */}
|
|
105
|
+
<p className="mb-3 line-clamp-2 text-sm text-gray-600 dark:text-gray-400">
|
|
106
|
+
{data.description || `API endpoint for ${id}`}
|
|
107
|
+
</p>
|
|
108
|
+
|
|
109
|
+
{/* Route */}
|
|
110
|
+
<div className="mb-3 border border-gray-300 bg-gray-50 px-2 py-1 dark:border-gray-600 dark:bg-gray-800">
|
|
111
|
+
<code className="font-mono text-xs text-gray-700 dark:text-gray-300">
|
|
112
|
+
/api/v2/{id}
|
|
113
|
+
</code>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
{/* Methods */}
|
|
117
|
+
<div className="mt-auto flex flex-wrap gap-1">
|
|
118
|
+
{methods.map((method) => (
|
|
119
|
+
<span
|
|
120
|
+
key={method}
|
|
121
|
+
className={`border px-2 py-0.5 font-mono text-xs font-bold ${
|
|
122
|
+
methodColors[method] || 'border-gray-400 bg-gray-100 text-gray-700'
|
|
123
|
+
}`}
|
|
124
|
+
>
|
|
125
|
+
{method}
|
|
126
|
+
</span>
|
|
127
|
+
))}
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
{/* Combined Info */}
|
|
131
|
+
{type === 'combined' && data.combines && (
|
|
132
|
+
<div className="mt-3 border-t border-gray-200 pt-3 dark:border-gray-700">
|
|
133
|
+
<p className="text-xs text-gray-500 dark:text-gray-400">
|
|
134
|
+
<span className="font-semibold">Combines:</span> {data.combines.join(', ')}
|
|
135
|
+
</p>
|
|
136
|
+
{data.flow_type && (
|
|
137
|
+
<p className="text-xs text-gray-500 dark:text-gray-400">
|
|
138
|
+
<span className="font-semibold">Flow:</span> {data.flow_type}
|
|
139
|
+
</p>
|
|
140
|
+
)}
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
{/* Footer */}
|
|
146
|
+
<div className="border-t border-gray-200 bg-gray-50 px-4 py-2 dark:border-gray-700 dark:bg-gray-800">
|
|
147
|
+
<p className="text-xs text-gray-500 dark:text-gray-400">
|
|
148
|
+
{data.created_at ? `Created ${data.created_at}` : 'Click to test'}
|
|
149
|
+
</p>
|
|
150
|
+
</div>
|
|
151
|
+
</button>
|
|
152
|
+
);
|
|
153
|
+
}
|