File size: 8,532 Bytes
e4ab6d0 0a2fc2b 50fc34c e4ab6d0 50fc34c 04830fa 50fc34c 04830fa 50fc34c 04830fa 50fc34c 04830fa 50fc34c 04830fa 50fc34c 04830fa 50fc34c 04830fa 50fc34c e4ab6d0 50fc34c 04830fa e4ab6d0 50fc34c 04830fa 50fc34c 04830fa e4ab6d0 50fc34c 04830fa 50fc34c e4ab6d0 50fc34c 04830fa 50fc34c e4ab6d0 04830fa e4ab6d0 50fc34c e4ab6d0 a998588 e4ab6d0 04830fa 50fc34c 04830fa e4ab6d0 50fc34c e4ab6d0 50fc34c 04830fa 50fc34c 04830fa 50fc34c e4ab6d0 50fc34c 04830fa e4ab6d0 50fc34c 6f70a09 50fc34c 6f70a09 e4ab6d0 04830fa e4ab6d0 6f70a09 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
<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>
|