alpha
Login
or
Join now
jeremy.herve.bzh
/
standard.site
forked from
standard.site/standard.site
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Standard.site landing page built in Next.js
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
Inline code styling
author
Brooke
date
5 months ago
(Jan 8, 2026, 1:09 AM -0800)
commit
b180817a
b180817a7176ef7ace0ca35cecfdb68376bace0f
parent
ac9e7b71
ac9e7b717aad1117b9fae2cc4f93e6d41a22d89a
+107
-75
1 changed file
Expand all
Collapse all
Unified
Split
app
components
ExpandableField.tsx
+107
-75
app/components/ExpandableField.tsx
Reviewed
···
85
85
return entries.map(([name, prop]) => {
86
86
const constraints: string[] = []
87
87
88
88
-
if (prop.maxLength) constraints.push(`maxLength: ${ prop.maxLength }`)
89
89
-
if (prop.maxGraphemes) constraints.push(`maxGraphemes: ${ prop.maxGraphemes }`)
88
88
+
if (prop.maxLength) constraints.push(`maxLength: ${prop.maxLength}`)
89
89
+
if (prop.maxGraphemes) constraints.push(`maxGraphemes: ${prop.maxGraphemes}`)
90
90
if (prop.maxSize) {
91
91
const bytes = prop.maxSize
92
92
-
const formatted = bytes >= 1_000_000 ? `${ bytes / 1_000_000 }MB` : bytes >= 1_000 ? `${ bytes / 1_000 }KB` : `${ bytes }B`
93
93
-
constraints.push(`maxSize: ${ formatted }`)
92
92
+
const formatted = bytes >= 1_000_000 ? `${bytes / 1_000_000}MB` : bytes >= 1_000 ? `${bytes / 1_000}KB` : `${bytes}B`
93
93
+
constraints.push(`maxSize: ${formatted}`)
94
94
}
95
95
-
if (prop.accept) constraints.push(`accept: [${ prop.accept.join(', ') }]`)
95
95
+
if (prop.accept) constraints.push(`accept: [${prop.accept.join(', ')}]`)
96
96
97
97
if (prop.items) {
98
98
-
if (prop.items.maxLength) constraints.push(`items.maxLength: ${ prop.items.maxLength }`)
99
99
-
if (prop.items.maxGraphemes) constraints.push(`items.maxGraphemes: ${ prop.items.maxGraphemes }`)
98
98
+
if (prop.items.maxLength) constraints.push(`items.maxLength: ${prop.items.maxLength}`)
99
99
+
if (prop.items.maxGraphemes) constraints.push(`items.maxGraphemes: ${prop.items.maxGraphemes}`)
100
100
}
101
101
102
102
let type = prop.type
103
103
-
if (prop.format) type = `${ prop.type }:${ prop.format }`
103
103
+
if (prop.format) type = `${prop.type}:${prop.format}`
104
104
if (prop.ref) type = prop.ref
105
105
if (prop.type === 'array' && prop.items) {
106
106
-
type = `array<${ prop.items.type }>`
106
106
+
type = `array<${prop.items.type}>`
107
107
}
108
108
109
109
const refs = (prop as { refs?: string[] }).refs
···
142
142
let type = def.type
143
143
144
144
if (def.type === 'array' && def.items) {
145
145
-
type = `array<${ def.items.type }>`
146
146
-
if (def.items.maxLength) constraints.push(`items.maxLength: ${ def.items.maxLength }`)
147
147
-
if (def.items.maxGraphemes) constraints.push(`items.maxGraphemes: ${ def.items.maxGraphemes }`)
145
145
+
type = `array<${def.items.type}>`
146
146
+
if (def.items.maxLength) constraints.push(`items.maxLength: ${def.items.maxLength}`)
147
147
+
if (def.items.maxGraphemes) constraints.push(`items.maxGraphemes: ${def.items.maxGraphemes}`)
148
148
}
149
149
150
150
if ((def as ExtendedLexiconDef).minimum !== undefined) {
151
151
-
constraints.push(`minimum: ${ (def as ExtendedLexiconDef).minimum }`)
151
151
+
constraints.push(`minimum: ${(def as ExtendedLexiconDef).minimum}`)
152
152
}
153
153
if ((def as ExtendedLexiconDef).maximum !== undefined) {
154
154
-
constraints.push(`maximum: ${ (def as ExtendedLexiconDef).maximum }`)
154
154
+
constraints.push(`maximum: ${(def as ExtendedLexiconDef).maximum}`)
155
155
}
156
156
157
157
return {
···
162
162
}
163
163
}
164
164
165
165
+
// Helper to parse description with inline code (backticks)
166
166
+
function parseInlineCode(text: string): React.ReactNode {
167
167
+
const parts: React.ReactNode[] = []
168
168
+
let lastIndex = 0
169
169
+
const regex = /`([^`]+)`/g
170
170
+
let match
171
171
+
172
172
+
while ((match = regex.exec(text)) !== null) {
173
173
+
// Add text before the match
174
174
+
if (match.index > lastIndex) {
175
175
+
parts.push(text.slice(lastIndex, match.index))
176
176
+
}
177
177
+
// Add the code part with styling
178
178
+
parts.push(
179
179
+
<code
180
180
+
key={match.index}
181
181
+
className="rounded bg-base-200 px-1 mx-0.5 font-mono text-sm text-base-content italic"
182
182
+
>
183
183
+
{match[1]}
184
184
+
</code>
185
185
+
)
186
186
+
lastIndex = match.index + match[0].length
187
187
+
}
188
188
+
189
189
+
// Add remaining text
190
190
+
if (lastIndex < text.length) {
191
191
+
parts.push(text.slice(lastIndex))
192
192
+
}
193
193
+
194
194
+
return parts.length > 0 ? parts : text
195
195
+
}
196
196
+
165
197
function TypeBadge({ name, type, required }: { name: string; type: string; required?: boolean }) {
166
198
return (
167
199
<div className="flex flex-wrap items-center gap-2">
168
200
<span className="font-mono font-semibold text-base leading-snug tracking-tight text-base-content">
169
169
-
{ name }
201
201
+
{name}
170
202
</span>
171
203
<span className="rounded border border-sky-200 bg-sky-100 text-sky-800 dark:border-sky-900 dark:bg-sky-950 dark:text-sky-100 px-1 py-0.5 font-mono font-medium text-sm leading-none tracking-tight">
172
172
-
{ type }
204
204
+
{type}
173
205
</span>
174
174
-
{ required && (
206
206
+
{required && (
175
207
<span className="rounded border border-red-200 bg-red-100 text-red-800 dark:border-red-900 dark:bg-red-950 dark:text-red-100 px-1 py-0.5 font-mono font-medium text-sm leading-none tracking-tight">
176
208
required
177
209
</span>
178
178
-
) }
210
210
+
)}
179
211
</div>
180
212
)
181
213
}
···
183
215
function RefBadge({ ref }: { ref: string }) {
184
216
return (
185
217
<span className="rounded border border-emerald-200 bg-emerald-100 text-emerald-800 dark:border-emerald-900 dark:bg-emerald-950 dark:text-emerald-100 px-1 py-0.5 font-mono font-medium text-sm leading-none tracking-tight">
186
186
-
{ ref }
187
187
-
</span>
218
218
+
{ref}
219
219
+
</span>
188
220
)
189
221
}
190
222
···
200
232
return (
201
233
<div className="flex flex-col gap-1 p-4">
202
234
<div className="flex flex-wrap items-center gap-2">
203
203
-
<span className="rounded border border-sky-200 bg-sky-100 text-sky-800 dark:border-sky-900 dark:bg-sky-950 dark:text-sky-100 px-1 py-0.5 font-mono font-medium text-sm leading-none tracking-tight">
204
204
-
{ summary.type }
205
205
-
</span>
235
235
+
<span className="rounded border border-sky-200 bg-sky-100 text-sky-800 dark:border-sky-900 dark:bg-sky-950 dark:text-sky-100 px-1 py-0.5 font-mono font-medium text-sm leading-none tracking-tight">
236
236
+
{summary.type}
237
237
+
</span>
206
238
</div>
207
239
208
208
-
{/* Union refs as badges */ }
209
209
-
{ summary.refs && summary.refs.length > 0 && (
240
240
+
{/* Union refs as badges */}
241
241
+
{summary.refs && summary.refs.length > 0 && (
210
242
<div className="flex flex-wrap gap-2">
211
211
-
{ summary.refs.map((ref) => (
212
212
-
<RefBadge key={ ref } ref={ ref } />
213
213
-
)) }
243
243
+
{summary.refs.map((ref) => (
244
244
+
<RefBadge key={ref} ref={ref} />
245
245
+
))}
214
246
</div>
215
215
-
) }
247
247
+
)}
216
248
217
217
-
{ summary.constraints.length > 0 && (
249
249
+
{summary.constraints.length > 0 && (
218
250
<div className="flex flex-wrap gap-4 font-mono text-sm leading-none tracking-tight text-muted">
219
219
-
{ summary.constraints.map((constraint) => (
220
220
-
<span key={ constraint }>{ constraint }</span>
221
221
-
)) }
251
251
+
{summary.constraints.map((constraint) => (
252
252
+
<span key={constraint}>{constraint}</span>
253
253
+
))}
222
254
</div>
223
223
-
) }
255
255
+
)}
224
256
225
225
-
{ summary.description && (
257
257
+
{summary.description && (
226
258
<p className="text-sm italic leading-snug tracking-tight text-muted">
227
227
-
{ summary.description }
259
259
+
{parseInlineCode(summary.description)}
228
260
</p>
229
229
-
) }
261
261
+
)}
230
262
</div>
231
263
)
232
264
}
···
253
285
const isExpandable = !!field.ref && !NON_EXPANDABLE_REFS.includes(field.ref)
254
286
255
287
const toggleExpand = () => {
256
256
-
setExpanded( !expanded)
288
288
+
setExpanded(!expanded)
257
289
}
258
290
259
291
const resolvedDef = field.ref ? resolveRef(field.ref, schema) : null
···
268
300
269
301
return (
270
302
<div className="flex flex-col gap-1 border-b border-border p-4 last:border-b-0">
271
271
-
<TypeBadge name={ field.name } type={ field.type } required={ field.required } />
303
303
+
<TypeBadge name={field.name} type={field.type} required={field.required} />
272
304
273
273
-
{/* Union refs as badges */ }
274
274
-
{ field.refs && field.refs.length > 0 && (
305
305
+
{/* Union refs as badges */}
306
306
+
{field.refs && field.refs.length > 0 && (
275
307
<div className="flex flex-wrap gap-2">
276
276
-
{ field.refs.map((ref) => (
277
277
-
<RefBadge key={ ref } ref={ ref } />
278
278
-
)) }
308
308
+
{field.refs.map((ref) => (
309
309
+
<RefBadge key={ref} ref={ref} />
310
310
+
))}
279
311
</div>
280
280
-
) }
312
312
+
)}
281
313
282
282
-
{ field.constraints.length > 0 && (
314
314
+
{field.constraints.length > 0 && (
283
315
<div className="flex flex-wrap gap-4 font-mono text-sm leading-none tracking-tight text-muted">
284
284
-
{ field.constraints.map((constraint) => (
285
285
-
<span key={ constraint }>{ constraint }</span>
286
286
-
)) }
316
316
+
{field.constraints.map((constraint) => (
317
317
+
<span key={constraint}>{constraint}</span>
318
318
+
))}
287
319
</div>
288
288
-
) }
320
320
+
)}
289
321
290
290
-
{ field.description && (
322
322
+
{field.description && (
291
323
<p className="text-sm italic leading-snug tracking-tight text-muted">
292
292
-
{ field.description }
324
324
+
{parseInlineCode(field.description)}
293
325
</p>
294
294
-
) }
326
326
+
)}
295
327
296
296
-
{ isExpandable && (
328
328
+
{isExpandable && (
297
329
<div className="pt-2">
298
330
<div className="flex flex-col rounded-xl border border-border bg-base-200 overflow-hidden">
299
299
-
{/* Header button */ }
331
331
+
{/* Header button */}
300
332
<button
301
301
-
onClick={ toggleExpand }
302
302
-
className={ `flex items-center gap-2 px-4 py-2.5 hover:bg-base-300 transition-colors hover:cursor-pointer ${ expanded ? 'border-b border-border' : '' }` }
333
333
+
onClick={toggleExpand}
334
334
+
className={`flex items-center gap-2 px-4 py-2.5 hover:bg-base-300 transition-colors hover:cursor-pointer ${expanded ? 'border-b border-border' : ''}`}
303
335
>
304
336
<FileIcon className="size-4 text-base-content" />
305
337
<span className="font-medium text-base leading-snug tracking-tight text-base-content">
306
306
-
{ refDisplayName }
338
338
+
{refDisplayName}
307
339
</span>
308
340
<motion.div
309
341
className="ml-auto"
310
310
-
initial={ false }
342
342
+
initial={false}
311
343
animate={{ opacity: 1 }}
312
344
>
313
313
-
{ expanded ? (
345
345
+
{expanded ? (
314
346
<EyeOffIcon className="size-4 text-muted" />
315
347
) : (
316
348
<EyeIcon className="size-4 text-muted" />
317
317
-
) }
349
349
+
)}
318
350
</motion.div>
319
351
</button>
320
352
321
321
-
{/* Expandable content */ }
322
322
-
<AnimatePresence initial={ false }>
323
323
-
{ expanded && (
353
353
+
{/* Expandable content */}
354
354
+
<AnimatePresence initial={false}>
355
355
+
{expanded && (
324
356
<motion.div
325
357
initial={{ height: 0, opacity: 0 }}
326
358
animate={{ height: 'auto', opacity: 1 }}
···
330
362
>
331
363
<div className="p-1">
332
364
<div className="flex flex-col rounded-xl border border-border bg-card overflow-hidden">
333
333
-
{ hasNestedFields ? (
365
365
+
{hasNestedFields ? (
334
366
nestedFields.map((nestedField) => (
335
367
<ExpandableField
336
336
-
key={ nestedField.name }
337
337
-
field={ nestedField }
338
338
-
schema={ schema }
368
368
+
key={nestedField.name}
369
369
+
field={nestedField}
370
370
+
schema={schema}
339
371
/>
340
372
))
341
373
) : resolvedDef ? (
342
342
-
<DefSummaryDisplay def={ resolvedDef as ExtendedLexiconDef } />
343
343
-
) : null }
374
374
+
<DefSummaryDisplay def={resolvedDef as ExtendedLexiconDef} />
375
375
+
) : null}
344
376
</div>
345
377
</div>
346
378
</motion.div>
347
347
-
) }
379
379
+
)}
348
380
</AnimatePresence>
349
381
</div>
350
382
</div>
351
351
-
) }
383
383
+
)}
352
384
</div>
353
385
)
354
386
}
···
368
400
return (
369
401
<div className="p-1">
370
402
<div className="flex flex-col rounded-xl border border-border bg-card overflow-hidden">
371
371
-
{ fields.map((field) => (
372
372
-
<ExpandableField key={ field.name } field={ field } schema={ schema } />
373
373
-
)) }
403
403
+
{fields.map((field) => (
404
404
+
<ExpandableField key={field.name} field={field} schema={schema} />
405
405
+
))}
374
406
</div>
375
407
</div>
376
408
)