Construye una aplicación web de temporizador para aula inteligente de pila completa
De Wikiprompt, la enciclopedia libre de prompts
Construye una aplicación web de temporizador para aula inteligente de pila completa Un prompt integral en árabe para construir una aplicación web full-stack de un temporizador interactivo inteligente para el aula, con cuenta regresiva, sonidos, selector aleatorio de estudiantes y personalización de escenario.
Contenido del PromptGuardar
🌐
خطة التطوير:
1. **تحليل المتطلبات**: بناء تطبيق ويب كامل (Full-Stack) لمعلمين، بواجهة عربية، مع مؤقت ذكي للفصول الدراسية.
2. **التقنيات**: استخدام Node.js مع Express للخادم، وHTML/CSS/JavaScript للواجهة، مع تخزين محلي (LocalStorage) للبيانات.
3. **المكونات**:
- مؤقت تنازلي مع شريط تقدم دائري يتغير لونه (أخضر، أصفر، أحمر).
- نظام أصوات (بدء الحصة، تحذير آخر دقيقة، انتهاء الوقت، مكتبة أصوات تحفيزية).
- أداة اختيار طالب عشوائي مع صوت تشويق.
- إدارة مراحل الحصة (إحماء، نقاش، تمرين) مع مؤقت لكل مرحلة.
- تحكم في مستوى الصوت (كتم/تشغيل).
4. **التصميم**: واجهة عربية حديثة، خطوط واضحة، ألوان مريحة للعين، متجاوبة مع الشاشات الكبيرة.
5. **النشر**: تجهيز التطبيق للنشر المباشر.
---
**الكود الكامل**:
**server.js** (الخادم):
```javascript
const express = require('express');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
```
**public/index.html**:
```html
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>مؤقت الفصل الذكي</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<header>
<h1>مؤقت الفصل الذكي</h1>
<div class="controls">
<button id="muteBtn">🔊 كتم الصوت</button>
</div>
</header>
<main>
<section class="timer-section">
<div class="timer-circle" id="timerCircle">
<div class="timer-display">
<span id="minutes">45</span>:<span id="seconds">00</span>
</div>
<div class="progress-ring">
<svg viewBox="0 0 200 200">
<circle class="progress-ring-circle" cx="100" cy="100" r="90" />
</svg>
</div>
</div>
<div class="timer-controls">
<input type="number" id="timerInput" value="45" min="1" max="120">
<button id="startBtn">▶ بدء</button>
<button id="pauseBtn">⏸ إيقاف مؤقت</button>
<button id="resetBtn">↺ إعادة</button>
</div>
</section>
<section class="stages-section">
<h2>مراحل الحصة</h2>
<div id="stagesList"></div>
<div class="add-stage">
<input type="text" id="stageName" placeholder="اسم المرحلة">
<input type="number" id="stageDuration" placeholder="المدة (دقائق)" min="1">
<button id="addStageBtn">+ إضافة مرحلة</button>
</div>
</section>
<section class="sounds-section">
<h2>الأصوات التحفيزية</h2>
<div class="sound-buttons">
<button class="sound-btn" data-sound="applause">👏 تصفيق</button>
<button class="sound-btn" data-sound="ding">🔔 نجاح</button>
<button class="sound-btn" data-sound="error">❌ خطأ</button>
<button class="sound-btn" data-sound="music">🎵 موسيقى</button>
</div>
</section>
<section class="student-picker">
<h2>اختيار طالب عشوائي</h2>
<textarea id="studentsInput" placeholder="أدخل أسماء الطلاب، كل اسم في سطر"></textarea>
<button id="pickStudentBtn">🎲 اختر طالباً</button>
<div id="selectedStudent" class="selected-student"></div>
</section>
</main>
</div>
<script src="script.js"></script>
</body>
</html>
```
**public/style.css**:
```css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #fff;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
background: rgba(255, 255, 255, 0.1);
padding: 15px 25px;
border-radius: 15px;
backdrop-filter: blur(10px);
}
h1 {
font-size: 2.5rem;
font-weight: bold;
}
.controls button {
background: rgba(255, 255, 255, 0.2);
border: none;
color: white;
padding: 10px 20px;
border-radius: 10px;
cursor: pointer;
font-size: 1.1rem;
transition: all 0.3s;
}
.controls button:hover {
background: rgba(255, 255, 255, 0.3);
}
main {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
}
section {
background: rgba(255, 255, 255, 0.1);
padding: 25px;
border-radius: 15px;
backdrop-filter: blur(10px);
}
.timer-section {
grid-column: 1 / -1;
text-align: center;
}
.timer-circle {
position: relative;
width: 300px;
height: 300px;
margin: 0 auto 20px;
}
.timer-display {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 3.5rem;
font-weight: bold;
z-index: 2;
}
.progress-ring {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.progress-ring-circle {
fill: none;
stroke: #4CAF50;
stroke-width: 8;
stroke-linecap: round;
transform: rotate(-90deg);
transform-origin: 50% 50%;
transition: stroke 0.3s, stroke-dashoffset 0.3s;
}
.timer-controls {
display: flex;
justify-content: center;
gap: 15px;
flex-wrap: wrap;
}
.timer-controls input {
width: 80px;
padding: 10px;
border: none;
border-radius: 8px;
font-size: 1.2rem;
text-align: center;
}
.timer-controls button {
padding: 10px 25px;
border: none;
border-radius: 8px;
background: #4CAF50;
color: white;
font-size: 1.1rem;
cursor: pointer;
transition: all 0.3s;
}
.timer-controls button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.stages-section h2,
.sounds-section h2,
.student-picker h2 {
margin-bottom: 20px;
font-size: 1.5rem;
}
#stagesList {
margin-bottom: 15px;
}
.stage-item {
display: flex;
justify-content: space-between;
align-items: center;
background: rgba(255, 255, 255, 0.1);
padding: 10px 15px;
margin-bottom: 10px;
border-radius: 8px;
}
.stage-item button {
background: #f44336;
border: none;
color: white;
padding: 5px 10px;
border-radius: 5px;
cursor: pointer;
}
.add-stage {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.add-stage input {
flex: 1;
padding: 10px;
border: none;
border-radius: 8px;
font-size: 1rem;
}
.add-stage button {
padding: 10px 20px;
background: #2196F3;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
}
.sound-buttons {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
}
.sound-btn {
padding: 20px;
background: rgba(255, 255, 255, 0.2);
border: none;
border-radius: 10px;
color: white;
font-size: 1.2rem;
cursor: pointer;
transition: all 0.3s;
}
.sound-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: scale(1.05);
}
.student-picker textarea {
width: 100%;
height: 100px;
padding: 10px;
border: none;
border-radius: 8px;
margin-bottom: 15px;
font-size: 1rem;
resize: vertical;
}
.student-picker button {
width: 100%;
padding: 15px;
background: #FF9800;
color: white;
border: none;
border-radius: 8px;
font-size: 1.2rem;
cursor: pointer;
transition: all 0.3s;
}
.student-picker button:hover {
background: #F57C00;
}
.selected-student {
margin-top: 20px;
padding: 20px;
background: rgba(255, 255, 255, 0.2);
border-radius: 10px;
text-align: center;
font-size: 2rem;
font-weight: bold;
min-height: 80px;
display: flex;
align-items: center;
justify-content: center;
}
@media (max-width: 768px) {
main {
grid-template-columns: 1fr;
}
.timer-circle {
width: 250px;
height: 250px;
}
.timer-display {
font-size: 2.5rem;
}
}
```
**public/script.js**:
```javascript
// Audio setup
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
let isMuted = false;
// Sound functions
function playTone(frequency, duration, type = 'sine', volume = 0.5) {
if (isMuted) return;
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.type = type;
oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime);
gainNode.gain.setValueAtTime(volume, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + duration);
}
function playStartChime() {
playTone(523.25, 0.5, 'sine', 0.5); // C5
setTimeout(() => playTone(659.25, 0.5, 'sine', 0.5), 300); // E5
setTimeout(() => playTone(783.99, 0.8, 'sine', 0.5), 600); // G5
}
function playWarningSound() {
playTone(880, 0.2, 'square', 0.3);
setTimeout(() => playTone(880, 0.2, 'square', 0.3), 300);
}
function playTimeUpSound() {
playTone(523.25, 0.3, 'sine', 0.5);
setTimeout(() => playTone(523.25, 0.3, 'sine', 0.5), 300);
setTimeout(() => playTone(523.25, 0.5, 'sine', 0.5), 600);
setTimeout(() => playTone(659.25, 0.5, 'sine', 0.5), 900);
setTimeout(() => playTone(783.99, 0.8, 'sine', 0.5), 1200);
}
function playApplause() {
for (let i = 0; i < 10; i++) {
setTimeout(() => {
playTone(200 + Math.random() * 800, 0.1, 'noise', 0.3);
}, i * 100);
}
}
function playDing() {
playTone(1046.5, 0.5, 'sine', 0.5); // C6
setTimeout(() => playTone(1318.5, 0.8, 'sine', 0.5), 200); // E6
}
function playErrorSound() {
playTone(200, 0.3, 'square', 0.3);
setTimeout(() => playTone(150, 0.5, 'square', 0.3), 300);
}
function playMusic() {
const notes = [523.25, 659.25, 783.99, 1046.5];
notes.forEach((note, index) => {
setTimeout(() => playTone(note, 0.3, 'sine', 0.4), index * 200);
});
}
function playSuspenseSound() {
playTone(400, 0.2, 'sine', 0.3);
setTimeout(() => playTone(450, 0.2, 'sine', 0.3), 200);
setTimeout(() => playTone(500, 0.2, 'sine', 0.3), 400);
setTimeout(() => playTone(600, 0.5, 'sine', 0.4), 600);
}
// Timer logic
let timerInterval;
let remainingTime = 45 * 60; // 45 minutes in seconds
let totalTime = 45 * 60;
let isRunning = false;
let currentStage = null;
const minutesDisplay = document.getElementById('minutes');
const secondsDisplay = document.getElementById('seconds');
const timerInput = document.getElementById('timerInput');
const startBtn = document.getElementById('startBtn');
const pauseBtn = document.getElementById('pauseBtn');
const resetBtn = document.getElementById('resetBtn');
const muteBtn = document.getElementById('muteBtn');
const timerCircle = document.getElementById('timerCircle');
const progressRing = document.querySelector('.progress-ring-circle');
const circumference = 2 * Math.PI * 90;
progressRing.style.strokeDasharray = `${circumference} ${circumference}`;
progressRing.style.strokeDashoffset = 0;
function updateTimerDisplay() {
const minutes = Math.floor(remainingTime / 60);
const seconds = remainingTime % 60;
minutesDisplay.textContent = String(minutes).padStart(2, '0');
secondsDisplay.textContent = String(seconds).padStart(2, '0');
// Update progress ring
const progress = remainingTime / totalTime;
const offset = circumference * (1 - progress);
progressRing.style.strokeDashoffset = offset;
// Change color based on time
if (progress > 0.5) {
progressRing.style.stroke = '#4CAF50'; // Green
} else if (progress > 0.2) {
progressRing.style.stroke = '#FFC107'; // Yellow
} else {
progressRing.style.stroke = '#F44336'; // Red
}
}
function startTimer() {
if (!isRunning && remainingTime > 0) {
isRunning = true;
playStartChime();
timerInterval = setInterval(() => {
remainingTime--;
updateTimerDisplay();
// Warning at last minute
if (remainingTime === 60) {
playWarningSound();
}
// Time's up
if (remainingTime <= 0) {
clearInterval(timerInterval);
isRunning = false;
playTimeUpSound();
alert('انتهى الوقت!');
}
}, 1000);
}
}
function pauseTimer() {
if (isRunning) {
clearInterval(timerInterval);
isRunning = false;
}
}
function resetTimer() {
clearInterval(timerInterval);
isRunning = false;
totalTime = parseInt(timerInput.value) * 60;
remainingTime = totalTime;
updateTimerDisplay();
}
// Event listeners
startBtn.addEventListener('click', startTimer);
pauseBtn.addEventListener('click', pauseTimer);
resetBtn.addEventListener('click', resetTimer);
muteBtn.addEventListener('click', () => {
isMuted = !isMuted;
muteBtn.textContent = isMuted ? '🔇 تشغيل الصوت' : '🔊 كتم الصوت';
});
// Stage management
const stagesList = document.getElementById('stagesList');
const stageNameInput = document.getElementById('stageName');
const stageDurationInput = document.getElementById('stageDuration');
const addStageBtn = document.getElementById('addStageBtn');
let stages = JSON.parse(localStorage.getItem('stages') || '[]');
function renderStages() {
stagesList.innerHTML = '';
stages.forEach((stage, index) => {
const stageItem = document.createElement('div');
stageItem.className = 'stage-item';
stageItem.innerHTML = `
<span>${stage.name} (${stage.duration} دقائق)</span>
<div>
<button onclick="runStage(${index})">▶ تشغيل</button>
<button onclick="deleteStage(${index})">🗑 حذف</button>
</div>
`;
stagesList.appendChild(stageItem);
});
}
function addStage() {
const name = stageNameInput.value.trim();
const duration = parseInt(stageDurationInput.value);
if (name && duration > 0) {
stages.push({ name, duration });
localStorage.setItem('stages', JSON.stringify(stages));
renderStages();
stageNameInput.value = '';
stageDurationInput.value = '';
}
}
function deleteStage(index) {
stages.splice(index, 1);
localStorage.setItem('stages', JSON.stringify(stages));
renderStages();
}
function runStage(index) {
const stage = stages[index];
pauseTimer();
totalTime = stage.duration * 60;
remainingTime = totalTime;
timerInput.value = stage.duration;
updateTimerDisplay();
startTimer();
alert(`بدء مرحلة: ${stage.name}`);
}
addStageBtn.addEventListener('click', addStage);
// Student picker
const studentsInput = document.getElementById('studentsInput');
const pickStudentBtn = document.getElementById('pickStudentBtn');
const selectedStudent = document.getElementById('selectedStudent');
pickStudentBtn.addEventListener('click', () => {
const students = studentsInput.value.split('\n').filter(name => name.trim());
if (students.length > 0) {
playSuspenseSound();
const randomIndex = Math.floor(Math.random() * students.length);
selectedStudent.textContent = students[randomIndex];
} else {
selectedStudent.textContent = 'الرجاء إدخال أسماء الطلاب أولاً';
}
});
// Sound buttons
document.querySelectorAll('.sound-btn').forEach(button => {
button.addEventListener('click', () => {
const sound = button.dataset.sound;
switch(sound) {
case 'applause':
playApplause();
break;
case 'ding':
playDing();
break;
case 'error':
playErrorSound();
break;
case 'music':
playMusic();
break;
}
});
});
// Initialize
updateTimerDisplay();
renderStages();
```
---
**ملف package.json**:
```json
{
"name": "smart-classroom-timer",
"version": "1.0.0",
"description": "مؤقت الفصل الذكي للمعلمين",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.18.2"
}
}
```
---
**تعليمات النشر**:
1. **محلياً**:
- قم بتثبيت Node.js
- شغّل `npm install` ثم `npm start`
- افتح المتصفح على `http://localhost:3000`
2. **على منصة Render**:
- ارفع المشروع إلى GitHub
- أنشئ خدمة Web Service جديدة على Render
- اربط المستودع، وحدد `npm start` كأمر التشغيل
3. **على منصة Heroku**:
- ارفع المشروع إلى GitHub
- أنشئ تطبيقاً جديداً واربط المستودع
- فعّل النشر التلقائي
التطبيق جاهز للاستخدام المباشر في الفصل الدراسي، مع دعم كامل للغة العربية وواجهة سهلة الاستخدام على الشاشات الكبيرة.
Iniciá sesión para ver el prompt completo
Continuar con:
Al iniciar sesión, aceptás nuestros Términos de uso y Política de privacidad
Uso
Este prompt está diseñado para usarse con education. Copiá el contenido de arriba y pegalo en tu herramienta de IA preferida.
Para mejores resultados, personalizá los marcadores (indicados con corchetes o mayúsculas) con tus requisitos específicos.
Referencias
- Categoría: Prompts de education
- Fuente: https://x.com/AbeerAlhasan/status/2104541640811806903
Discusión
0 comentarios