@@ -47,6 +47,8 @@ export default function ApiEndpoint({
47
47
Object . keys ( responses ) [ 0 ] || "200"
48
48
) ;
49
49
const [ copied , setCopied ] = useState ( false ) ;
50
+ const [ paramsCollapsed , setParamsCollapsed ] = useState ( true ) ;
51
+ const [ responsesCollapsed , setResponsesCollapsed ] = useState ( true ) ;
50
52
51
53
const currentBaseUrl = normalizedBaseUrls [ selectedBaseUrl ] ?. url || '' ;
52
54
const fullUrl = `${ currentBaseUrl } ${ endpoint } ` ;
@@ -110,48 +112,116 @@ export default function ApiEndpoint({
110
112
111
113
{ params . length > 0 && (
112
114
< div className = { styles . section } >
113
- < h4 className = { styles . sectionTitle } > 參數</ h4 >
114
- < div className = { styles . paramsList } >
115
- { params . map ( ( param ) => (
116
- < div key = { param . name } className = { styles . param } >
117
- < div className = { styles . paramHeader } >
118
- < code className = { styles . paramName } > { param . name } </ code >
119
- { param . type && < span className = { styles . paramType } > { param . type } </ span > }
120
- { param . optional && < span className = { styles . optional } > optional</ span > }
115
+ < div className = { styles . collapsibleHeader } onClick = { ( ) => setParamsCollapsed ( ! paramsCollapsed ) } >
116
+ < div className = { styles . titleContainer } >
117
+ < h4 className = { styles . sectionTitle } > 參數</ h4 >
118
+ { paramsCollapsed && (
119
+ < div className = { styles . previewTags } >
120
+ { params . slice ( 0 , 3 ) . map ( ( param , index ) => (
121
+ < span key = { index } className = { `${ styles . previewTag } ${ param . optional ? styles . optional : styles . required } ` } >
122
+ { param . name }
123
+ </ span >
124
+ ) ) }
125
+ { params . length > 3 && (
126
+ < span className = { styles . moreCount } > +{ params . length - 3 } </ span >
127
+ ) }
121
128
</ div >
122
- < div className = { styles . paramDescription } >
123
- { param . description }
124
- { param . default && < span className = { styles . default } > (預設: { param . default } )</ span > }
125
- </ div >
126
- </ div >
127
- ) ) }
129
+ ) }
130
+ </ div >
131
+ < button className = { styles . collapseButton } >
132
+ < svg
133
+ width = "16"
134
+ height = "16"
135
+ viewBox = "0 0 16 16"
136
+ fill = "currentColor"
137
+ style = { { transform : paramsCollapsed ? 'rotate(0deg)' : 'rotate(90deg)' } }
138
+ >
139
+ < path d = "M6 4l4 4-4 4V4z" />
140
+ </ svg >
141
+ </ button >
128
142
</ div >
143
+ { ! paramsCollapsed && (
144
+ < div className = { styles . paramsList } >
145
+ { params . map ( ( param ) => (
146
+ < div key = { param . name } className = { styles . param } >
147
+ < div className = { styles . paramHeader } >
148
+ < code className = { styles . paramName } > { param . name } </ code >
149
+ { param . type && < span className = { styles . paramType } > { param . type } </ span > }
150
+ { param . optional && < span className = { styles . optional } > optional</ span > }
151
+ </ div >
152
+ < div className = { styles . paramDescription } >
153
+ { param . description }
154
+ { param . default && < span className = { styles . default } > (預設: { param . default } )</ span > }
155
+ </ div >
156
+ </ div >
157
+ ) ) }
158
+ </ div >
159
+ ) }
129
160
</ div >
130
161
) }
131
162
132
163
{ Object . keys ( responses ) . length > 0 && (
133
164
< div className = { styles . section } >
134
- < div className = { styles . responseHeader } >
135
- < h4 className = { styles . sectionTitle } > 回傳</ h4 >
136
- < select
137
- className = { `${ styles . statusSelect } ${ getStatusColor ( selectedStatus ) } ` }
138
- value = { selectedStatus }
139
- onChange = { ( e ) => setSelectedStatus ( e . target . value ) }
140
- >
141
- { Object . keys ( responses ) . map ( ( status ) => (
142
- < option key = { status } value = { status } >
143
- { status } { responses [ status ] . description && `- ${ responses [ status ] . description } ` }
144
- </ option >
145
- ) ) }
146
- </ select >
165
+ < div className = { styles . collapsibleHeader } onClick = { ( ) => setResponsesCollapsed ( ! responsesCollapsed ) } >
166
+ < div className = { styles . titleContainer } >
167
+ < h4 className = { styles . sectionTitle } > 回傳</ h4 >
168
+ { responsesCollapsed && (
169
+ < div className = { styles . previewTags } >
170
+ { Object . keys ( responses ) . slice ( 0 , 4 ) . map ( ( status ) => {
171
+ const code = parseInt ( status ) ;
172
+ let statusType = 'default' ;
173
+ if ( code >= 200 && code < 300 ) statusType = 'success' ;
174
+ else if ( code >= 400 && code < 500 ) statusType = 'error' ;
175
+ else if ( code >= 500 ) statusType = 'serverError' ;
176
+
177
+ return (
178
+ < span key = { status } className = { `${ styles . previewTag } ${ styles [ statusType ] } ` } >
179
+ { status }
180
+ </ span >
181
+ ) ;
182
+ } ) }
183
+ { Object . keys ( responses ) . length > 4 && (
184
+ < span className = { styles . moreCount } > +{ Object . keys ( responses ) . length - 4 } </ span >
185
+ ) }
186
+ </ div >
187
+ ) }
188
+ </ div >
189
+ < button className = { styles . collapseButton } >
190
+ < svg
191
+ width = "16"
192
+ height = "16"
193
+ viewBox = "0 0 16 16"
194
+ fill = "currentColor"
195
+ style = { { transform : responsesCollapsed ? 'rotate(0deg)' : 'rotate(90deg)' } }
196
+ >
197
+ < path d = "M6 4l4 4-4 4V4z" />
198
+ </ svg >
199
+ </ button >
147
200
</ div >
148
- < pre className = { styles . codeBlock } >
149
- < code
150
- dangerouslySetInnerHTML = { {
151
- __html : highlightJSON ( JSON . stringify ( responses [ selectedStatus ] ?. data , null , 2 ) )
152
- } }
153
- />
154
- </ pre >
201
+ { ! responsesCollapsed && (
202
+ < >
203
+ < div className = { styles . responseHeader } >
204
+ < select
205
+ className = { `${ styles . statusSelect } ${ getStatusColor ( selectedStatus ) } ` }
206
+ value = { selectedStatus }
207
+ onChange = { ( e ) => setSelectedStatus ( e . target . value ) }
208
+ >
209
+ { Object . keys ( responses ) . map ( ( status ) => (
210
+ < option key = { status } value = { status } >
211
+ { status } { responses [ status ] . description && `- ${ responses [ status ] . description } ` }
212
+ </ option >
213
+ ) ) }
214
+ </ select >
215
+ </ div >
216
+ < pre className = { styles . codeBlock } >
217
+ < code
218
+ dangerouslySetInnerHTML = { {
219
+ __html : highlightJSON ( JSON . stringify ( responses [ selectedStatus ] ?. data , null , 2 ) )
220
+ } }
221
+ />
222
+ </ pre >
223
+ </ >
224
+ ) }
155
225
</ div >
156
226
) }
157
227
</ div >
0 commit comments