py-learn / src /app /reading /reading.component.html
Anupriya
reading component back arrow
a998588
<div class="reading-container">
<app-header [title]="'Reading'"></app-header>
<img src="assets/images/grammar-bg.png" alt="Background" class="grammar-bg" />
<div class="main-container" *ngIf="!showCongrats">
<section class="intro-section split" *ngIf="!content && !hasStarted">
<div class="split-shell">
<div class="split-left">
<img class="intro-illustration" src="assets/images/reading/teacher.png" alt="Reading and quiz illustration" />
</div>
<div class="split-right">
<h1 class="hero-title">Welcome to the Reading Exercise</h1>
<p class="hero-copy">
The Reading component is a simple tool that turns any meaningful topic into a short, age-appropriate passage. It checks the topic first to avoid nonsense and unsafe inputs, then creates clear content at the chosen level (Easy, Medium, or Hard). After
reading, it generates multiple-choice questions and gives instant feedback. Read-Aloud and A−/A+ controls support different learning needs. This helps students build comprehension and vocabulary, and saves teachers and parents
time during practice, homework, and revision.
</p>
<div class="form-row">
<label class="row-label">Topic:</label>
<div class="input-wrap clearable" [class.locked]="!difficulty">
<span class="icon-search" aria-hidden="true"></span>
<input type="text" class="has-clear" [(ngModel)]="topic" [placeholder]="difficulty ? 'Enter or select a topic' : 'Select a level first'" [disabled]="!difficulty" (focus)="openSuggestions()" (input)="onTyping()" (keydown)="onKeydown($event)" (blur)="hideSuggestionsWithDelay()"
autocomplete="off" aria-autocomplete="list" [attr.aria-expanded]="showSuggestions && !!difficulty" [attr.aria-disabled]="!difficulty" />
<button class="clear-btn" *ngIf="difficulty && topic.trim().length" (mousedown)="$event.preventDefault()" (click)="onClearTopic()">×</button>
<div class="suggestion-box" *ngIf="difficulty && showSuggestions">
<ng-container *ngIf="filteredSuggestions?.length">
<span *ngFor="let s of filteredSuggestions; let i = index" (mousedown)="selectSuggestion(s)" [class.active]="i === activeIndex">{{ s }}</span>
</ng-container>
</div>
</div>
<div class="field-hint" *ngIf="!difficulty">
<span class="lock-icon" aria-hidden="true"></span> Please select a level to enable topic suggestions.
</div>
</div>
<div class="form-row">
<label class="row-label">Select Level:</label>
<div class="select-wrap">
<span class="icon-level" aria-hidden="true"></span>
<select [(ngModel)]="difficulty" (ngModelChange)="onDifficultyChange($event)" required>
<option [ngValue]="'easy'">Easy</option>
<option [ngValue]="'medium'">Medium</option>
<option [ngValue]="'hard'">Hard</option>
</select>
<span class="badge" *ngIf="difficulty" [attr.data-level]="difficulty">{{ difficulty | titlecase }}</span>
</div>
<app-button (click)="generateContent()" [disabled]="!topic.trim() || !difficulty.trim() || isGenerateDisabled">Generate Passage</app-button>
</div>
</div>
</div>
<div class="loader-overlay" *ngIf="isGeneratingContent" role="status" aria-live="polite">
<div class="loader">Loading</div>
</div>
<div class="popup-overlay" *ngIf="showPopup">
<div class="popup-content">
<p>{{ errorMessage || 'We could not create the passage right now. Please try again.' }}</p>
<app-button (click)="closeErrorPopup()">Close</app-button>
</div>
</div>
</section>
<div *ngIf="content && !hasStarted" class="reading-card">
<div class="reading-head">
<img src="assets/images/reading/back.png" (click)="goToIntroSection()" alt="" class="icon-img" />
<h2 class="reading-title">Let’s Start Reading!</h2>
<div class="head-actions">
<button class="icon-btn" (click)="decreaseFont()" aria-label="Decrease font">A−</button>
<button class="icon-btn" (click)="increaseFont()" aria-label="Increase font">A+</button>
<button class="icon-btn" [class.active]="isReading || ttsPaused" (click)="toggleReadAloud()" [attr.aria-pressed]="isReading || ttsPaused" aria-label="Read aloud">{{ isReading ? '⏸' : '🔊' }}</button>
</div>
</div>
<div class="reading-meta">
<span class="chip chip-topic" *ngIf="normalizedTopic || topic">📚 {{ normalizedTopic || topic }}</span>
<span class="chip chip-level" [attr.data-level]="difficulty">{{ difficulty | titlecase }}</span>
</div>
<div class="passage-shell">
<div class="passage-text" [innerHTML]="transformContent(content)"></div>
</div>
<div class="reading-actions">
<app-button (click)="stopReadAloud(); generateQuestions()" [disabled]="isGenerateQuestionDisabled">Generate Questions</app-button>
<div class="loader-overlay" *ngIf="loadingQuestions" aria-live="polite" aria-busy="true">
<span class="loader">Loading</span>
</div>
<app-button (click)="stopReadAloud(); resetAll()">Reset</app-button>
</div>
</div>
<div class="mcq-card" *ngIf="hasStarted && questions?.length">
<div class="mcq-card__header">
<img src="assets/images/reading/back.png"
alt="Back"
class="icon-img"
(click)="goToReadingPassage()"
tabindex="0"
(keydown.enter)="goToReadingPassage()" />
<h3 class="mcq-card__title">Question {{ currentQuestionIndex + 1 }} of {{ questions.length }}</h3>
<div class="mcq-card__actions">
<button class="user-guide-close-icon" (click)="startOver()">×</button>
</div>
</div>
<div class="mcq-card__body">
<div class="quiz-pill quiz-question-pill">
<span class="qq-label">Question:</span>
<span class="qq-text">{{ questions[currentQuestionIndex].question }}</span>
</div>
<ul class="quiz-options">
<li *ngFor="let option of (questions[currentQuestionIndex]?.options | slice:0:4); let i = index">
<label class="quiz-pill quiz-option-pill" [ngClass]="{
'is-selected': !questions[currentQuestionIndex].isChecked && getSelectedAnswer() === option,
'is-correct': questions[currentQuestionIndex].isChecked && questions[currentQuestionIndex].correct_answer === option,
'is-incorrect':questions[currentQuestionIndex].isChecked && getSelectedAnswer() === option && option !== questions[currentQuestionIndex].correct_answer
}">
<input type="radio" class="visually-hidden" [name]="'q_'+currentQuestionIndex" [value]="option" [checked]="getSelectedAnswer() === option" (change)="setSelectedAnswer(option)" [disabled]="questions[currentQuestionIndex].isChecked" />
<span class="slot">{{ ['A','B','C','D'][i] }}:</span>
<span class="opt-text">{{ option }}</span>
</label>
</li>
</ul>
</div>
<div class="mcq-card__footer">
<app-button *ngIf="currentQuestionIndex > 0" (click)="previousQuestion()">◀ Previous</app-button>
<div style="display: flex; gap: 10px; justify-content: flex-end; flex: 1;">
<app-button *ngIf="!questions[currentQuestionIndex].isChecked" (click)="validateAnswer(); scheduleCongratsIfLast()" [disabled]="!selectedAnswers[questions[currentQuestionIndex].question]">Validate</app-button>
<app-button *ngIf="questions[currentQuestionIndex].isChecked && currentQuestionIndex < questions.length - 1" (click)="nextQuestion()">Next ▶</app-button>
</div>
</div>
</div>
</div>
<div class="congrats-overlay" *ngIf="showCongrats" aria-live="polite" aria-modal="true" role="dialog">
<div class="congrats-card">
<div class="score-badge" aria-label="Your score">
Your Score: <span class="score">{{ scoreCorrect }}</span> / <span class="total">{{ scoreTotal }}</span>
</div>
<h2>{{ congratsTitle }}</h2>
<p>{{ congratsMessage }}</p>
<app-button (click)="startOver()">Start Over</app-button>
</div>
</div>
</div>