Standard.site landing page built in Next.js

Inline code styling

brookie.blog b180817a ac9e7b71

verified
+107 -75
+107 -75
app/components/ExpandableField.tsx
··· 85 85 return entries.map(([name, prop]) => { 86 86 const constraints: string[] = [] 87 87 88 - if (prop.maxLength) constraints.push(`maxLength: ${ prop.maxLength }`) 89 - if (prop.maxGraphemes) constraints.push(`maxGraphemes: ${ prop.maxGraphemes }`) 88 + if (prop.maxLength) constraints.push(`maxLength: ${prop.maxLength}`) 89 + if (prop.maxGraphemes) constraints.push(`maxGraphemes: ${prop.maxGraphemes}`) 90 90 if (prop.maxSize) { 91 91 const bytes = prop.maxSize 92 - const formatted = bytes >= 1_000_000 ? `${ bytes / 1_000_000 }MB` : bytes >= 1_000 ? `${ bytes / 1_000 }KB` : `${ bytes }B` 93 - constraints.push(`maxSize: ${ formatted }`) 92 + const formatted = bytes >= 1_000_000 ? `${bytes / 1_000_000}MB` : bytes >= 1_000 ? `${bytes / 1_000}KB` : `${bytes}B` 93 + constraints.push(`maxSize: ${formatted}`) 94 94 } 95 - if (prop.accept) constraints.push(`accept: [${ prop.accept.join(', ') }]`) 95 + if (prop.accept) constraints.push(`accept: [${prop.accept.join(', ')}]`) 96 96 97 97 if (prop.items) { 98 - if (prop.items.maxLength) constraints.push(`items.maxLength: ${ prop.items.maxLength }`) 99 - if (prop.items.maxGraphemes) constraints.push(`items.maxGraphemes: ${ prop.items.maxGraphemes }`) 98 + if (prop.items.maxLength) constraints.push(`items.maxLength: ${prop.items.maxLength}`) 99 + if (prop.items.maxGraphemes) constraints.push(`items.maxGraphemes: ${prop.items.maxGraphemes}`) 100 100 } 101 101 102 102 let type = prop.type 103 - if (prop.format) type = `${ prop.type }:${ prop.format }` 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 - type = `array<${ prop.items.type }>` 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 - type = `array<${ def.items.type }>` 146 - if (def.items.maxLength) constraints.push(`items.maxLength: ${ def.items.maxLength }`) 147 - if (def.items.maxGraphemes) constraints.push(`items.maxGraphemes: ${ def.items.maxGraphemes }`) 145 + type = `array<${def.items.type}>` 146 + if (def.items.maxLength) constraints.push(`items.maxLength: ${def.items.maxLength}`) 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 - constraints.push(`minimum: ${ (def as ExtendedLexiconDef).minimum }`) 151 + constraints.push(`minimum: ${(def as ExtendedLexiconDef).minimum}`) 152 152 } 153 153 if ((def as ExtendedLexiconDef).maximum !== undefined) { 154 - constraints.push(`maximum: ${ (def as ExtendedLexiconDef).maximum }`) 154 + constraints.push(`maximum: ${(def as ExtendedLexiconDef).maximum}`) 155 155 } 156 156 157 157 return { ··· 162 162 } 163 163 } 164 164 165 + // Helper to parse description with inline code (backticks) 166 + function parseInlineCode(text: string): React.ReactNode { 167 + const parts: React.ReactNode[] = [] 168 + let lastIndex = 0 169 + const regex = /`([^`]+)`/g 170 + let match 171 + 172 + while ((match = regex.exec(text)) !== null) { 173 + // Add text before the match 174 + if (match.index > lastIndex) { 175 + parts.push(text.slice(lastIndex, match.index)) 176 + } 177 + // Add the code part with styling 178 + parts.push( 179 + <code 180 + key={match.index} 181 + className="rounded bg-base-200 px-1 mx-0.5 font-mono text-sm text-base-content italic" 182 + > 183 + {match[1]} 184 + </code> 185 + ) 186 + lastIndex = match.index + match[0].length 187 + } 188 + 189 + // Add remaining text 190 + if (lastIndex < text.length) { 191 + parts.push(text.slice(lastIndex)) 192 + } 193 + 194 + return parts.length > 0 ? parts : text 195 + } 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 - { name } 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 - { type } 204 + {type} 173 205 </span> 174 - { required && ( 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 - ) } 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 - { ref } 187 - </span> 218 + {ref} 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 - <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 - { summary.type } 205 - </span> 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 + {summary.type} 237 + </span> 206 238 </div> 207 239 208 - {/* Union refs as badges */ } 209 - { summary.refs && summary.refs.length > 0 && ( 240 + {/* Union refs as badges */} 241 + {summary.refs && summary.refs.length > 0 && ( 210 242 <div className="flex flex-wrap gap-2"> 211 - { summary.refs.map((ref) => ( 212 - <RefBadge key={ ref } ref={ ref } /> 213 - )) } 243 + {summary.refs.map((ref) => ( 244 + <RefBadge key={ref} ref={ref} /> 245 + ))} 214 246 </div> 215 - ) } 247 + )} 216 248 217 - { summary.constraints.length > 0 && ( 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 - { summary.constraints.map((constraint) => ( 220 - <span key={ constraint }>{ constraint }</span> 221 - )) } 251 + {summary.constraints.map((constraint) => ( 252 + <span key={constraint}>{constraint}</span> 253 + ))} 222 254 </div> 223 - ) } 255 + )} 224 256 225 - { summary.description && ( 257 + {summary.description && ( 226 258 <p className="text-sm italic leading-snug tracking-tight text-muted"> 227 - { summary.description } 259 + {parseInlineCode(summary.description)} 228 260 </p> 229 - ) } 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 - setExpanded( !expanded) 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 - <TypeBadge name={ field.name } type={ field.type } required={ field.required } /> 303 + <TypeBadge name={field.name} type={field.type} required={field.required} /> 272 304 273 - {/* Union refs as badges */ } 274 - { field.refs && field.refs.length > 0 && ( 305 + {/* Union refs as badges */} 306 + {field.refs && field.refs.length > 0 && ( 275 307 <div className="flex flex-wrap gap-2"> 276 - { field.refs.map((ref) => ( 277 - <RefBadge key={ ref } ref={ ref } /> 278 - )) } 308 + {field.refs.map((ref) => ( 309 + <RefBadge key={ref} ref={ref} /> 310 + ))} 279 311 </div> 280 - ) } 312 + )} 281 313 282 - { field.constraints.length > 0 && ( 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 - { field.constraints.map((constraint) => ( 285 - <span key={ constraint }>{ constraint }</span> 286 - )) } 316 + {field.constraints.map((constraint) => ( 317 + <span key={constraint}>{constraint}</span> 318 + ))} 287 319 </div> 288 - ) } 320 + )} 289 321 290 - { field.description && ( 322 + {field.description && ( 291 323 <p className="text-sm italic leading-snug tracking-tight text-muted"> 292 - { field.description } 324 + {parseInlineCode(field.description)} 293 325 </p> 294 - ) } 326 + )} 295 327 296 - { isExpandable && ( 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 - {/* Header button */ } 331 + {/* Header button */} 300 332 <button 301 - onClick={ toggleExpand } 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 + onClick={toggleExpand} 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 - { refDisplayName } 338 + {refDisplayName} 307 339 </span> 308 340 <motion.div 309 341 className="ml-auto" 310 - initial={ false } 342 + initial={false} 311 343 animate={{ opacity: 1 }} 312 344 > 313 - { expanded ? ( 345 + {expanded ? ( 314 346 <EyeOffIcon className="size-4 text-muted" /> 315 347 ) : ( 316 348 <EyeIcon className="size-4 text-muted" /> 317 - ) } 349 + )} 318 350 </motion.div> 319 351 </button> 320 352 321 - {/* Expandable content */ } 322 - <AnimatePresence initial={ false }> 323 - { expanded && ( 353 + {/* Expandable content */} 354 + <AnimatePresence initial={false}> 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 - { hasNestedFields ? ( 365 + {hasNestedFields ? ( 334 366 nestedFields.map((nestedField) => ( 335 367 <ExpandableField 336 - key={ nestedField.name } 337 - field={ nestedField } 338 - schema={ schema } 368 + key={nestedField.name} 369 + field={nestedField} 370 + schema={schema} 339 371 /> 340 372 )) 341 373 ) : resolvedDef ? ( 342 - <DefSummaryDisplay def={ resolvedDef as ExtendedLexiconDef } /> 343 - ) : null } 374 + <DefSummaryDisplay def={resolvedDef as ExtendedLexiconDef} /> 375 + ) : null} 344 376 </div> 345 377 </div> 346 378 </motion.div> 347 - ) } 379 + )} 348 380 </AnimatePresence> 349 381 </div> 350 382 </div> 351 - ) } 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 - { fields.map((field) => ( 372 - <ExpandableField key={ field.name } field={ field } schema={ schema } /> 373 - )) } 403 + {fields.map((field) => ( 404 + <ExpandableField key={field.name} field={field} schema={schema} /> 405 + ))} 374 406 </div> 375 407 </div> 376 408 )