Skip to content

Commit 94f4aa4

Browse files
committed
feat: enhance layout and text wrapping in HomePage component
- Introduced a new utility class `wrap-anywhere` in CSS to allow text wrapping anywhere within elements. - Adjusted padding and margin in the HomePage layout for better spacing and responsiveness. - Updated headline font size for improved readability. - Refactored button display logic for sample IDs to enhance user experience on smaller screens. - Ensured error messages utilize the new text wrapping utility for better presentation.
1 parent 9776b80 commit 94f4aa4

2 files changed

Lines changed: 59 additions & 32 deletions

File tree

sample/app/globals.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ html, body {
4949
text-wrap: balance;
5050
}
5151

52+
@utility wrap-anywhere {
53+
overflow-wrap: anywhere;
54+
}
55+
5256
/* Highlighter-pen effect: wraps only the text per line, with the color capped
5357
to the visible ascender height instead of the heading's larger line box. */
5458
.highlight {

sample/app/page.tsx

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,14 @@ export default function HomePage() {
203203

204204
return (
205205
<main className='min-h-screen flex flex-col'>
206-
<div className='mx-auto w-full max-w-2xl px-6 sm:px-8 pt-16 sm:pt-24 pb-16 flex-1'>
206+
<div className='mx-auto w-full max-w-2xl px-5 sm:px-8 pt-14 sm:pt-24 pb-16 flex-1'>
207207
{/* Eyebrow */}
208208
<div className='font-mono text-[10px] uppercase tracking-[0.22em] text-stone-500'>
209209
youtube-caption-extractor
210210
</div>
211211

212212
{/* Headline */}
213-
<h1 className='mt-3 font-serif text-[44px] sm:text-[56px] leading-[1.15] tracking-[-0.02em] text-stone-900'>
213+
<h1 className='mt-3 font-serif text-[40px] sm:text-[56px] leading-[1.15] tracking-[-0.02em] text-stone-900'>
214214
<span className='highlight'>Get clean transcript</span>
215215
<br />
216216
<span className='highlight italic font-light'>
@@ -297,23 +297,28 @@ export default function HomePage() {
297297
</label>
298298

299299
{!hasResults && !isFetching && (
300-
<div className='inline-flex items-baseline gap-3'>
301-
<span>or try</span>
302-
{SAMPLE_IDS.map((id, idx) => (
303-
<span key={id} className='inline-flex items-baseline gap-3'>
304-
<button
305-
type='button'
300+
<>
301+
<div className='flex min-w-0 flex-wrap items-baseline gap-x-3 gap-y-2 sm:hidden'>
302+
<span className='shrink-0'>or try</span>
303+
{SAMPLE_IDS.slice(0, 2).map((id) => (
304+
<SampleIdButton
305+
key={id}
306+
id={id}
306307
onClick={() => fetchData(id)}
307-
className='font-mono text-stone-700 hover:text-stone-900 underline decoration-stone-300 hover:decoration-stone-900 decoration-1 underline-offset-[3px] transition-colors'
308-
>
309-
{id}
310-
</button>
311-
{idx < SAMPLE_IDS.length - 1 && (
312-
<span className='text-stone-300'>·</span>
313-
)}
314-
</span>
315-
))}
316-
</div>
308+
/>
309+
))}
310+
</div>
311+
<div className='hidden min-w-0 flex-wrap items-baseline justify-end gap-x-3 gap-y-2 sm:flex'>
312+
<span className='shrink-0'>or try</span>
313+
{SAMPLE_IDS.map((id) => (
314+
<SampleIdButton
315+
key={id}
316+
id={id}
317+
onClick={() => fetchData(id)}
318+
/>
319+
))}
320+
</div>
321+
</>
317322
)}
318323
</div>
319324
</form>
@@ -325,7 +330,7 @@ export default function HomePage() {
325330
<div className='font-mono text-[10px] uppercase tracking-[0.22em] text-amber-700 mb-2'>
326331
Live demo limitation
327332
</div>
328-
<p className='text-sm text-stone-700 leading-relaxed'>
333+
<p className='text-sm text-stone-700 leading-relaxed wrap-anywhere'>
329334
{error.message}
330335
</p>
331336
<div className='mt-3 flex flex-wrap gap-x-5 gap-y-1 text-xs'>
@@ -348,7 +353,7 @@ export default function HomePage() {
348353
</div>
349354
</aside>
350355
) : (
351-
<p className='mt-6 text-sm text-stone-600 border-l-2 border-stone-300 pl-3'>
356+
<p className='mt-6 text-sm text-stone-600 border-l-2 border-stone-300 pl-3 wrap-anywhere'>
352357
{error.message}
353358
</p>
354359
))}
@@ -382,12 +387,12 @@ export default function HomePage() {
382387
{hasResults && (
383388
<article className='mt-16'>
384389
{/* Video header */}
385-
<header className='flex gap-5 mb-10'>
390+
<header className='flex flex-col gap-4 sm:flex-row sm:gap-5 mb-10'>
386391
<a
387392
href={`https://youtu.be/${videoId}`}
388393
target='_blank'
389394
rel='noopener noreferrer'
390-
className='shrink-0 group block w-32 aspect-video rounded overflow-hidden bg-stone-100 border border-stone-200'
395+
className='group block w-full aspect-video rounded overflow-hidden bg-stone-100 border border-stone-200 sm:w-32 sm:shrink-0'
391396
>
392397
<img
393398
src={`https://img.youtube.com/vi/${videoId}/hqdefault.jpg`}
@@ -396,16 +401,16 @@ export default function HomePage() {
396401
/>
397402
</a>
398403
<div className='flex-1 min-w-0'>
399-
<h2 className='font-serif text-2xl leading-[1.15] tracking-[-0.01em] text-stone-900 text-balance'>
404+
<h2 className='font-serif text-2xl leading-[1.15] tracking-[-0.01em] text-stone-900 text-balance wrap-anywhere'>
400405
{videoDetails.title || `youtu.be/${videoId}`}
401406
</h2>
402407
<a
403408
href={`https://youtu.be/${videoId}`}
404409
target='_blank'
405410
rel='noopener noreferrer'
406-
className='mt-2 inline-flex items-center gap-1 text-xs font-mono text-stone-500 hover:text-stone-900 transition-colors'
411+
className='mt-2 inline-flex max-w-full items-center gap-1 text-xs font-mono text-stone-500 hover:text-stone-900 transition-colors'
407412
>
408-
<span>youtu.be/{videoId}</span>
413+
<span className='min-w-0 truncate'>youtu.be/{videoId}</span>
409414
<span aria-hidden='true'></span>
410415
</a>
411416
</div>
@@ -414,7 +419,7 @@ export default function HomePage() {
414419
<hr className='border-stone-200' />
415420

416421
{/* Stats */}
417-
<dl className='mt-6 flex items-baseline gap-8 text-sm'>
422+
<dl className='mt-6 grid grid-cols-2 gap-x-8 gap-y-5 text-sm sm:flex sm:items-baseline sm:gap-8'>
418423
<Stat label='segments' value={subtitles.length.toString()} />
419424
<Stat label='length' value={formatTime(totalDuration)} />
420425
<Stat label='words' value={wordCount.toLocaleString()} />
@@ -430,15 +435,15 @@ export default function HomePage() {
430435
431436
</span>
432437
</summary>
433-
<p className='mt-3 text-sm text-stone-600 whitespace-pre-wrap leading-relaxed max-h-60 overflow-y-auto scrollbar-paper pr-2'>
438+
<p className='mt-3 text-sm text-stone-600 whitespace-pre-wrap leading-relaxed max-h-60 overflow-y-auto scrollbar-paper pr-2 wrap-anywhere'>
434439
{videoDetails.description}
435440
</p>
436441
</details>
437442
)}
438443

439444
{/* Transcript section */}
440445
<section className='mt-14'>
441-
<div className='flex items-baseline justify-between gap-4 mb-5'>
446+
<div className='flex flex-wrap items-baseline justify-between gap-4 mb-5'>
442447
<h3 className='font-serif text-2xl tracking-[-0.01em] text-stone-900'>
443448
Transcript
444449
</h3>
@@ -501,19 +506,19 @@ export default function HomePage() {
501506
{/* Segments */}
502507
<ol className='space-y-2'>
503508
{filteredSubs.map((sub, i) => (
504-
<li key={`${sub.start}-${i}`} className='flex gap-5 group'>
509+
<li key={`${sub.start}-${i}`} className='flex gap-4 sm:gap-5 group'>
505510
<a
506511
href={`https://youtu.be/${videoId}?t=${Math.floor(
507512
Number(sub.start),
508513
)}s`}
509514
target='_blank'
510515
rel='noopener noreferrer'
511-
className='shrink-0 w-12 pt-[3px] font-mono text-[11px] tabular-nums text-stone-400 hover:text-stone-900 transition-colors text-right'
516+
className='shrink-0 w-10 sm:w-12 pt-[3px] font-mono text-[11px] tabular-nums text-stone-400 hover:text-stone-900 transition-colors text-right'
512517
title='Open at this moment'
513518
>
514519
{formatTime(sub.start)}
515520
</a>
516-
<p className='flex-1 text-[15px] leading-[1.7] text-stone-800'>
521+
<p className='min-w-0 flex-1 text-[15px] leading-[1.7] text-stone-800 wrap-anywhere'>
517522
{query.trim() ? highlight(sub.text, query) : sub.text}
518523
</p>
519524
</li>
@@ -526,7 +531,7 @@ export default function HomePage() {
526531

527532
{/* Footer pinned to the bottom of the viewport on short content, naturally follows on long content */}
528533
<footer className='border-t border-stone-200'>
529-
<div className='mx-auto w-full max-w-2xl px-6 sm:px-8 py-6 text-xs text-stone-500 flex flex-wrap items-baseline gap-x-6 gap-y-2'>
534+
<div className='mx-auto w-full max-w-2xl px-5 sm:px-8 py-6 text-xs text-stone-500 flex flex-wrap items-baseline gap-x-6 gap-y-2'>
530535
<a
531536
href='https://www.npmjs.com/package/youtube-caption-extractor'
532537
target='_blank'
@@ -565,6 +570,24 @@ function Spinner() {
565570
);
566571
}
567572

573+
function SampleIdButton({
574+
id,
575+
onClick,
576+
}: {
577+
id: string;
578+
onClick: () => void;
579+
}) {
580+
return (
581+
<button
582+
type='button'
583+
onClick={onClick}
584+
className='font-mono text-stone-700 hover:text-stone-900 underline decoration-stone-300 hover:decoration-stone-900 decoration-1 underline-offset-[3px] transition-colors'
585+
>
586+
{id}
587+
</button>
588+
);
589+
}
590+
568591
function Stat({ label, value }: { label: string; value: string }) {
569592
return (
570593
<div className='flex flex-col'>

0 commit comments

Comments
 (0)