1-
21import React , { useState } from 'react' ;
32import { ChapterData , PageData } from '../types' ;
43import CodePlayground from './CodePlayground' ;
54import PreviewBox from './PreviewBox' ;
65import ReadingSection from './ReadingSection' ;
6+ import { getGeminiExplanation } from '../services/geminiService' ;
77
88interface ChapterSectionProps {
99 data : ChapterData ;
@@ -22,9 +22,8 @@ const ChapterSection: React.FC<ChapterSectionProps> = ({
2222 const [ completedPages , setCompletedPages ] = useState < Record < string , boolean > > ( { } ) ;
2323 const [ userCodes , setUserCodes ] = useState < Record < string , string > > ( { } ) ;
2424 const [ errors , setErrors ] = useState < Record < string , string | null > > ( { } ) ;
25-
26- // Stores which hint index (1-based) the user is currently on for a specific page
27- const [ hintSteps , setHintSteps ] = useState < Record < string , number > > ( { } ) ;
25+ const [ hints , setHints ] = useState < Record < string , string > > ( { } ) ;
26+ const [ loadingHints , setLoadingHints ] = useState < Record < string , boolean > > ( { } ) ;
2827
2928 const handleRun = ( page : PageData , code : string ) => {
3029 if ( ! page . challenge ) return ;
@@ -45,30 +44,27 @@ const ChapterSection: React.FC<ChapterSectionProps> = ({
4544 }
4645 } ;
4746
48- const revealHint = ( pageId : string ) => {
49- setHintSteps ( prev => {
50- const current = prev [ pageId ] || 0 ;
51- return { ...prev , [ pageId ] : current + 1 } ;
52- } ) ;
47+ const askWizard = async ( page : PageData ) => {
48+ if ( ! page . challenge ) return ;
49+
50+ setLoadingHints ( prev => ( { ...prev , [ page . id ] : true } ) ) ;
51+ const code = userCodes [ page . id ] || "empty" ;
52+ const help = await getGeminiExplanation ( data . title + ": " + page . challenge . subtitle , code ) ;
53+ setHints ( prev => ( { ...prev , [ page . id ] : help } ) ) ;
54+ setLoadingHints ( prev => ( { ...prev , [ page . id ] : false } ) ) ;
5355 } ;
5456
5557 return (
5658 < div id = { `chapter-${ data . id } ` } className = "w-full" >
59+ { /* Chapter Title Slide (Optional, integrated into first page or just distinct) */ }
60+
5761 { data . pages . map ( ( page ) => {
58-
59- // Hint Logic
60- const currentHintStep = hintSteps [ page . id ] || 0 ;
61- const maxHints = page . challenge ?. hints ?. length || 0 ;
62- const activeHintText = currentHintStep > 0 && page . challenge ?. hints
63- ? page . challenge . hints [ Math . min ( currentHintStep , maxHints ) - 1 ]
64- : null ;
65-
6662 // Wrapper for snap behavior
6763 return (
68- < div key = { page . id } className = "min-h-screen w-full snap-start snap-always flex items-center justify-center p-4 md:p-8 relative" >
64+ < div key = { page . id } className = "min-h-screen w-full snap-start flex items-center justify-center p-4 md:p-8 relative" >
6965
7066 { /* Chapter Indicator Watermark */ }
71- < div className = { `absolute top-4 left-4 md:top-8 md:left-8 px-4 py-1 rounded-full border border-black/20 font-bold text-sm opacity-50 ${ data . color } z-20 ` } >
67+ < div className = { `absolute top-4 left-4 md:top-8 md:left-8 px-4 py-1 rounded-full border border-black/20 font-bold text-sm opacity-50 ${ data . color } ` } >
7268 CH.{ data . id } - { data . title }
7369 </ div >
7470
@@ -79,8 +75,8 @@ const ChapterSection: React.FC<ChapterSectionProps> = ({
7975 < div className = "w-full max-w-7xl mx-auto grid grid-cols-1 lg:grid-cols-2 gap-8 items-center h-full max-h-[90vh]" >
8076
8177 { /* Left: Challenge Code */ }
82- < div className = "flex flex-col gap-6 h-full justify-center relative z-10 w-full " >
83- < div className = "bg-white p-6 sketchy-border border-2 relative shadow-lg" >
78+ < div className = "flex flex-col gap-6 h-full justify-center" >
79+ < div className = "bg-white p-6 sketchy-border border-2 relative z-10 shadow-lg" >
8480 < div className = "absolute -top-3 -left-2 bg-black text-white px-3 py-1 text-xs font-bold rounded transform -rotate-3 shadow-md" >
8581 CHALLENGE
8682 </ div >
@@ -99,35 +95,21 @@ const ChapterSection: React.FC<ChapterSectionProps> = ({
9995 error = { errors [ page . id ] || null }
10096 />
10197
102- { /* Hints System (Hardcoded) */ }
103- { ! completedPages [ page . id ] && page . challenge ?. hints && (
104- < div className = "w-full " >
105- { currentHintStep === 0 ? (
98+ { /* Hints */ }
99+ { ! completedPages [ page . id ] && (
100+ < div className = "flex justify-start pl-2 " >
101+ { ! hints [ page . id ] ? (
106102 < button
107- onClick = { ( ) => revealHint ( page . id ) }
108- className = "w-full py-3 rounded-xl border-2 border-purple-200 bg-purple-50 hover:bg-purple-100 text-purple-700 font-bold transition-all flex items-center justify-center gap-2 shadow-sm group"
103+ onClick = { ( ) => askWizard ( page ) }
104+ disabled = { loadingHints [ page . id ] }
105+ className = "text-sm font-bold text-purple-600 hover:text-purple-800 transition-all flex items-center gap-2"
109106 >
110- < span className = "text-xl group-hover:scale-110 transition-transform " > 🧙♂️</ span >
111- Ask the Wizard for a Hint
107+ < span className = "text-lg " > 🧙♂️</ span >
108+ { loadingHints [ page . id ] ? "Consulting the orbs..." : "Need a hint?" }
112109 </ button >
113110 ) : (
114- < div className = "w-full bg-purple-50 p-4 rounded-xl border-2 border-purple-200 text-purple-900 shadow-sm animate-in fade-in slide-in-from-bottom-2 relative" >
115- < div className = "flex justify-between items-start mb-2" >
116- < div className = "font-bold text-xs text-purple-400 uppercase" >
117- Wizard's Wisdom ({ Math . min ( currentHintStep , maxHints ) } /{ maxHints } )
118- </ div >
119- { currentHintStep < maxHints && (
120- < button
121- onClick = { ( ) => revealHint ( page . id ) }
122- className = "text-xs font-bold text-purple-600 hover:text-purple-800 underline bg-purple-100 px-2 py-1 rounded"
123- >
124- Next Hint →
125- </ button >
126- ) }
127- </ div >
128- < div className = "font-hand text-lg leading-tight" >
129- { activeHintText }
130- </ div >
111+ < div className = "bg-purple-50 p-3 rounded-lg border border-purple-200 text-purple-900 text-sm max-w-md animate-in fade-in slide-in-from-bottom-2" >
112+ < strong > Wizard says:</ strong > { hints [ page . id ] }
131113 </ div >
132114 ) }
133115 </ div >
@@ -145,8 +127,10 @@ const ChapterSection: React.FC<ChapterSectionProps> = ({
145127 </ div >
146128 ) ;
147129 } ) }
130+
131+ { /* Optional: Next Chapter Button Page if needed, or just rely on scroll */ }
148132 </ div >
149133 ) ;
150134} ;
151135
152- export default ChapterSection ;
136+ export default ChapterSection ;
0 commit comments