py-learn / src /app /reading /reading.component.html
Anupriya
integrated shared header into all components
0a2fc2b
raw
history blame
11.1 kB
<div class="reading-container">
<app-header [title]="'Reading'"></app-header>
<!-- Background -->
<img src="assets/images/grammar-bg.png" alt="Background" class="grammar-bg" />
<!-- Main -->
<div class="main-container" *ngIf="!showCongrats">
<!-- INTRO (split left image / right form) -->
<section class="intro-section split" *ngIf="!content && !hasStarted">
<div class="split-shell">
<!-- Left -->
<div class="split-left">
<img class="intro-illustration"
src="assets/images/reading/teacher.png"
alt="Reading and quiz illustration" />
</div>
<!-- Right -->
<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>
<!-- Row: Topic -->
<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" />
<!-- Clear (×) only when enabled and has text -->
<button class="clear-btn"
*ngIf="difficulty && topic.trim().length"
(mousedown)="$event.preventDefault()"
(click)="onClearTopic()">
×
</button>
<!-- Suggestions only after a level is chosen -->
<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>
<!--
<ng-template #noMatches>
<span (mousedown)="selectSuggestion(topic)">Use “{{ topic }}”</span>
</ng-template>
-->
</div>
</div>
<!-- Tiny helper note shown only when level not chosen -->
<div class="field-hint" *ngIf="!difficulty">
<span class="lock-icon" aria-hidden="true"></span>
Please select a level to enable topic suggestions.
</div>
</div>
<!-- Row: Level + Generate -->
<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>
<button class="btn-get"
(click)="generateContent()
"
[disabled]="!topic.trim() || !difficulty.trim() || isGenerateDisabled">
Generate Passage
</button>
</div>
</div>
</div>
<!-- Centered loader (uses your .loader-overlay/.loader CSS) -->
<div class="loader-overlay" *ngIf="isGeneratingContent" role="status" aria-live="polite">
<div class="loader">Loading</div>
</div>
<!-- Error popup (uses existing CSS .popup-overlay/.popup-content) -->
<div class="popup-overlay" *ngIf="showPopup">
<div class="popup-content">
<p>
{{ errorMessage || 'We could not create the passage right now. Please try again.' }}
</p>
<button class="close-btn1" (click)="closeErrorPopup()">Close</button>
</div>
</div>
</section>
<!-- READING CARD -->
<div *ngIf="content && !hasStarted" class="reading-card">
<!-- Header -->
<div class="reading-head">
<button class="icon-btn back" (click)="goToIntroSection()" aria-label="Back">
<img src="assets/images/reading/back.png" alt="" class="icon-img" />
</button>
<h2 class="reading-title">Let’s Start Reading!</h2>
<!-- Actions: A− A+ Read/Pause Stop -->
<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>
<!--
<button class="icon-btn danger" (click)="stopReadAloud()" aria-label="Stop reading">■</button>
-->
</div>
</div>
<!-- Meta -->
<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>
<!-- Passage -->
<div class="passage-shell">
<div class="passage-text" [innerHTML]="transformContent(content)"></div>
</div>
<!-- Footer -->
<div class="reading-actions">
<button class="btn-primary"
(click)="stopReadAloud(); generateQuestions()"
[disabled]="isGenerateQuestionDisabled">
Generate Questions
</button>
<!-- Centered loader while generating questions -->
<div class="loader-overlay" *ngIf="loadingQuestions" aria-live="polite" aria-busy="true">
<span class="loader">Loading</span>
</div>
<button class="btn-danger" (click)="stopReadAloud(); resetAll()">Reset</button>
</div>
</div>
<!-- QUESTIONS -->
<!-- MCQ CARD -->
<div class="mcq-card" *ngIf="hasStarted && questions?.length">
<!-- Header inside the card -->
<div class="mcq-card__header">
<button class="icon-btn back" (click)="goBack()" aria-label="Back">
<img src="assets/images/reading/back.png" alt="" class="icon-img" />
</button>
<h3 class="mcq-card__title">
Question {{ currentQuestionIndex + 1 }} of {{ questions.length }}
</h3>
<div class="mcq-card__actions">
<button class="icon-btn1" (click)="startOver()" aria-label="Close"></button>
</div>
</div>
<!-- Body -->
<div class="mcq-card__body">
<!-- Question pill -->
<div class="quiz-pill quiz-question-pill">
<span class="qq-label">Question:</span>
<span class="qq-text">{{ questions[currentQuestionIndex].question }}</span>
</div>
<!-- Options -->
<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>
<!-- Footer inside the card -->
<div class="mcq-card__footer">
<!-- Submit (visible until answered) -->
<button *ngIf="!questions[currentQuestionIndex].isChecked"
class="submit-btn"
(click)="validateAnswer(); scheduleCongratsIfLast()"
[disabled]="!selectedAnswers[questions[currentQuestionIndex].question]">
Validate
</button>
<!-- Next (for Q1 & Q2 after submit) -->
<button *ngIf="questions[currentQuestionIndex].isChecked && currentQuestionIndex < questions.length - 1"
class="next-btn"
(click)="nextQuestion()">
Next ▶
</button>
</div>
</div>
</div>
<!-- Congratulations overlay -->
<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> <!-- Display the dynamic title -->
<p>{{ congratsMessage }}</p> <!-- Display the dynamic message -->
<button class="start-over-btn" (click)="startOver()">Start Over</button>
</div>
</div>
</div>