Aksel Joonas Reedi commited on
Commit
21aa9ca
·
unverified ·
1 Parent(s): 895c557

Make onboarding screen scroll when it overflows the viewport (#165)

Browse files

* Make onboarding screen scroll when it overflows the viewport

The welcome screen used a flex column with justify-content: center and
no overflow handling, so on short viewports (1366×768 Chrome was the
reported case) the bottom of the checklist — including the "Start
session" CTA — got clipped with no way for the user to scroll to it.

Wrap the children in an inner Box and use the margin: auto pattern: the
outer container scrolls, the inner box centers when the viewport has
room and top-aligns when it doesn't.

Reported in smolagents/ml-intern Space discussion #19.

* Reindent welcome screen children under inner Box

frontend/src/components/WelcomeScreen/WelcomeScreen.tsx CHANGED
@@ -280,6 +280,12 @@ export default function WelcomeScreen() {
280
  : '';
281
 
282
  return (
 
 
 
 
 
 
283
  <Box
284
  sx={{
285
  width: '100%',
@@ -287,172 +293,182 @@ export default function WelcomeScreen() {
287
  display: 'flex',
288
  flexDirection: 'column',
289
  alignItems: 'center',
290
- justifyContent: 'center',
291
  background: 'var(--body-gradient)',
292
- py: 8,
293
  }}
294
  >
295
- {/* Logo */}
296
  <Box
297
- component="img"
298
- src="/smolagents.webp"
299
- alt="smolagents"
300
- sx={{ width: 80, height: 80, mb: 2.5, display: 'block' }}
301
- />
302
-
303
- {/* Title */}
304
- <Typography
305
- variant="h2"
306
  sx={{
307
- fontWeight: 800,
308
- color: 'var(--text)',
309
- mb: 1,
310
- letterSpacing: '-0.02em',
311
- fontSize: { xs: '1.8rem', md: '2.4rem' },
 
312
  }}
313
  >
314
- ML Intern
315
- </Typography>
 
 
 
 
 
316
 
317
- {/* Description */}
318
- <Typography
319
- variant="body1"
320
- sx={{
321
- color: 'var(--muted-text)',
322
- maxWidth: 480,
323
- mb: 4,
324
- lineHeight: 1.7,
325
- fontSize: '0.9rem',
326
- textAlign: 'center',
327
- px: 2,
328
- '& strong': { color: 'var(--text)', fontWeight: 600 },
329
- }}
330
- >
331
- Your personal <strong>ML agent</strong>. It reads <strong>papers</strong>, finds <strong>datasets</strong>, trains <strong>models</strong>, and iterates until the numbers go up. Instructions in. Trained model out.
332
- </Typography>
333
 
334
- {/* ── Checklist ──────────────────────────────────────────── */}
335
- <Box
336
- sx={{
337
- width: '100%',
338
- maxWidth: 520,
339
- bgcolor: 'var(--surface)',
340
- border: '1px solid var(--border)',
341
- borderRadius: '12px',
342
- overflow: 'hidden',
343
- mx: 2,
344
- }}
345
- >
346
- {isDevUser ? (
347
- /* Dev mode: single step */
348
- <ChecklistStep
349
- stepNumber={1}
350
- title="Start Session"
351
- description="Launch an AI agent session for ML engineering."
352
- status="active"
353
- actionLabel="Start Session"
354
- actionIcon={<RocketLaunchIcon sx={{ fontSize: 16 }} />}
355
- onAction={handleStartSession}
356
- loading={isCreating}
357
- isLast
358
- />
359
- ) : inIframe ? (
360
- /* Iframe: 2 steps */
361
- <>
362
- <ChecklistStep
363
- stepNumber={1}
364
- title="Join ML Agent Explorers"
365
- description="Get free access to GPUs, inference APIs, and Hub resources."
366
- status={isOrgMember ? 'completed' : 'active'}
367
- actionLabel="Join Organization"
368
- actionIcon={<GroupAddIcon sx={{ fontSize: 16 }} />}
369
- onAction={handleJoinOrg}
370
- />
371
- <ChecklistStep
372
- stepNumber={2}
373
- title="Open ML Intern"
374
- description="Open the agent in a full browser tab to get started."
375
- status={isOrgMember ? 'active' : 'locked'}
376
- lockedReason="Join the organization first."
377
- actionLabel="Open ML Intern"
378
- actionIcon={<OpenInNewIcon sx={{ fontSize: 16 }} />}
379
- actionHref={spaceHost}
380
- isLast
381
- />
382
- </>
383
- ) : (
384
- /* Direct access: 3 steps */
385
- <>
386
  <ChecklistStep
387
  stepNumber={1}
388
- title="Sign in with Hugging Face"
389
- description="Authenticate to access GPU resources and model APIs."
390
- status={signInStatus}
391
- actionLabel="Sign in"
392
- actionIcon={<LoginIcon sx={{ fontSize: 16 }} />}
393
- onAction={() => triggerLogin()}
394
- />
395
- <ChecklistStep
396
- stepNumber={2}
397
- title="Join ML Agent Explorers"
398
- description="Get free access to GPUs, inference APIs, and Hub resources."
399
- status={joinOrgStatus}
400
- lockedReason="Sign in first to continue."
401
- actionLabel="Join Organization"
402
- actionIcon={<GroupAddIcon sx={{ fontSize: 16 }} />}
403
- onAction={handleJoinOrg}
404
- />
405
- <ChecklistStep
406
- stepNumber={3}
407
  title="Start Session"
408
  description="Launch an AI agent session for ML engineering."
409
- status={startStatus}
410
- lockedReason="Complete the steps above to continue."
411
  actionLabel="Start Session"
412
  actionIcon={<RocketLaunchIcon sx={{ fontSize: 16 }} />}
413
  onAction={handleStartSession}
414
  loading={isCreating}
415
  isLast
416
  />
417
- </>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
  )}
419
- </Box>
420
 
421
- {/* Polling hint when waiting for org join */}
422
- {isAuthenticated && !isOrgMember && !isDevUser && !inIframe && (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
  <Typography
424
  variant="caption"
425
- sx={{ mt: 2, color: 'var(--muted-text)', fontSize: '0.75rem', textAlign: 'center' }}
426
  >
427
- This page updates automatically when you join the organization.
428
  </Typography>
429
- )}
430
-
431
- {/* Error */}
432
- {error && (
433
- <Alert
434
- severity="warning"
435
- variant="outlined"
436
- onClose={() => setError(null)}
437
- sx={{
438
- mt: 3,
439
- maxWidth: 400,
440
- fontSize: '0.8rem',
441
- borderColor: HF_ORANGE,
442
- color: 'var(--text)',
443
- }}
444
- >
445
- {error}
446
- </Alert>
447
- )}
448
-
449
- {/* Footnote */}
450
- <Typography
451
- variant="caption"
452
- sx={{ mt: 4, color: 'var(--muted-text)', opacity: 0.5, fontSize: '0.7rem' }}
453
- >
454
- Conversations are stored locally in your browser.
455
- </Typography>
456
  </Box>
457
  );
458
  }
 
280
  : '';
281
 
282
  return (
283
+ // Outer container scrolls; inner uses `margin: auto` so the checklist
284
+ // centers vertically when the viewport has room and falls back to top-
285
+ // aligned + scrollable when it doesn't. The previous setup hardcoded
286
+ // `justify-content: center` with no overflow, so on short viewports
287
+ // (1366×768 Chrome was the reported case) the bottom of the card —
288
+ // including the "Start session" CTA — got clipped with no way to scroll.
289
  <Box
290
  sx={{
291
  width: '100%',
 
293
  display: 'flex',
294
  flexDirection: 'column',
295
  alignItems: 'center',
296
+ overflowY: 'auto',
297
  background: 'var(--body-gradient)',
 
298
  }}
299
  >
 
300
  <Box
 
 
 
 
 
 
 
 
 
301
  sx={{
302
+ display: 'flex',
303
+ flexDirection: 'column',
304
+ alignItems: 'center',
305
+ width: '100%',
306
+ margin: 'auto',
307
+ py: 8,
308
  }}
309
  >
310
+ {/* Logo */}
311
+ <Box
312
+ component="img"
313
+ src="/smolagents.webp"
314
+ alt="smolagents"
315
+ sx={{ width: 80, height: 80, mb: 2.5, display: 'block' }}
316
+ />
317
 
318
+ {/* Title */}
319
+ <Typography
320
+ variant="h2"
321
+ sx={{
322
+ fontWeight: 800,
323
+ color: 'var(--text)',
324
+ mb: 1,
325
+ letterSpacing: '-0.02em',
326
+ fontSize: { xs: '1.8rem', md: '2.4rem' },
327
+ }}
328
+ >
329
+ ML Intern
330
+ </Typography>
 
 
 
331
 
332
+ {/* Description */}
333
+ <Typography
334
+ variant="body1"
335
+ sx={{
336
+ color: 'var(--muted-text)',
337
+ maxWidth: 480,
338
+ mb: 4,
339
+ lineHeight: 1.7,
340
+ fontSize: '0.9rem',
341
+ textAlign: 'center',
342
+ px: 2,
343
+ '& strong': { color: 'var(--text)', fontWeight: 600 },
344
+ }}
345
+ >
346
+ Your personal <strong>ML agent</strong>. It reads <strong>papers</strong>, finds <strong>datasets</strong>, trains <strong>models</strong>, and iterates until the numbers go up. Instructions in. Trained model out.
347
+ </Typography>
348
+
349
+ {/* ── Checklist ──────────────────────────────────────────── */}
350
+ <Box
351
+ sx={{
352
+ width: '100%',
353
+ maxWidth: 520,
354
+ bgcolor: 'var(--surface)',
355
+ border: '1px solid var(--border)',
356
+ borderRadius: '12px',
357
+ overflow: 'hidden',
358
+ mx: 2,
359
+ }}
360
+ >
361
+ {isDevUser ? (
362
+ /* Dev mode: single step */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  <ChecklistStep
364
  stepNumber={1}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  title="Start Session"
366
  description="Launch an AI agent session for ML engineering."
367
+ status="active"
 
368
  actionLabel="Start Session"
369
  actionIcon={<RocketLaunchIcon sx={{ fontSize: 16 }} />}
370
  onAction={handleStartSession}
371
  loading={isCreating}
372
  isLast
373
  />
374
+ ) : inIframe ? (
375
+ /* Iframe: 2 steps */
376
+ <>
377
+ <ChecklistStep
378
+ stepNumber={1}
379
+ title="Join ML Agent Explorers"
380
+ description="Get free access to GPUs, inference APIs, and Hub resources."
381
+ status={isOrgMember ? 'completed' : 'active'}
382
+ actionLabel="Join Organization"
383
+ actionIcon={<GroupAddIcon sx={{ fontSize: 16 }} />}
384
+ onAction={handleJoinOrg}
385
+ />
386
+ <ChecklistStep
387
+ stepNumber={2}
388
+ title="Open ML Intern"
389
+ description="Open the agent in a full browser tab to get started."
390
+ status={isOrgMember ? 'active' : 'locked'}
391
+ lockedReason="Join the organization first."
392
+ actionLabel="Open ML Intern"
393
+ actionIcon={<OpenInNewIcon sx={{ fontSize: 16 }} />}
394
+ actionHref={spaceHost}
395
+ isLast
396
+ />
397
+ </>
398
+ ) : (
399
+ /* Direct access: 3 steps */
400
+ <>
401
+ <ChecklistStep
402
+ stepNumber={1}
403
+ title="Sign in with Hugging Face"
404
+ description="Authenticate to access GPU resources and model APIs."
405
+ status={signInStatus}
406
+ actionLabel="Sign in"
407
+ actionIcon={<LoginIcon sx={{ fontSize: 16 }} />}
408
+ onAction={() => triggerLogin()}
409
+ />
410
+ <ChecklistStep
411
+ stepNumber={2}
412
+ title="Join ML Agent Explorers"
413
+ description="Get free access to GPUs, inference APIs, and Hub resources."
414
+ status={joinOrgStatus}
415
+ lockedReason="Sign in first to continue."
416
+ actionLabel="Join Organization"
417
+ actionIcon={<GroupAddIcon sx={{ fontSize: 16 }} />}
418
+ onAction={handleJoinOrg}
419
+ />
420
+ <ChecklistStep
421
+ stepNumber={3}
422
+ title="Start Session"
423
+ description="Launch an AI agent session for ML engineering."
424
+ status={startStatus}
425
+ lockedReason="Complete the steps above to continue."
426
+ actionLabel="Start Session"
427
+ actionIcon={<RocketLaunchIcon sx={{ fontSize: 16 }} />}
428
+ onAction={handleStartSession}
429
+ loading={isCreating}
430
+ isLast
431
+ />
432
+ </>
433
+ )}
434
+ </Box>
435
+
436
+ {/* Polling hint when waiting for org join */}
437
+ {isAuthenticated && !isOrgMember && !isDevUser && !inIframe && (
438
+ <Typography
439
+ variant="caption"
440
+ sx={{ mt: 2, color: 'var(--muted-text)', fontSize: '0.75rem', textAlign: 'center' }}
441
+ >
442
+ This page updates automatically when you join the organization.
443
+ </Typography>
444
  )}
 
445
 
446
+ {/* Error */}
447
+ {error && (
448
+ <Alert
449
+ severity="warning"
450
+ variant="outlined"
451
+ onClose={() => setError(null)}
452
+ sx={{
453
+ mt: 3,
454
+ maxWidth: 400,
455
+ fontSize: '0.8rem',
456
+ borderColor: HF_ORANGE,
457
+ color: 'var(--text)',
458
+ }}
459
+ >
460
+ {error}
461
+ </Alert>
462
+ )}
463
+
464
+ {/* Footnote */}
465
  <Typography
466
  variant="caption"
467
+ sx={{ mt: 4, color: 'var(--muted-text)', opacity: 0.5, fontSize: '0.7rem' }}
468
  >
469
+ Conversations are stored locally in your browser.
470
  </Typography>
471
+ </Box>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472
  </Box>
473
  );
474
  }