Skip to content

Commit daa799b

Browse files
committed
v2.53 - Renew Onboarding
1 parent 90634ca commit daa799b

2 files changed

Lines changed: 53 additions & 53 deletions

File tree

frontend/src/components/app/AppShell.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { fetchUserMemory, fetchUserStatus, updateUserMemory, type UpdateUserMemo
1313
import { trackFrontendEvent } from "@/lib/frontendAnalytics"
1414
import { setSettingsCache } from "@/lib/settingsCache"
1515

16-
const GoldenGuideModal = lazy(() => import("@/components/app/GoldenGuideModal")) as React.LazyExoticComponent<React.ComponentType<{ COLORS: ThemeColors }>>
1716
const SearchModal = lazy(() => import("@/components/app/SearchModal")) as React.LazyExoticComponent<React.ComponentType<{ COLORS: ThemeColors }>>
1817
const DeleteConfirmModal = lazy(() => import("@/components/app/DeleteConfirmModal").then((m) => ({ default: m.DeleteConfirmModal }))) as React.LazyExoticComponent<React.ComponentType<{ COLORS: ThemeColors }>>
1918

@@ -45,7 +44,7 @@ function ShellInner({ children }: { children: React.ReactNode }) {
4544
const COLORS = useThemeColors()
4645
const { resolved } = useTheme()
4746
const exp1 = useExp1()
48-
const { state } = useChat()
47+
const { state, closeGuide } = useChat()
4948
const { user, loading } = useAuth()
5049
const pathname = usePathname()
5150
const router = useRouter()
@@ -144,7 +143,7 @@ function ShellInner({ children }: { children: React.ReactNode }) {
144143
}}
145144
>
146145
<Suspense fallback={null}>
147-
{guideOpen && <GoldenGuideModal COLORS={COLORS} />}
146+
{guideOpen && <OnboardingModal mode="tutorial" open onClose={closeGuide} />}
148147
{searchOpen && <SearchModal COLORS={COLORS} />}
149148
<DeleteConfirmModal COLORS={COLORS} />
150149
</Suspense>

frontend/src/components/app/OnboardingModal.tsx

Lines changed: 51 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -196,13 +196,13 @@ export default function OnboardingModal({
196196

197197
const chipStyle = (active: boolean): React.CSSProperties => ({
198198
borderRadius: "999px",
199-
border: active ? `1.5px solid ${accent}` : `1px solid ${isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)"}`,
199+
border: active ? `1.5px solid ${accent}` : `1px solid ${isDark ? "rgba(255,255,255,0.12)" : "rgba(0,0,0,0.1)"}`,
200200
background: active ? accentBg : "transparent",
201201
color: active ? (isDark ? "#fff" : "#000") : COLORS.textSecondary,
202202
fontFamily: FONTS.sans,
203-
fontSize: "13px",
203+
fontSize: "14px",
204204
fontWeight: active ? 600 : 400,
205-
padding: "8px 16px",
205+
padding: "10px 18px",
206206
cursor: submitting ? "not-allowed" : "pointer",
207207
transition: "all 250ms cubic-bezier(0.4, 0, 0.2, 1)",
208208
outline: "none",
@@ -213,35 +213,35 @@ export default function OnboardingModal({
213213
/* ── Step renderers ── */
214214

215215
const renderStep0 = () => (
216-
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "36px", maxWidth: "420px", margin: "0 auto" }}>
216+
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "48px", maxWidth: "440px", margin: "0 auto" }}>
217217
{/* Logo / brand mark */}
218218
<div style={{
219-
width: "64px", height: "64px", borderRadius: "18px",
219+
width: "72px", height: "72px", borderRadius: "20px",
220220
background: `linear-gradient(135deg, ${accent}, #E8A020)`,
221221
display: "flex", alignItems: "center", justifyContent: "center",
222222
boxShadow: `0 8px 32px ${accent}40`,
223223
}}>
224-
<span style={{ fontSize: "28px", fontWeight: 800, color: "#fff", fontFamily: FONTS.mono }}>FP</span>
224+
<span style={{ fontSize: "30px", fontWeight: 800, color: "#fff", fontFamily: FONTS.mono }}>FP</span>
225225
</div>
226226

227227
<div style={{ textAlign: "center" }}>
228228
<h1 style={{
229-
margin: "0 0 12px", fontFamily: FONTS.sans, fontSize: "32px", fontWeight: 700,
230-
color: COLORS.textPrimary, lineHeight: 1.15, letterSpacing: "-0.02em",
229+
margin: "0 0 16px", fontFamily: FONTS.sans, fontSize: "34px", fontWeight: 700,
230+
color: COLORS.textPrimary, lineHeight: 1.2, letterSpacing: "-0.02em",
231231
}}>
232232
Welcome to First Principle
233233
</h1>
234234
<p style={{
235-
margin: 0, fontFamily: FONTS.sans, fontSize: "16px", fontWeight: 400,
236-
color: COLORS.textSecondary, lineHeight: 1.6, maxWidth: "38ch", marginInline: "auto",
235+
margin: 0, fontFamily: FONTS.sans, fontSize: "17px", fontWeight: 400,
236+
color: COLORS.textSecondary, lineHeight: 1.65, maxWidth: "40ch", marginInline: "auto",
237237
}}>
238238
Learn anything from the ground up. We just need a few details to personalize your experience.
239239
</p>
240240
</div>
241241

242242
{/* Name fields */}
243-
<div style={{ width: "100%", display: "flex", flexDirection: "column", gap: "14px" }}>
244-
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "12px" }}>
243+
<div style={{ width: "100%", display: "flex", flexDirection: "column", gap: "20px" }}>
244+
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "16px" }}>
245245
<input
246246
value={firstName}
247247
onChange={(e) => { setFirstName(e.target.value); clearError() }}
@@ -269,23 +269,23 @@ export default function OnboardingModal({
269269
)
270270

271271
const renderStep1 = () => (
272-
<div style={{ display: "flex", flexDirection: "column", gap: "28px", maxWidth: "520px", margin: "0 auto" }}>
272+
<div style={{ display: "flex", flexDirection: "column", gap: "40px", maxWidth: "560px", margin: "0 auto" }}>
273273
<div style={{ textAlign: "center" }}>
274274
<h2 style={{
275-
margin: "0 0 8px", fontFamily: FONTS.sans, fontSize: "26px", fontWeight: 700,
275+
margin: "0 0 12px", fontFamily: FONTS.sans, fontSize: "28px", fontWeight: 700,
276276
color: COLORS.textPrimary, letterSpacing: "-0.01em",
277277
}}>
278278
Make it yours
279279
</h2>
280-
<p style={{ margin: 0, fontFamily: FONTS.sans, fontSize: "15px", color: COLORS.textSecondary, lineHeight: 1.6 }}>
280+
<p style={{ margin: 0, fontFamily: FONTS.sans, fontSize: "16px", color: COLORS.textSecondary, lineHeight: 1.65 }}>
281281
This helps us tailor explanations to your world. The model will keep learning from your chats over time.
282282
</p>
283283
</div>
284284

285285
{/* Role */}
286-
<div>
286+
<div style={{ paddingBottom: "8px" }}>
287287
<p style={sectionLabel(COLORS)}>I am a...</p>
288-
<div style={{ display: "flex", flexWrap: "wrap", gap: "8px", justifyContent: "center" }}>
288+
<div style={{ display: "flex", flexWrap: "wrap", gap: "10px", justifyContent: "center", marginTop: "14px" }}>
289289
{ONBOARDING_ROLES.map((r) => (
290290
<button key={r} type="button" onClick={() => { if (!submitting) { setRole(r); clearError() } }} style={chipStyle(role === r)}>
291291
{ONBOARDING_ROLE_LABELS[r]}
@@ -295,9 +295,9 @@ export default function OnboardingModal({
295295
</div>
296296

297297
{/* Goals */}
298-
<div>
298+
<div style={{ paddingBottom: "8px" }}>
299299
<p style={sectionLabel(COLORS)}>I want to...</p>
300-
<div style={{ display: "flex", flexWrap: "wrap", gap: "8px", justifyContent: "center" }}>
300+
<div style={{ display: "flex", flexWrap: "wrap", gap: "10px", justifyContent: "center", marginTop: "14px" }}>
301301
{ONBOARDING_GOALS.map((g) => (
302302
<button key={g} type="button" onClick={() => {
303303
if (submitting) return
@@ -311,9 +311,9 @@ export default function OnboardingModal({
311311
</div>
312312

313313
{/* How did you find us */}
314-
<div>
314+
<div style={{ paddingBottom: "8px" }}>
315315
<p style={sectionLabel(COLORS)}>How did you find us?</p>
316-
<div style={{ display: "flex", flexWrap: "wrap", gap: "8px", justifyContent: "center" }}>
316+
<div style={{ display: "flex", flexWrap: "wrap", gap: "10px", justifyContent: "center", marginTop: "14px" }}>
317317
{ONBOARDING_SOURCES.map((s) => (
318318
<button key={s} type="button" onClick={() => {
319319
if (submitting) return
@@ -330,38 +330,39 @@ export default function OnboardingModal({
330330
value={sourceOther}
331331
onChange={(e) => { setSourceOther(e.target.value); clearError() }}
332332
placeholder="Please specify..."
333-
style={{ ...inputStyle(COLORS, isDark), marginTop: "10px", maxWidth: "320px", marginInline: "auto", display: "block" }}
333+
style={{ ...inputStyle(COLORS, isDark), marginTop: "14px", maxWidth: "320px", marginInline: "auto", display: "block" }}
334334
/>
335335
)}
336336
</div>
337337

338338
{/* Background */}
339-
<div style={{ textAlign: "center" }}>
339+
<div style={{ textAlign: "center", paddingBottom: "8px" }}>
340340
<p style={sectionLabel(COLORS)}>Background (optional)</p>
341341
<textarea
342342
value={background}
343343
onChange={(e) => { setBackground(e.target.value); clearError() }}
344344
placeholder="Optional: share your experience level. The model will also learn from your chats."
345345
style={{
346346
...inputStyle(COLORS, isDark),
347-
minHeight: "80px",
347+
minHeight: "88px",
348348
resize: "vertical" as const,
349349
maxWidth: "100%",
350+
marginTop: "14px",
350351
}}
351352
/>
352353
</div>
353354
</div>
354355
)
355356

356357
const renderStep2 = () => (
357-
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "24px", maxWidth: "600px", margin: "0 auto", width: "100%" }}>
358+
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "32px", maxWidth: "620px", margin: "0 auto", width: "100%" }}>
358359
{/* Video area */}
359360
<div style={{
360361
width: "100%",
361-
borderRadius: "16px",
362+
borderRadius: "18px",
362363
overflow: "hidden",
363364
background: isDark ? "rgba(255,255,255,0.03)" : "rgba(0,0,0,0.03)",
364-
border: `1px solid ${isDark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)"}`,
365+
border: `1px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.06)"}`,
365366
aspectRatio: "16 / 9",
366367
position: "relative",
367368
}}>
@@ -401,30 +402,30 @@ export default function OnboardingModal({
401402
{/* Text */}
402403
<div key={currentSlide.id} style={{ textAlign: "center", animation: "fpOnboardFadeUp 400ms ease-out" }}>
403404
<h2 style={{
404-
margin: "0 0 8px", fontFamily: FONTS.sans, fontSize: "22px", fontWeight: 700,
405+
margin: "0 0 10px", fontFamily: FONTS.sans, fontSize: "24px", fontWeight: 700,
405406
color: COLORS.textPrimary, letterSpacing: "-0.01em",
406407
}}>
407408
{currentSlide.title}
408409
</h2>
409410
<p style={{
410-
margin: 0, fontFamily: FONTS.sans, fontSize: "15px", color: COLORS.textSecondary,
411-
lineHeight: 1.6, maxWidth: "44ch", marginInline: "auto",
411+
margin: 0, fontFamily: FONTS.sans, fontSize: "16px", color: COLORS.textSecondary,
412+
lineHeight: 1.65, maxWidth: "46ch", marginInline: "auto",
412413
}}>
413414
{currentSlide.description}
414415
</p>
415416
</div>
416417

417418
{/* Slide dots */}
418-
<div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
419+
<div style={{ display: "flex", gap: "10px", alignItems: "center" }}>
419420
{ONBOARDING_TUTORIAL_SLIDES.map((s, i) => (
420421
<button
421422
key={s.id}
422423
type="button"
423424
onClick={() => setSlide(i)}
424425
aria-label={`Tutorial ${i + 1}`}
425426
style={{
426-
width: i === slide ? "24px" : "8px",
427-
height: "8px",
427+
width: i === slide ? "28px" : "10px",
428+
height: "10px",
428429
borderRadius: "999px",
429430
border: "none",
430431
background: i === slide ? accent : (isDark ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.12)"),
@@ -438,13 +439,13 @@ export default function OnboardingModal({
438439
</div>
439440
)
440441

441-
/* ── Tutorial-only mode (reopened from Profile) ── */
442+
/* ── Tutorial-only mode (Golden Guide button or Profile) ── */
442443
const renderTutorialOnly = () => (
443444
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
444-
<div style={{ flex: 1, minHeight: 0, overflowY: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: "32px 24px" }}>
445+
<div style={{ flex: 1, minHeight: 0, overflowY: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: "40px 32px" }}>
445446
{renderStep2()}
446447
</div>
447-
<div style={{ padding: "16px 28px", display: "flex", justifyContent: "flex-end" }}>
448+
<div style={{ padding: "20px 36px 24px", display: "flex", justifyContent: "flex-end" }}>
448449
<button type="button" onClick={() => onClose?.()} style={primaryBtnStyle(accent)}>
449450
{slide >= TOTAL_SLIDES - 1 ? "Done" : "Close"}
450451
</button>
@@ -495,9 +496,9 @@ export default function OnboardingModal({
495496
aria-modal="true"
496497
aria-label={isOnboarding ? "Onboarding" : "Tutorial"}
497498
style={{
498-
width: "min(680px, 94vw)",
499-
maxHeight: "min(92vh, 780px)",
500-
borderRadius: "24px",
499+
width: "min(720px, 94vw)",
500+
maxHeight: "min(92vh, 840px)",
501+
borderRadius: "28px",
501502
border: `1px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)"}`,
502503
background: isDark ? "rgba(14,14,14,0.98)" : "rgba(255,255,255,0.98)",
503504
boxShadow: isDark
@@ -520,7 +521,7 @@ export default function OnboardingModal({
520521
flex: 1,
521522
minHeight: 0,
522523
overflowY: "auto",
523-
padding: step === 2 ? "32px 28px 20px" : "48px 36px 24px",
524+
padding: step === 2 ? "40px 36px 28px" : "56px 44px 32px",
524525
display: "flex",
525526
alignItems: step === 2 ? "flex-start" : "center",
526527
justifyContent: "center",
@@ -536,12 +537,12 @@ export default function OnboardingModal({
536537

537538
{/* Footer */}
538539
<div style={{
539-
padding: "16px 28px",
540+
padding: "20px 36px 24px",
540541
display: "flex",
541542
alignItems: "center",
542543
justifyContent: "space-between",
543-
gap: "12px",
544-
borderTop: `1px solid ${isDark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.05)"}`,
544+
gap: "16px",
545+
borderTop: `1px solid ${isDark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)"}`,
545546
}}>
546547
{/* Left: dots */}
547548
<div style={{ display: "flex", gap: "6px", alignItems: "center" }}>
@@ -617,13 +618,13 @@ function inputStyle(COLORS: any, isDark: boolean): React.CSSProperties {
617618
return {
618619
width: "100%",
619620
boxSizing: "border-box",
620-
borderRadius: "12px",
621-
border: `1px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)"}`,
621+
borderRadius: "14px",
622+
border: `1px solid ${isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.08)"}`,
622623
background: isDark ? "rgba(255,255,255,0.04)" : "rgba(0,0,0,0.03)",
623624
color: COLORS.textPrimary,
624-
fontSize: "15px",
625+
fontSize: "16px",
625626
fontFamily: FONTS.sans,
626-
padding: "12px 16px",
627+
padding: "14px 18px",
627628
outline: "none",
628629
transition: "border-color 200ms ease",
629630
}
@@ -632,13 +633,13 @@ function inputStyle(COLORS: any, isDark: boolean): React.CSSProperties {
632633
// eslint-disable-next-line @typescript-eslint/no-explicit-any
633634
function sectionLabel(COLORS: any): React.CSSProperties {
634635
return {
635-
margin: "0 0 10px",
636+
margin: 0,
636637
fontFamily: FONTS.sans,
637-
fontSize: "13px",
638+
fontSize: "12px",
638639
fontWeight: 600,
639640
color: COLORS.textTertiary,
640641
textTransform: "uppercase" as const,
641-
letterSpacing: "0.06em",
642+
letterSpacing: "0.08em",
642643
textAlign: "center" as const,
643644
}
644645
}

0 commit comments

Comments
 (0)