Opera8 commited on
Commit
1768ef0
·
verified ·
1 Parent(s): bae13a2

Upload index (1) (5).html

Browse files
Files changed (1) hide show
  1. index (1) (5).html +559 -0
index (1) (5).html ADDED
@@ -0,0 +1,559 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fa" dir="rtl">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
6
+ <title>آوا هوش - جعبه ابزار صدا</title>
7
+
8
+ <!-- Tailwind CSS -->
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+
11
+ <!-- Fonts -->
12
+ <link rel="preconnect" href="https://fonts.googleapis.com">
13
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
14
+ <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100..900&display=swap" rel="stylesheet">
15
+
16
+ <!-- Babel for JSX transformation in browser -->
17
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
18
+
19
+ <style>
20
+ body {
21
+ font-family: 'Vazirmatn', sans-serif;
22
+ background-color: #0f172a;
23
+ color: white;
24
+ -webkit-tap-highlight-color: transparent;
25
+ overflow-x: hidden;
26
+ }
27
+ ::-webkit-scrollbar {
28
+ width: 6px;
29
+ }
30
+ ::-webkit-scrollbar-track {
31
+ background: #0f172a;
32
+ }
33
+ ::-webkit-scrollbar-thumb {
34
+ background: #334155;
35
+ border-radius: 3px;
36
+ }
37
+ ::-webkit-scrollbar-thumb:hover {
38
+ background: #475569;
39
+ }
40
+ /* Custom Animations */
41
+ @keyframes gradient {
42
+ 0% { background-position: 0% 50%; }
43
+ 50% { background-position: 100% 50%; }
44
+ 100% { background-position: 0% 50%; }
45
+ }
46
+ .animate-gradient-x {
47
+ animation: gradient 3s ease infinite;
48
+ }
49
+
50
+ .glass-panel {
51
+ background: rgba(19, 23, 34, 0.8);
52
+ backdrop-filter: blur(12px);
53
+ -webkit-backdrop-filter: blur(12px);
54
+ border: 1px solid rgba(255, 255, 255, 0.05);
55
+ }
56
+ </style>
57
+
58
+ <!-- Import Map to resolve modules -->
59
+ <script type="importmap">
60
+ {
61
+ "imports": {
62
+ "react": "https://esm.sh/react@18.2.0",
63
+ "react-dom/client": "https://esm.sh/react-dom@18.2.0/client",
64
+ "framer-motion": "https://esm.sh/framer-motion@10.16.4",
65
+ "lucide-react": "https://esm.sh/lucide-react@0.292.0",
66
+ "react-dom/": "https://esm.sh/react-dom@^19.2.4/",
67
+ "react/": "https://esm.sh/react@^19.2.4/"
68
+ }
69
+ }
70
+ </script>
71
+ </head>
72
+ <body>
73
+ <div id="root"></div>
74
+
75
+ <!-- MAIN APPLICATION SCRIPT -->
76
+ <script type="text/babel" data-type="module">
77
+ import React, { useState, useEffect } from 'react';
78
+ import ReactDOM from 'react-dom/client';
79
+ import { motion, AnimatePresence } from 'framer-motion';
80
+ import {
81
+ Mic2,
82
+ Wand2,
83
+ Podcast,
84
+ Fingerprint,
85
+ Activity,
86
+ Music,
87
+ Settings,
88
+ User,
89
+ Bell,
90
+ ArrowLeft,
91
+ Sparkles,
92
+ Play,
93
+ Square,
94
+ Volume2,
95
+ X
96
+ } from 'lucide-react';
97
+
98
+ // --- CONSTANTS & DATA ---
99
+ const APP_NAME = "آوا هوش";
100
+
101
+ const FEATURES = [
102
+ {
103
+ id: 'tts',
104
+ title: 'تبدیل متن به گفتار',
105
+ subtitle: '۳۰ گوینده حرفه‌ای',
106
+ icon: Mic2,
107
+ colorFrom: 'from-blue-500',
108
+ colorTo: 'to-cyan-400',
109
+ isHot: true
110
+ },
111
+ {
112
+ id: 'voice-changer',
113
+ title: 'تغییر صدا',
114
+ subtitle: 'مدل‌های جذاب فارسی',
115
+ icon: Wand2,
116
+ colorFrom: 'from-violet-500',
117
+ colorTo: 'to-purple-500'
118
+ },
119
+ {
120
+ id: 'podcast',
121
+ title: 'ساخت پادکست',
122
+ subtitle: 'تولید خودکار با هوش مصنوعی',
123
+ icon: Podcast,
124
+ colorFrom: 'from-pink-500',
125
+ colorTo: 'to-rose-500'
126
+ },
127
+ {
128
+ id: 'clone',
129
+ title: 'کلون کردن صدا',
130
+ subtitle: 'شبیه‌سازی دقیق صدا',
131
+ icon: Fingerprint,
132
+ colorFrom: 'from-amber-500',
133
+ colorTo: 'to-orange-500',
134
+ isNew: true
135
+ },
136
+ {
137
+ id: 'enhance',
138
+ title: 'افزایش کیفیت',
139
+ subtitle: 'حذف نویز و شفاف‌سازی',
140
+ icon: Activity,
141
+ colorFrom: 'from-emerald-500',
142
+ colorTo: 'to-green-400'
143
+ }
144
+ ];
145
+
146
+ const SPECIAL_FEATURE = {
147
+ id: 'ai-gen',
148
+ title: 'تولید صدا Ai',
149
+ subtitle: 'خلق افکت‌های صوتی خاص',
150
+ icon: Music,
151
+ colorFrom: 'from-indigo-600',
152
+ colorTo: 'to-blue-600'
153
+ };
154
+
155
+ const IMAGES = [
156
+ "https://app.puzzley.net/uploads/user/Jydo/%D8%AA%D8%BA%DB%8C%D8%B1%20%D8%B5%D8%AF%D8%A7%20%D8%A8%D8%A7%20%D9%87%D9%88%D8%B4%20%D9%85%D8%B5%D9%86%D9%88%D8%B9%DB%8C/tmpxposlxsv.png?_t=1769590682",
157
+ "https://app.puzzley.net/uploads/user/Jydo/%D8%AA%D8%BA%DB%8C%D8%B1%20%D8%B5%D8%AF%D8%A7%20%D8%A8%D8%A7%20%D9%87%D9%88%D8%B4%20%D9%85%D8%B5%D9%86%D9%88%D8%B9%DB%8C/tmpnv5v143z.png?_t=1769590682",
158
+ "https://app.puzzley.net/uploads/user/Jydo/%D8%AA%D8%BA%DB%8C%D8%B1%20%D8%B5%D8%AF%D8%A7%20%D8%A8%D8%A7%20%D9%87%D9%88%D8%B4%20%D9%85%D8%B5%D9%86%D9%88%D8%B9%DB%8C/tmpkqpm8k8l.png?_t=1769590756"
159
+ ];
160
+
161
+ // --- COMPONENTS ---
162
+
163
+ // 1. Background Effects
164
+ const Particle = ({ index }) => {
165
+ const randomX = Math.random() * 100;
166
+ const randomDelay = Math.random() * 5;
167
+ const randomDuration = 10 + Math.random() * 10;
168
+
169
+ return (
170
+ <motion.div
171
+ className="absolute w-1 h-1 bg-white rounded-full opacity-0"
172
+ initial={{ x: `${randomX}vw`, y: '110vh', opacity: 0 }}
173
+ animate={{
174
+ y: '-10vh',
175
+ opacity: [0, 0.3, 0]
176
+ }}
177
+ transition={{
178
+ duration: randomDuration,
179
+ repeat: Infinity,
180
+ delay: randomDelay,
181
+ ease: "linear"
182
+ }}
183
+ style={{
184
+ left: 0,
185
+ filter: 'blur(1px)'
186
+ }}
187
+ />
188
+ );
189
+ };
190
+
191
+ const BackgroundEffects = () => {
192
+ return (
193
+ <div className="fixed inset-0 z-0 overflow-hidden pointer-events-none bg-[#0B0F19]">
194
+ <div
195
+ className="absolute inset-0 opacity-[0.04]"
196
+ style={{
197
+ backgroundImage: `linear-gradient(#fff 1px, transparent 1px), linear-gradient(90deg, #fff 1px, transparent 1px)`,
198
+ backgroundSize: '50px 50px'
199
+ }}
200
+ ></div>
201
+ {[...Array(15)].map((_, i) => <Particle key={i} index={i} />)}
202
+ <motion.div
203
+ animate={{ scale: [1, 1.15, 1], opacity: [0.15, 0.35, 0.15], rotate: [0, 20, 0] }}
204
+ transition={{ duration: 12, repeat: Infinity, ease: "easeInOut" }}
205
+ className="absolute -top-[10%] -right-[20%] w-[600px] h-[600px] bg-gradient-to-br from-violet-600/20 to-indigo-600/20 rounded-full blur-[120px]"
206
+ />
207
+ <motion.div
208
+ animate={{ scale: [1, 1.25, 1], opacity: [0.1, 0.25, 0.1], x: [0, 30, 0] }}
209
+ transition={{ duration: 15, repeat: Infinity, ease: "easeInOut", delay: 1 }}
210
+ className="absolute top-[40%] -left-[20%] w-[500px] h-[500px] bg-gradient-to-tr from-blue-600/15 to-cyan-500/15 rounded-full blur-[100px]"
211
+ />
212
+ <div className="absolute inset-0 bg-gradient-to-b from-transparent via-[#0B0F19]/60 to-[#0B0F19] pointer-events-none"></div>
213
+ </div>
214
+ );
215
+ };
216
+
217
+ // 2. Header
218
+ const Header = () => {
219
+ return (
220
+ <header className="relative z-20 flex flex-col items-center justify-center pt-8 pb-4">
221
+ <motion.div
222
+ initial={{ y: -20, opacity: 0 }}
223
+ animate={{ y: 0, opacity: 1 }}
224
+ transition={{ duration: 0.6, ease: "easeOut" }}
225
+ className="flex flex-col items-center gap-4"
226
+ >
227
+ <div className="relative group cursor-pointer">
228
+ <div className="w-16 h-16 rounded-2xl bg-gradient-to-br from-violet-600 to-indigo-600 flex items-center justify-center shadow-2xl shadow-indigo-500/40 ring-4 ring-white/5 transition-transform duration-500 hover:scale-105">
229
+ <span className="text-4xl font-black text-white pb-2">آ</span>
230
+ </div>
231
+ <span className="absolute -top-1 -right-1 flex h-4 w-4">
232
+ <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75"></span>
233
+ <span className="relative inline-flex rounded-full h-4 w-4 bg-cyan-500 border-4 border-[#0B0F19]"></span>
234
+ </span>
235
+ </div>
236
+ <h1 className="text-xl font-bold text-slate-200 tracking-wide opacity-90">{APP_NAME}</h1>
237
+ </motion.div>
238
+ </header>
239
+ );
240
+ };
241
+
242
+ // 3. Hero
243
+ const Hero = () => {
244
+ return (
245
+ <div className="px-6 pt-2 pb-8 mb-2 relative z-10 text-center">
246
+ <motion.div
247
+ initial={{ opacity: 0, y: 20 }}
248
+ animate={{ opacity: 1, y: 0 }}
249
+ transition={{ duration: 0.8, ease: "easeOut", delay: 0.2 }}
250
+ >
251
+ <h2 className="text-[2.2rem] font-black text-white mb-4 leading-[1.3] tracking-tight">
252
+ دنیای صدا را <br />
253
+ <span className="relative inline-block px-2">
254
+ <span className="absolute inset-0 bg-indigo-500/10 blur-xl rounded-full transform rotate-3"></span>
255
+ <span
256
+ className="relative text-transparent bg-clip-text bg-gradient-to-r from-indigo-300 via-purple-300 to-cyan-300 animate-gradient-x"
257
+ style={{ backgroundSize: '200% auto' }}
258
+ >
259
+ با هوش مصنوعی
260
+ </span>
261
+ </span>
262
+ <br/>
263
+ <span className="text-white">متحول کنید</span>
264
+ </h2>
265
+
266
+ <p className="text-slate-400 text-sm leading-7 font-light max-w-[80%] mx-auto opacity-80">
267
+ تکنولوژی پیشرفته برای خلق، ویرایش و تبدیل صدا
268
+ </p>
269
+ </motion.div>
270
+ </div>
271
+ );
272
+ };
273
+
274
+ // 4. Feature Card
275
+ const FeatureCard = ({ item, index, onClick }) => {
276
+ return (
277
+ <motion.div
278
+ initial={{ opacity: 0, scale: 0.9, y: 30 }}
279
+ animate={{ opacity: 1, scale: 1, y: 0 }}
280
+ transition={{ delay: index * 0.1 + 0.2, duration: 0.5, type: "spring", stiffness: 100, damping: 20 }}
281
+ whileTap={{ scale: 0.96 }}
282
+ onClick={onClick}
283
+ className="relative group cursor-pointer"
284
+ >
285
+ <div className={`absolute -inset-[1px] rounded-[24px] bg-gradient-to-b ${item.colorFrom} ${item.colorTo} opacity-0 group-hover:opacity-40 blur-md transition duration-500`}></div>
286
+ <div className="relative h-full flex flex-col justify-between bg-[#131722]/80 backdrop-blur-xl border border-white/5 p-5 rounded-[24px] shadow-2xl overflow-hidden hover:border-white/15 transition-all duration-300">
287
+ <div className="absolute inset-0 z-0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-1000 bg-gradient-to-r from-transparent via-white/5 to-transparent skew-x-12"></div>
288
+ <div className="flex justify-between items-start mb-5 relative z-10">
289
+ <div className={`relative p-3.5 rounded-2xl bg-gradient-to-br ${item.colorFrom} ${item.colorTo} shadow-lg ring-1 ring-white/20 group-hover:scale-105 transition-transform duration-300`}>
290
+ <motion.div
291
+ animate={{ rotate: [0, 5, -5, 0] }}
292
+ transition={{ duration: 4, repeat: Infinity, ease: "easeInOut", delay: index * 0.5 }}
293
+ >
294
+ <item.icon className="text-white w-6 h-6 relative z-10" strokeWidth={2} />
295
+ </motion.div>
296
+ <div className="absolute inset-0 rounded-2xl bg-white/30 blur opacity-40"></div>
297
+ </div>
298
+ {(item.isNew || item.isHot) && (
299
+ <motion.div
300
+ initial={{ scale: 0 }}
301
+ animate={{ scale: 1 }}
302
+ transition={{ delay: 0.5 + index * 0.1, type: "spring" }}
303
+ className="flex flex-col items-end gap-1"
304
+ >
305
+ {item.isNew && (
306
+ <span className="px-2.5 py-1 text-[9px] font-bold bg-gradient-to-r from-amber-400 to-orange-500 text-white rounded-full shadow-lg shadow-amber-500/20">جدید</span>
307
+ )}
308
+ {item.isHot && (
309
+ <span className="px-2.5 py-1 text-[9px] font-bold bg-gradient-to-r from-rose-500 to-pink-600 text-white rounded-full shadow-lg shadow-rose-500/20">داغ</span>
310
+ )}
311
+ </motion.div>
312
+ )}
313
+ </div>
314
+ <div className="relative z-10">
315
+ <h3 className="text-[17px] font-bold text-white mb-1.5 tracking-tight group-hover:text-transparent group-hover:bg-clip-text group-hover:bg-gradient-to-r group-hover:from-white group-hover:to-slate-300 transition-colors">{item.title}</h3>
316
+ <p className="text-[11px] text-slate-400 font-medium leading-relaxed opacity-80 group-hover:opacity-100 transition-opacity">{item.subtitle}</p>
317
+ </div>
318
+ <div className="absolute bottom-4 left-4 w-8 h-8 rounded-full bg-white/5 border border-white/5 flex items-center justify-center opacity-0 translate-y-4 group-hover:opacity-100 group-hover:translate-y-0 transition-all duration-300 shadow-lg">
319
+ <ArrowLeft size={14} className="text-white" />
320
+ </div>
321
+ </div>
322
+ </motion.div>
323
+ );
324
+ };
325
+
326
+ // 5. Special Card
327
+ const SpecialCard = ({ item }) => {
328
+ return (
329
+ <motion.div
330
+ initial={{ opacity: 0, scale: 0.95, y: 20 }}
331
+ animate={{ opacity: 1, scale: 1, y: 0 }}
332
+ transition={{ delay: 0.6, duration: 0.6, ease: "easeOut" }}
333
+ whileTap={{ scale: 0.98 }}
334
+ className="relative w-full cursor-pointer group"
335
+ >
336
+ <div className="absolute -inset-[2px] bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 rounded-[26px] opacity-70 blur-sm group-hover:opacity-100 group-hover:blur-md transition duration-500 animate-pulse"></div>
337
+ <div className="relative overflow-hidden p-6 bg-[#0f1219] rounded-[24px] border border-white/10">
338
+ <div className="absolute inset-0 opacity-20">
339
+ <div className="absolute top-0 right-0 w-64 h-64 bg-indigo-600 rounded-full blur-[80px] animate-pulse"></div>
340
+ <div className="absolute bottom-0 left-0 w-64 h-64 bg-purple-600 rounded-full blur-[80px] animate-pulse" style={{ animationDelay: '1s' }}></div>
341
+ </div>
342
+ <div className="relative z-10 flex flex-col sm:flex-row sm:items-center justify-between gap-4">
343
+ <div className="flex items-center gap-5">
344
+ <div className="relative">
345
+ <div className={`w-16 h-16 rounded-2xl bg-gradient-to-br ${item.colorFrom} ${item.colorTo} flex items-center justify-center shadow-lg shadow-indigo-500/30 ring-4 ring-indigo-500/10 group-hover:scale-105 transition-transform duration-300`}>
346
+ <motion.div animate={{ rotate: [0, 10, -10, 0] }} transition={{ duration: 5, repeat: Infinity, ease: "easeInOut" }}>
347
+ <item.icon className="text-white w-8 h-8" strokeWidth={2.5} />
348
+ </motion.div>
349
+ </div>
350
+ <div className="absolute -top-2 -right-2 bg-white text-indigo-700 text-[10px] font-black px-2 py-0.5 rounded-full shadow-md border-2 border-[#0f1219]">Ai</div>
351
+ </div>
352
+ <div>
353
+ <div className="flex items-center gap-2 mb-1">
354
+ <h3 className="text-xl font-black text-white">{item.title}</h3>
355
+ <motion.div animate={{ opacity: [0.5, 1, 0.5], scale: [1, 1.2, 1] }} transition={{ duration: 2, repeat: Infinity }}>
356
+ <Sparkles className="w-5 h-5 text-yellow-400 fill-yellow-400" />
357
+ </motion.div>
358
+ </div>
359
+ <p className="text-sm text-slate-300 font-medium opacity-90 max-w-[200px] leading-relaxed">{item.subtitle}</p>
360
+ </div>
361
+ </div>
362
+ <div className="self-end sm:self-center">
363
+ <div className="w-12 h-12 rounded-full bg-white/10 hover:bg-white text-white hover:text-indigo-900 flex items-center justify-center border border-white/10 transition-all duration-300 group-hover:rotate-[-45deg]">
364
+ <ArrowLeft className="w-5 h-5" strokeWidth={3} />
365
+ </div>
366
+ </div>
367
+ </div>
368
+ </div>
369
+ </motion.div>
370
+ );
371
+ };
372
+
373
+ // 6. Image Slider
374
+ const ImageSlider = () => {
375
+ const [currentIndex, setCurrentIndex] = useState(0);
376
+ useEffect(() => {
377
+ const timer = setInterval(() => {
378
+ setCurrentIndex((prev) => (prev + 1) % IMAGES.length);
379
+ }, 4000);
380
+ return () => clearInterval(timer);
381
+ }, []);
382
+ return (
383
+ <div className="relative w-full aspect-[2/1] rounded-[24px] overflow-hidden shadow-2xl ring-1 ring-white/10 mb-2 group z-20">
384
+ <AnimatePresence mode='popLayout'>
385
+ <motion.img
386
+ key={currentIndex}
387
+ src={IMAGES[currentIndex]}
388
+ alt={`Slide ${currentIndex + 1}`}
389
+ initial={{ opacity: 0, scale: 1.1 }}
390
+ animate={{ opacity: 1, scale: 1 }}
391
+ exit={{ opacity: 0 }}
392
+ transition={{ duration: 0.7 }}
393
+ className="absolute inset-0 w-full h-full object-cover"
394
+ />
395
+ </AnimatePresence>
396
+ <div className="absolute inset-0 bg-gradient-to-t from-[#0B0F19]/80 via-transparent to-transparent opacity-80"></div>
397
+ <div className="absolute bottom-3 left-1/2 -translate-x-1/2 flex gap-1.5 z-10">
398
+ {IMAGES.map((_, index) => (
399
+ <div key={index} className={`h-1.5 rounded-full transition-all duration-300 ${index === currentIndex ? 'w-6 bg-white' : 'w-1.5 bg-white/40'}`} />
400
+ ))}
401
+ </div>
402
+ </div>
403
+ );
404
+ };
405
+
406
+ // 7. TTS Overlay (Text to Speech Feature)
407
+ const TTSOverlay = ({ onClose }) => {
408
+ const [text, setText] = useState('');
409
+ const [speaking, setSpeaking] = useState(false);
410
+
411
+ const speak = () => {
412
+ if (!text) return;
413
+ window.speechSynthesis.cancel();
414
+ // Create utterance
415
+ const u = new SpeechSynthesisUtterance(text);
416
+ // Attempt to use a Persian voice if available, otherwise default
417
+ // iOS/Android usually select based on lang code
418
+ u.lang = 'fa-IR';
419
+ u.rate = 0.9;
420
+
421
+ u.onstart = () => setSpeaking(true);
422
+ u.onend = () => setSpeaking(false);
423
+ u.onerror = () => setSpeaking(false);
424
+
425
+ window.speechSynthesis.speak(u);
426
+ };
427
+
428
+ const stop = () => {
429
+ window.speechSynthesis.cancel();
430
+ setSpeaking(false);
431
+ };
432
+
433
+ return (
434
+ <motion.div
435
+ initial={{ opacity: 0, y: "100%" }}
436
+ animate={{ opacity: 1, y: 0 }}
437
+ exit={{ opacity: 0, y: "100%" }}
438
+ transition={{ type: "spring", damping: 25, stiffness: 200 }}
439
+ className="fixed inset-0 z-50 bg-[#0f172a] flex flex-col"
440
+ >
441
+ <BackgroundEffects />
442
+
443
+ {/* Header */}
444
+ <div className="relative z-10 px-6 py-4 flex items-center justify-between glass-panel border-b-0">
445
+ <button onClick={onClose} className="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center active:scale-95 transition-transform">
446
+ <ArrowLeft className="text-white" size={20} />
447
+ </button>
448
+ <h2 className="text-lg font-bold text-white">تبدیل متن به صدا</h2>
449
+ <div className="w-10"></div>
450
+ </div>
451
+
452
+ {/* Content */}
453
+ <div className="relative z-10 flex-1 p-6 flex flex-col gap-6">
454
+ <div className="flex-1 glass-panel rounded-3xl p-1 overflow-hidden shadow-2xl">
455
+ <textarea
456
+ className="w-full h-full bg-transparent p-5 text-right text-lg text-white placeholder-slate-400 focus:outline-none resize-none leading-loose"
457
+ placeholder="متن خود را اینجا بنویسید... (مثال: سلام، به آوا هوش خوش آمدید)"
458
+ value={text}
459
+ onChange={e => setText(e.target.value)}
460
+ />
461
+ </div>
462
+
463
+ {/* Controls */}
464
+ <div className="flex flex-col gap-4 mb-4">
465
+ <motion.button
466
+ whileTap={{ scale: 0.98 }}
467
+ onClick={speaking ? stop : speak}
468
+ className={`w-full py-5 rounded-2xl font-bold text-lg flex items-center justify-center gap-3 shadow-xl transition-all relative overflow-hidden ${speaking ? 'bg-rose-500' : 'bg-gradient-to-r from-blue-600 to-indigo-600'}`}
469
+ >
470
+ {speaking ? (
471
+ <>
472
+ <Square fill="currentColor" size={20} />
473
+ <span>توقف پخش</span>
474
+ <span className="absolute right-4 w-2 h-2 bg-white rounded-full animate-ping"></span>
475
+ </>
476
+ ) : (
477
+ <>
478
+ <Play fill="currentColor" size={24} />
479
+ <span>پخش صدا</span>
480
+ </>
481
+ )}
482
+ </motion.button>
483
+ </div>
484
+ </div>
485
+ </motion.div>
486
+ );
487
+ };
488
+
489
+ // --- MAIN APP COMPONENT ---
490
+ const App = () => {
491
+ const [activeFeature, setActiveFeature] = useState(null);
492
+
493
+ const handleFeatureClick = (id) => {
494
+ if (id === 'tts') {
495
+ setActiveFeature('tts');
496
+ } else {
497
+ // For other features just show a simple alert or log for now
498
+ console.log(`Feature ${id} clicked`);
499
+ }
500
+ };
501
+
502
+ return (
503
+ <div className="min-h-screen relative overflow-x-hidden pb-10">
504
+ <BackgroundEffects />
505
+
506
+ <main className="relative z-10 pt-2">
507
+ <Header />
508
+
509
+ <div className="px-6 mb-4">
510
+ <ImageSlider />
511
+ </div>
512
+
513
+ <Hero />
514
+
515
+ <div className="px-6 mt-4">
516
+ <div className="grid grid-cols-2 gap-5">
517
+ {FEATURES.map((item, index) => (
518
+ <FeatureCard
519
+ key={item.id}
520
+ item={item}
521
+ index={index}
522
+ onClick={() => handleFeatureClick(item.id)}
523
+ />
524
+ ))}
525
+ </div>
526
+
527
+ <div className="mt-8 mb-4">
528
+ <SpecialCard item={SPECIAL_FEATURE} />
529
+ </div>
530
+
531
+ <div className="text-center mt-8 opacity-40">
532
+ <p className="text-[10px] text-slate-300 font-light tracking-widest">
533
+ POWERED BY ALPHA • VER 2.0
534
+ </p>
535
+ </div>
536
+ </div>
537
+ </main>
538
+
539
+ {/* Overlays */}
540
+ <AnimatePresence>
541
+ {activeFeature === 'tts' && (
542
+ <TTSOverlay key="tts" onClose={() => setActiveFeature(null)} />
543
+ )}
544
+ </AnimatePresence>
545
+ </div>
546
+ );
547
+ };
548
+
549
+ // --- RENDER ---
550
+ const rootElement = document.getElementById('root');
551
+ const root = ReactDOM.createRoot(rootElement);
552
+ root.render(
553
+ <React.StrictMode>
554
+ <App />
555
+ </React.StrictMode>
556
+ );
557
+ </script>
558
+ </body>
559
+ </html>