EGYADMIN commited on
Commit
a81155a
·
verified ·
1 Parent(s): f268115

Delete static

Browse files
static/css/enhanced-styles.css DELETED
@@ -1,913 +0,0 @@
1
- /* أنماط CSS المحسنة للنظام - تم التحديث 2025 */
2
- @import url('https://fonts.googleapis.com/css2?family=Almarai:wght@300;400;700;800&family=Cairo:wght@200;300;400;500;600;700;800;900&family=Tajawal:wght@200;300;400;500;700;800;900&display=swap');
3
-
4
- :root {
5
- --primary-color: #0EA5A5; /* لون رئيسي جديد: فيروزي */
6
- --primary-light: rgba(14, 165, 165, 0.1);
7
- --primary-dark: #088585;
8
- --primary-gradient: linear-gradient(135deg, #0EA5A5, #088585);
9
- --secondary-color: #FF9A3C; /* لون ثانوي: برتقالي */
10
- --secondary-light: rgba(255, 154, 60, 0.1);
11
- --text-dark: #1d2b36;
12
- --text-medium: #3a4f5f;
13
- --text-light: #607d94;
14
- --background-light: #f8f9fa;
15
- --border-color: #e1e5ea;
16
- --danger-color: #e3342f;
17
- --success-color: #38c172;
18
- --warning-color: #f7b731;
19
- --info-color: #3490dc;
20
- --card-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
21
- --header-gradient: linear-gradient(120deg, #0EA5A5, #088585);
22
- --sidebar-gradient: linear-gradient(180deg, #1d2b36, #2d3a45);
23
- --border-radius: 10px;
24
- --transition-speed: 0.3s;
25
- }
26
-
27
- /* تعيين اتجاه النص من اليمين إلى اليسار للغة العربية */
28
- body {
29
- direction: rtl;
30
- text-align: right;
31
- font-family: 'Almarai', 'Tajawal', 'Cairo', sans-serif;
32
- color: var(--text-dark);
33
- background-color: #fafafa;
34
- /* التوافق مع جميع المتصفحات والأجهزة */
35
- -webkit-font-smoothing: antialiased;
36
- -moz-osx-font-smoothing: grayscale;
37
- text-rendering: optimizeLegibility;
38
- }
39
-
40
- /* أنماط العناوين */
41
- h1, h2, h3, h4, h5, h6 {
42
- font-family: 'Almarai', 'Tajawal', 'Cairo', sans-serif;
43
- color: var(--text-dark);
44
- font-weight: 700;
45
- line-height: 1.4;
46
- margin-bottom: 0.75rem;
47
- }
48
-
49
- /* أنماط العنوان الرئيسي بتدرج لوني */
50
- .main-title {
51
- background: var(--primary-gradient);
52
- -webkit-background-clip: text;
53
- background-clip: text;
54
- color: transparent;
55
- font-size: 2.25rem;
56
- font-weight: 800;
57
- text-align: center;
58
- margin: 1.5rem 0;
59
- padding: 0.5rem;
60
- position: relative;
61
- }
62
-
63
- .main-title::after {
64
- content: "";
65
- position: absolute;
66
- bottom: -5px;
67
- left: 30%;
68
- right: 30%;
69
- height: 3px;
70
- background: var(--primary-gradient);
71
- border-radius: 3px;
72
- }
73
-
74
- /* أنماط ترويسة الصفحة محسنة */
75
- .header-container {
76
- display: flex;
77
- flex-direction: row;
78
- justify-content: space-between;
79
- align-items: center;
80
- padding: 1rem 1.5rem;
81
- background: var(--header-gradient);
82
- border-radius: var(--border-radius);
83
- margin-bottom: 1.5rem;
84
- box-shadow: var(--card-shadow);
85
- color: white;
86
- }
87
-
88
- .header-title {
89
- margin-right: 1.25rem;
90
- }
91
-
92
- .header-title h1 {
93
- margin: 0;
94
- font-size: 1.75rem;
95
- color: white;
96
- font-weight: 800;
97
- }
98
-
99
- .header-title p {
100
- margin: 0.25rem 0 0 0;
101
- font-size: 0.9rem;
102
- color: rgba(255, 255, 255, 0.8);
103
- font-weight: 400;
104
- }
105
-
106
- .header-info {
107
- display: flex;
108
- align-items: center;
109
- }
110
-
111
- .date-box {
112
- display: flex;
113
- background-color: rgba(255, 255, 255, 0.2);
114
- border: 1px solid rgba(255, 255, 255, 0.3);
115
- color: white;
116
- border-radius: 8px;
117
- padding: 0.5rem 0.75rem;
118
- margin-left: 1rem;
119
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
120
- backdrop-filter: blur(5px);
121
- }
122
-
123
- .date-day {
124
- font-size: 1.75rem;
125
- font-weight: bold;
126
- margin-left: 0.5rem;
127
- line-height: 1;
128
- }
129
-
130
- .date-info {
131
- display: flex;
132
- flex-direction: column;
133
- font-size: 0.8rem;
134
- }
135
-
136
- .date-month {
137
- font-weight: bold;
138
- line-height: 1.2;
139
- }
140
-
141
- .date-year {
142
- line-height: 1;
143
- }
144
-
145
- /* أنماط قائمة التنقل الجديدة */
146
- .nav-menu {
147
- background-color: white;
148
- border-radius: var(--border-radius);
149
- padding: 0.5rem;
150
- box-shadow: var(--card-shadow);
151
- margin: 1rem 0;
152
- }
153
-
154
- .nav-menu ul {
155
- display: flex;
156
- list-style: none;
157
- padding: 0;
158
- margin: 0;
159
- justify-content: flex-end;
160
- flex-wrap: wrap;
161
- }
162
-
163
- .nav-menu li {
164
- margin: 0.25rem;
165
- }
166
-
167
- .nav-menu a {
168
- display: flex;
169
- align-items: center;
170
- color: var(--text-medium);
171
- text-decoration: none;
172
- padding: 0.5rem 0.75rem;
173
- border-radius: 6px;
174
- transition: all var(--transition-speed);
175
- font-weight: 500;
176
- border: 1px solid transparent;
177
- }
178
-
179
- .nav-menu a:hover {
180
- background-color: var(--primary-light);
181
- color: var(--primary-color);
182
- border-color: var(--primary-color);
183
- transform: translateY(-2px);
184
- }
185
-
186
- .nav-icon {
187
- margin-left: 0.5rem;
188
- font-size: 1.25rem;
189
- }
190
-
191
- /* أنماط عنوان الوحدة */
192
- .module-title {
193
- color: var(--text-dark);
194
- font-size: 1.75rem;
195
- margin-bottom: 1.25rem;
196
- border-right: 4px solid var(--primary-color);
197
- padding-right: 0.75rem;
198
- position: relative;
199
- }
200
-
201
- /* أنماط بطاقات المعلومات المحسنة */
202
- .info-card {
203
- background-color: white;
204
- border-radius: var(--border-radius);
205
- padding: 1.5rem;
206
- margin-bottom: 1.25rem;
207
- box-shadow: var(--card-shadow);
208
- border-top: 4px solid var(--primary-color);
209
- transition: transform var(--transition-speed);
210
- }
211
-
212
- .info-card:hover {
213
- transform: translateY(-5px);
214
- }
215
-
216
- .info-card h3 {
217
- color: var(--text-dark);
218
- margin-top: 0;
219
- margin-bottom: 0.75rem;
220
- font-weight: 700;
221
- }
222
-
223
- .info-card p {
224
- color: var(--text-medium);
225
- margin: 0;
226
- line-height: 1.6;
227
- }
228
-
229
- /* أنماط الجداول */
230
- .dataframe {
231
- width: 100%;
232
- border-collapse: separate;
233
- border-spacing: 0;
234
- margin-bottom: 1.5rem;
235
- border-radius: var(--border-radius);
236
- overflow: hidden;
237
- box-shadow: var(--card-shadow);
238
- }
239
-
240
- .dataframe th {
241
- background-color: var(--primary-color);
242
- color: white;
243
- text-align: right;
244
- padding: 0.75rem 1rem;
245
- font-weight: 600;
246
- border: none;
247
- }
248
-
249
- .dataframe td {
250
- padding: 0.75rem 1rem;
251
- border-bottom: 1px solid var(--border-color);
252
- text-align: right;
253
- background-color: white;
254
- }
255
-
256
- .dataframe tr:last-child td {
257
- border-bottom: none;
258
- }
259
-
260
- .dataframe tr:nth-child(even) td {
261
- background-color: rgba(248, 249, 250, 0.7);
262
- }
263
-
264
- .dataframe tr:hover td {
265
- background-color: var(--primary-light);
266
- }
267
-
268
- /* أنماط الأزرار الجديدة */
269
- button, .stButton>button {
270
- background: var(--primary-gradient);
271
- color: white;
272
- border: none;
273
- border-radius: 6px;
274
- padding: 0.6rem 1.25rem;
275
- cursor: pointer;
276
- transition: all var(--transition-speed);
277
- font-weight: 600;
278
- font-size: 0.95rem;
279
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
280
- display: inline-flex;
281
- align-items: center;
282
- justify-content: center;
283
- }
284
-
285
- button:hover, .stButton>button:hover {
286
- background: var(--primary-dark);
287
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
288
- transform: translateY(-2px);
289
- }
290
-
291
- button:active, .stButton>button:active {
292
- transform: translateY(0);
293
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
294
- }
295
-
296
- /* أزرار ثانوية */
297
- .btn-secondary, .stButton.secondary>button {
298
- background: white;
299
- color: var(--primary-color);
300
- border: 1px solid var(--primary-color);
301
- }
302
-
303
- .btn-secondary:hover, .stButton.secondary>button:hover {
304
- background: var(--primary-light);
305
- }
306
-
307
- /* أنماط المخططات */
308
- .plot-container {
309
- background-color: white;
310
- border-radius: var(--border-radius);
311
- padding: 1rem;
312
- margin: 1.25rem 0;
313
- box-shadow: var(--card-shadow);
314
- }
315
-
316
- /* أنماط بطاقات الابتكارات */
317
- .innovation-card {
318
- background-color: white;
319
- border-radius: var(--border-radius);
320
- padding: 1.5rem;
321
- margin-bottom: 1.25rem;
322
- border-right: 4px solid var(--primary-color);
323
- box-shadow: var(--card-shadow);
324
- transition: transform var(--transition-speed);
325
- }
326
-
327
- .innovation-card:hover {
328
- transform: translateY(-5px);
329
- }
330
-
331
- .innovation-icon {
332
- font-size: 2rem;
333
- margin-bottom: 0.75rem;
334
- background: var(--primary-gradient);
335
- -webkit-background-clip: text;
336
- background-clip: text;
337
- color: transparent;
338
- }
339
-
340
- .innovation-card h3 {
341
- color: var(--text-dark);
342
- margin-bottom: 0.75rem;
343
- font-weight: 700;
344
- }
345
-
346
- .innovation-card p {
347
- color: var(--text-medium);
348
- font-size: 0.95rem;
349
- line-height: 1.6;
350
- }
351
-
352
- /* أنماط فريق التطوير */
353
- .team-section {
354
- display: flex;
355
- flex-wrap: wrap;
356
- justify-content: center;
357
- gap: 1.5rem;
358
- margin: 2rem 0;
359
- }
360
-
361
- .team-member {
362
- text-align: center;
363
- margin-bottom: 1.25rem;
364
- background-color: white;
365
- border-radius: var(--border-radius);
366
- padding: 1.5rem;
367
- box-shadow: var(--card-shadow);
368
- transition: transform var(--transition-speed);
369
- width: 230px;
370
- }
371
-
372
- .team-member:hover {
373
- transform: translateY(-5px);
374
- }
375
-
376
- .team-member h3 {
377
- color: var(--text-dark);
378
- margin-bottom: 0.3rem;
379
- font-size: 1.1rem;
380
- font-weight: 700;
381
- }
382
-
383
- .team-member h4 {
384
- color: var(--primary-color);
385
- margin-top: 0;
386
- margin-bottom: 0.75rem;
387
- font-size: 0.9rem;
388
- }
389
-
390
- .team-member p {
391
- color: var(--text-medium);
392
- font-size: 0.85rem;
393
- line-height: 1.5;
394
- }
395
-
396
- .avatar {
397
- background: var(--primary-gradient);
398
- color: white;
399
- width: 90px;
400
- height: 90px;
401
- border-radius: 50%;
402
- display: flex;
403
- justify-content: center;
404
- align-items: center;
405
- margin: 0 auto 1rem auto;
406
- font-size: 2rem;
407
- font-weight: 700;
408
- box-shadow: 0 5px 15px rgba(14, 165, 165, 0.3);
409
- }
410
-
411
- /* أنماط تذييل الصفحة */
412
- .footer {
413
- text-align: center;
414
- color: var(--text-light);
415
- font-size: 0.85rem;
416
- margin-top: 2rem;
417
- margin-bottom: 1rem;
418
- padding: 1rem;
419
- border-top: 1px solid var(--border-color);
420
- }
421
-
422
- /* أنماط رسائل التنبيه المحسنة */
423
- .alert {
424
- padding: 1rem 1.25rem;
425
- border-radius: var(--border-radius);
426
- margin-bottom: 1rem;
427
- position: relative;
428
- border-right: 4px solid;
429
- }
430
-
431
- .alert-icon {
432
- margin-left: 0.5rem;
433
- font-size: 1.25rem;
434
- }
435
-
436
- .alert-info {
437
- background-color: rgba(52, 144, 220, 0.1);
438
- color: var(--info-color);
439
- border-right-color: var(--info-color);
440
- }
441
-
442
- .alert-success {
443
- background-color: rgba(56, 193, 114, 0.1);
444
- color: var(--success-color);
445
- border-right-color: var(--success-color);
446
- }
447
-
448
- .alert-warning {
449
- background-color: rgba(247, 183, 49, 0.1);
450
- color: var(--warning-color);
451
- border-right-color: var(--warning-color);
452
- }
453
-
454
- .alert-danger {
455
- background-color: rgba(227, 52, 47, 0.1);
456
- color: var(--danger-color);
457
- border-right-color: var(--danger-color);
458
- }
459
-
460
- /* أنماط التبويبات المحسنة */
461
- .stTabs [data-baseweb="tab-list"] {
462
- gap: 1px;
463
- background-color: var(--background-light);
464
- border-radius: var(--border-radius);
465
- padding: 0.3rem;
466
- }
467
-
468
- .stTabs [data-baseweb="tab"] {
469
- height: 50px;
470
- white-space: pre-wrap;
471
- background-color: white;
472
- border-radius: 6px;
473
- gap: 1px;
474
- padding: 0.6rem 1rem;
475
- font-family: 'Almarai', 'Tajawal', sans-serif;
476
- font-weight: 500;
477
- transition: all var(--transition-speed);
478
- }
479
-
480
- .stTabs [aria-selected="true"] {
481
- background: var(--primary-gradient) !important;
482
- color: white !important;
483
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
484
- }
485
-
486
- /* أنماط مخصصة لدعم اللغة العربية في إدخالات النصوص والأرقام */
487
- input, textarea, .stTextInput>div>div>input, .stNumberInput>div>div>input {
488
- direction: rtl;
489
- text-align: right;
490
- font-family: 'Almarai', 'Tajawal', sans-serif;
491
- font-size: 0.95rem;
492
- padding: 0.6rem 0.75rem;
493
- border-radius: 6px;
494
- border: 1px solid var(--border-color);
495
- transition: border-color var(--transition-speed);
496
- }
497
-
498
- input:focus, textarea:focus, .stTextInput>div>div>input:focus, .stNumberInput>div>div>input:focus {
499
- outline: none;
500
- border-color: var(--primary-color);
501
- box-shadow: 0 0 0 1px var(--primary-light);
502
- }
503
-
504
- /* أنماط قائمة الخيارات */
505
- .stSelectbox [data-baseweb="select"] {
506
- direction: rtl;
507
- text-align: right;
508
- font-family: 'Almarai', 'Tajawal', sans-serif;
509
- }
510
-
511
- /* أنماط للنسخة المحمولة والاستجابة للشاشات */
512
- @media (max-width: 992px) {
513
- .main-title {
514
- font-size: 1.75rem;
515
- }
516
-
517
- .header-container {
518
- padding: 1rem;
519
- }
520
-
521
- .header-title h1 {
522
- font-size: 1.5rem;
523
- }
524
- }
525
-
526
- @media (max-width: 768px) {
527
- .header-container {
528
- flex-direction: column;
529
- align-items: flex-start;
530
- }
531
-
532
- .header-info {
533
- margin-top: 1rem;
534
- width: 100%;
535
- justify-content: flex-start;
536
- }
537
-
538
- .nav-menu ul {
539
- flex-wrap: wrap;
540
- justify-content: flex-start;
541
- }
542
-
543
- .nav-menu li {
544
- margin-bottom: 0.5rem;
545
- margin-left: 0.5rem;
546
- width: calc(50% - 1rem);
547
- }
548
-
549
- .module-title {
550
- font-size: 1.5rem;
551
- }
552
-
553
- .main-title {
554
- font-size: 1.4rem;
555
- }
556
-
557
- .innovation-card, .info-card {
558
- margin-bottom: 1rem;
559
- padding: 1rem;
560
- }
561
-
562
- .dataframe {
563
- display: block;
564
- overflow-x: auto;
565
- }
566
-
567
- .team-member {
568
- width: 100%;
569
- }
570
- }
571
-
572
- @media (max-width: 480px) {
573
- .main-title {
574
- font-size: 1.25rem;
575
- }
576
-
577
- .header-title h1 {
578
- font-size: 1.25rem;
579
- }
580
-
581
- .nav-menu li {
582
- width: 100%;
583
- margin-left: 0;
584
- }
585
- }
586
-
587
- /* تحسينات خاصة للأيفون والأجهزة ذات الشاشات الصغيرة */
588
- @media only screen and (max-width: 375px) {
589
- .nav-menu {
590
- margin: 0.5rem 0;
591
- }
592
-
593
- button, .stButton>button {
594
- padding: 0.5rem 0.75rem;
595
- font-size: 0.9rem;
596
- }
597
-
598
- .module-title, .info-card h3, .innovation-card h3 {
599
- font-size: 1.1rem;
600
- }
601
- }
602
-
603
- /* أضف كلاس للأيقونات */
604
- .icon {
605
- font-size: 1.1rem;
606
- margin-left: 0.5rem;
607
- }
608
-
609
- /* أنماط للصور والخلفيات */
610
- .bg-light {
611
- background-color: var(--background-light);
612
- }
613
-
614
- .card {
615
- background: white;
616
- border-radius: var(--border-radius);
617
- box-shadow: var(--card-shadow);
618
- padding: 1.25rem;
619
- margin-bottom: 1.25rem;
620
- }
621
-
622
- /* قسم معلومات النظام */
623
- .about-system {
624
- margin: 2rem 0;
625
- background: white;
626
- border-radius: var(--border-radius);
627
- box-shadow: var(--card-shadow);
628
- padding: 1.5rem;
629
- }
630
-
631
- .about-system h2 {
632
- color: var(--primary-color);
633
- margin-bottom: 1rem;
634
- padding-bottom: 0.5rem;
635
- border-bottom: 2px solid var(--primary-light);
636
- }
637
-
638
- .about-system p {
639
- line-height: 1.6;
640
- margin-bottom: 1rem;
641
- }
642
-
643
- .about-system ul {
644
- padding-right: 1.5rem;
645
- margin-bottom: 1rem;
646
- }
647
-
648
- .about-system li {
649
- margin-bottom: 0.5rem;
650
- line-height: 1.6;
651
- }
652
-
653
- /* أنماط مؤشر التقدم */
654
- .progress {
655
- height: 0.5rem;
656
- overflow: hidden;
657
- background-color: var(--background-light);
658
- border-radius: 0.25rem;
659
- margin: 0.5rem 0 1rem 0;
660
- }
661
-
662
- .progress-bar {
663
- height: 100%;
664
- border-radius: 0.25rem;
665
- background: var(--primary-gradient);
666
- }
667
-
668
- /* المؤقت للمواعيد النهائية */
669
- .countdown-timer {
670
- display: flex;
671
- justify-content: center;
672
- gap: 1rem;
673
- margin: 1.5rem 0;
674
- }
675
-
676
- .time-block {
677
- background: white;
678
- border-radius: var(--border-radius);
679
- padding: 0.75rem 1rem;
680
- text-align: center;
681
- min-width: 80px;
682
- box-shadow: var(--card-shadow);
683
- }
684
-
685
- .time-value {
686
- font-size: 1.75rem;
687
- font-weight: 700;
688
- color: var(--primary-color);
689
- line-height: 1;
690
- }
691
-
692
- .time-label {
693
- font-size: 0.8rem;
694
- color: var(--text-medium);
695
- margin-top: 0.25rem;
696
- }
697
-
698
- /* إعدادات المستخدم */
699
- .settings-form {
700
- background: white;
701
- border-radius: var(--border-radius);
702
- padding: 1.5rem;
703
- box-shadow: var(--card-shadow);
704
- }
705
-
706
- .settings-group {
707
- margin-bottom: 1.5rem;
708
- }
709
-
710
- .settings-group h3 {
711
- font-size: 1.2rem;
712
- margin-bottom: 1rem;
713
- padding-bottom: 0.5rem;
714
- border-bottom: 1px solid var(--border-color);
715
- }
716
-
717
- .settings-item {
718
- margin-bottom: 1rem;
719
- }
720
-
721
- .settings-item label {
722
- display: block;
723
- margin-bottom: 0.5rem;
724
- font-weight: 500;
725
- }
726
-
727
- /* أنماط للتسعير المتقدم */
728
- .pricing-grid {
729
- display: grid;
730
- grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
731
- gap: 1.25rem;
732
- margin: 1.5rem 0;
733
- }
734
-
735
- .price-card {
736
- background: white;
737
- border-radius: var(--border-radius);
738
- padding: 1.25rem;
739
- box-shadow: var(--card-shadow);
740
- display: flex;
741
- flex-direction: column;
742
- }
743
-
744
- .price-header {
745
- margin-bottom: 1rem;
746
- padding-bottom: 0.5rem;
747
- border-bottom: 1px solid var(--border-color);
748
- }
749
-
750
- .price-value {
751
- font-size: 1.5rem;
752
- font-weight: 700;
753
- color: var(--primary-color);
754
- margin: 0.5rem 0;
755
- }
756
-
757
- .price-details {
758
- flex-grow: 1;
759
- }
760
-
761
- .price-details ul {
762
- padding-right: 1.25rem;
763
- margin-bottom: 1rem;
764
- }
765
-
766
- .price-details li {
767
- margin-bottom: 0.5rem;
768
- line-height: 1.5;
769
- }
770
-
771
- .price-footer {
772
- margin-top: auto;
773
- padding-top: 1rem;
774
- }
775
-
776
- /* أنماط إضافية للأيقونات والرموز */
777
- .colored-icon {
778
- background: var(--primary-gradient);
779
- -webkit-background-clip: text;
780
- background-clip: text;
781
- color: transparent;
782
- }
783
-
784
- /* أنماط الشعار */
785
- .logo {
786
- display: flex;
787
- align-items: center;
788
- }
789
-
790
- .logo-text {
791
- font-weight: 800;
792
- font-size: 1.25rem;
793
- margin-right: 0.5rem;
794
- background: var(--primary-gradient);
795
- -webkit-background-clip: text;
796
- background-clip: text;
797
- color: transparent;
798
- }
799
-
800
- /* كلاس للخط العريض */
801
- .bold {
802
- font-weight: 700;
803
- }
804
-
805
- /* تحسين مظهر مخطط مرمايد للنظام */
806
- .mermaid {
807
- margin: 1.5rem 0;
808
- }
809
-
810
- /* تعديلات على شكل العنصر الجانبي */
811
- .stSidebar {
812
- background-color: white;
813
- box-shadow: 2px 0 10px rgba(0, 0, 0, 0.05);
814
- }
815
-
816
- [data-testid="stSidebarContent"] {
817
- background: var(--sidebar-gradient);
818
- }
819
-
820
- /* تحسين شكل لوحة المعلومات */
821
- .dashboard-card {
822
- background: white;
823
- border-radius: var(--border-radius);
824
- padding: 1rem;
825
- box-shadow: var(--card-shadow);
826
- height: 100%;
827
- position: relative;
828
- overflow: hidden;
829
- }
830
-
831
- .dashboard-card::before {
832
- content: "";
833
- position: absolute;
834
- top: 0;
835
- left: 0;
836
- right: 0;
837
- height: 4px;
838
- background: var(--primary-gradient);
839
- }
840
-
841
- .dashboard-value {
842
- font-size: 2rem;
843
- font-weight: 800;
844
- color: var(--primary-color);
845
- margin: 0.5rem 0;
846
- }
847
-
848
- .dashboard-title {
849
- color: var(--text-medium);
850
- font-size: 0.9rem;
851
- margin-bottom: 0.5rem;
852
- font-weight: 600;
853
- }
854
-
855
- .dashboard-change {
856
- font-size: 0.8rem;
857
- display: flex;
858
- align-items: center;
859
- }
860
-
861
- .change-up {
862
- color: var(--success-color);
863
- }
864
-
865
- .change-down {
866
- color: var(--danger-color);
867
- }
868
-
869
- /* بالنسبة للشركة */
870
- .company-info {
871
- text-align: center;
872
- background: white;
873
- padding: 1rem;
874
- border-radius: var(--border-radius);
875
- margin: 1.5rem 0;
876
- box-shadow: var(--card-shadow);
877
- }
878
-
879
- .company-logo {
880
- max-width: 150px;
881
- margin: 0 auto 1rem auto;
882
- }
883
-
884
- .company-name {
885
- font-size: 1.2rem;
886
- font-weight: 700;
887
- color: var(--text-dark);
888
- margin-bottom: 0.5rem;
889
- }
890
-
891
- .company-slogan {
892
- font-size: 0.9rem;
893
- color: var(--text-medium);
894
- margin-bottom: 1rem;
895
- }
896
-
897
- .company-contact {
898
- display: flex;
899
- justify-content: center;
900
- gap: 1rem;
901
- margin-top: 1rem;
902
- }
903
-
904
- .contact-item {
905
- display: flex;
906
- align-items: center;
907
- font-size: 0.85rem;
908
- color: var(--text-medium);
909
- }
910
-
911
- .contact-icon {
912
- margin-left: 0.3rem;
913
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
static/css/rtl-fixes.css DELETED
@@ -1,66 +0,0 @@
1
- /* إصلاحات لدعم اللغة العربية والعرض من اليمين إلى اليسار */
2
-
3
- /* نقل الشريط الجانبي من اليسار إلى اليمين */
4
- [data-testid="stSidebar"] {
5
- right: 0;
6
- left: unset !important;
7
- }
8
-
9
- section[data-testid="stSidebarContent"] {
10
- direction: rtl !important;
11
- text-align: right !important;
12
- }
13
-
14
- /* تعديل الاتجاه للمحتوى الرئيسي */
15
- .main .block-container {
16
- direction: rtl;
17
- text-align: right;
18
- margin-left: 0;
19
- margin-right: 21rem;
20
- max-width: calc(100% - 21rem);
21
- }
22
-
23
- @media (max-width: 768px) {
24
- .main .block-container {
25
- margin-right: 0;
26
- max-width: 100%;
27
- }
28
- }
29
-
30
- /* تصحيح اتجاه النصوص والعناصر */
31
- .streamlit-expanderHeader,
32
- .stRadio > div,
33
- .stCheckbox > div,
34
- .stSelectbox > div,
35
- .stTextInput > div {
36
- direction: rtl;
37
- text-align: right;
38
- }
39
-
40
- /* تعديل قائمة الخيارات في streamlit_option_menu */
41
- .nav-link {
42
- text-align: right !important;
43
- }
44
-
45
- /* تحسين ظهور الجداول */
46
- [data-testid="stTable"] {
47
- direction: rtl;
48
- }
49
-
50
- /* تصحيح أزرار الأرقام والتواريخ */
51
- .stNumberInput [data-baseweb="input"],
52
- .stDateInput [data-baseweb="input"] {
53
- direction: ltr;
54
- }
55
-
56
- /* جعل عناصر الملاحظات والخانات النصية تدعم العربية */
57
- [data-testid="stMarkdown"], textarea {
58
- direction: rtl;
59
- text-align: right;
60
- }
61
-
62
- /* تحسين ظهور قوائم الاختيار */
63
- .stMultiSelect div:first-child,
64
- .stSelectbox div:first-child {
65
- text-align: right;
66
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
static/css/styles.css DELETED
@@ -1,373 +0,0 @@
1
- /* أنماط CSS للنظام */
2
-
3
- /* تعيين اتجاه النص من اليمين إلى اليسار للغة العربية */
4
- body {
5
- direction: rtl;
6
- text-align: right;
7
- font-family: 'Tajawal', 'Cairo', sans-serif;
8
- }
9
-
10
- /* أنماط العناوين */
11
- h1, h2, h3, h4, h5, h6 {
12
- font-family: 'Tajawal', 'Cairo', sans-serif;
13
- color: #333;
14
- }
15
-
16
- /* أنماط ترويسة الصفحة */
17
- .header-container {
18
- display: flex;
19
- flex-direction: row;
20
- justify-content: space-between;
21
- align-items: center;
22
- padding: 10px 0;
23
- background-color: #f8f9fa;
24
- border-radius: 10px;
25
- margin-bottom: 20px;
26
- }
27
-
28
- .header-title {
29
- margin-right: 20px;
30
- }
31
-
32
- .header-title h1 {
33
- margin: 0;
34
- font-size: 24px;
35
- color: #2c3e50;
36
- }
37
-
38
- .header-title p {
39
- margin: 0;
40
- font-size: 14px;
41
- color: #7f8c8d;
42
- }
43
-
44
- .header-info {
45
- display: flex;
46
- align-items: center;
47
- }
48
-
49
- .date-box {
50
- display: flex;
51
- background-color: #ff9a3c;
52
- color: white;
53
- border-radius: 8px;
54
- padding: 5px 10px;
55
- margin-left: 15px;
56
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
57
- }
58
-
59
- .date-day {
60
- font-size: 24px;
61
- font-weight: bold;
62
- margin-left: 5px;
63
- line-height: 1;
64
- }
65
-
66
- .date-info {
67
- display: flex;
68
- flex-direction: column;
69
- font-size: 12px;
70
- }
71
-
72
- .date-month {
73
- font-weight: bold;
74
- line-height: 1.2;
75
- }
76
-
77
- .date-year {
78
- line-height: 1;
79
- }
80
-
81
- /* أنماط قائمة التنقل */
82
- .nav-menu {
83
- margin: 10px 0;
84
- }
85
-
86
- .nav-menu ul {
87
- display: flex;
88
- list-style: none;
89
- padding: 0;
90
- margin: 0;
91
- justify-content: flex-end;
92
- }
93
-
94
- .nav-menu li {
95
- margin-left: 15px;
96
- }
97
-
98
- .nav-menu a {
99
- display: flex;
100
- align-items: center;
101
- color: #2c3e50;
102
- text-decoration: none;
103
- padding: 5px 10px;
104
- border-radius: 5px;
105
- transition: background-color 0.3s;
106
- }
107
-
108
- .nav-menu a:hover {
109
- background-color: #f0f0f0;
110
- }
111
-
112
- .nav-icon {
113
- margin-left: 5px;
114
- }
115
-
116
- /* أنماط عنوان الوحدة */
117
- .module-title {
118
- color: #2c3e50;
119
- font-size: 28px;
120
- margin-bottom: 20px;
121
- border-right: 5px solid #ff9a3c;
122
- padding-right: 10px;
123
- }
124
-
125
- .main-title {
126
- color: #2c3e50;
127
- font-size: 32px;
128
- text-align: center;
129
- margin: 20px 0;
130
- }
131
-
132
- /* أنماط بطاقات المعلومات */
133
- .info-card {
134
- background-color: #f8f9fa;
135
- border-radius: 10px;
136
- padding: 20px;
137
- margin-bottom: 20px;
138
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
139
- }
140
-
141
- .info-card h3 {
142
- color: #333;
143
- margin-top: 0;
144
- margin-bottom: 10px;
145
- }
146
-
147
- .info-card p {
148
- color: #666;
149
- margin: 0;
150
- }
151
-
152
- /* أنماط الجداول */
153
- .dataframe {
154
- width: 100%;
155
- border-collapse: collapse;
156
- margin-bottom: 20px;
157
- }
158
-
159
- .dataframe th {
160
- background-color: #f0f0f0;
161
- color: #333;
162
- text-align: right;
163
- padding: 8px;
164
- border: 1px solid #ddd;
165
- }
166
-
167
- .dataframe td {
168
- padding: 8px;
169
- border: 1px solid #ddd;
170
- text-align: right;
171
- }
172
-
173
- .dataframe tr:nth-child(even) {
174
- background-color: #f9f9f9;
175
- }
176
-
177
- .dataframe tr:hover {
178
- background-color: #f0f0f0;
179
- }
180
-
181
- /* أنماط الأزرار */
182
- button, .stButton>button {
183
- background-color: #ff9a3c;
184
- color: white;
185
- border: none;
186
- border-radius: 4px;
187
- padding: 8px 16px;
188
- cursor: pointer;
189
- transition: background-color 0.3s;
190
- }
191
-
192
- button:hover, .stButton>button:hover {
193
- background-color: #e67e22;
194
- }
195
-
196
- /* أنماط المخططات */
197
- .plot-container {
198
- margin: 20px 0;
199
- }
200
-
201
- /* أنماط بطاقات الابتكارات */
202
- .innovation-card {
203
- background-color: #f8f9fa;
204
- border-radius: 10px;
205
- padding: 15px;
206
- margin-bottom: 20px;
207
- border-right: 5px solid #ff9a3c;
208
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
209
- }
210
-
211
- .innovation-icon {
212
- font-size: 24px;
213
- margin-bottom: 10px;
214
- }
215
-
216
- .innovation-card h3 {
217
- color: #333;
218
- margin-bottom: 10px;
219
- }
220
-
221
- .innovation-card p {
222
- color: #666;
223
- font-size: 14px;
224
- }
225
-
226
- /* أنماط فريق التطوير */
227
- .team-member {
228
- text-align: center;
229
- margin-bottom: 20px;
230
- }
231
-
232
- .team-member h3 {
233
- color: #333;
234
- margin-bottom: 5px;
235
- font-size: 18px;
236
- }
237
-
238
- .team-member h4 {
239
- color: #ff9a3c;
240
- margin-top: 0;
241
- margin-bottom: 10px;
242
- font-size: 14px;
243
- }
244
-
245
- .team-member p {
246
- color: #666;
247
- font-size: 12px;
248
- }
249
-
250
- .avatar {
251
- background-color: #ff9a3c;
252
- color: white;
253
- width: 100px;
254
- height: 100px;
255
- border-radius: 50%;
256
- display: flex;
257
- justify-content: center;
258
- align-items: center;
259
- margin: 0 auto 15px auto;
260
- font-size: 36px;
261
- }
262
-
263
- /* أنماط تذييل الصفحة */
264
- .footer {
265
- text-align: center;
266
- color: #7f8c8d;
267
- font-size: 12px;
268
- margin-top: 30px;
269
- margin-bottom: 10px;
270
- }
271
-
272
- /* أنماط رسائل التنبيه */
273
- .alert {
274
- padding: 10px 15px;
275
- border-radius: 4px;
276
- margin-bottom: 15px;
277
- }
278
-
279
- .alert-info {
280
- background-color: #d1ecf1;
281
- color: #0c5460;
282
- border: 1px solid #bee5eb;
283
- }
284
-
285
- .alert-success {
286
- background-color: #d4edda;
287
- color: #155724;
288
- border: 1px solid #c3e6cb;
289
- }
290
-
291
- .alert-warning {
292
- background-color: #fff3cd;
293
- color: #856404;
294
- border: 1px solid #ffeeba;
295
- }
296
-
297
- .alert-danger {
298
- background-color: #f8d7da;
299
- color: #721c24;
300
- border: 1px solid #f5c6cb;
301
- }
302
-
303
- /* أنماط الأيقونات */
304
- .icon {
305
- font-size: 18px;
306
- margin-left: 5px;
307
- }
308
-
309
- /* أنماط التبويبات */
310
- .stTabs [data-baseweb="tab-list"] {
311
- gap: 1px;
312
- }
313
-
314
- .stTabs [data-baseweb="tab"] {
315
- height: 50px;
316
- white-space: pre-wrap;
317
- background-color: white;
318
- border-radius: 4px 4px 0 0;
319
- gap: 1px;
320
- padding-top: 10px;
321
- padding-bottom: 10px;
322
- }
323
-
324
- .stTabs [aria-selected="true"] {
325
- background-color: #ff9a3c !important;
326
- color: white !important;
327
- }
328
-
329
- /* أنماط مخصصة لدعم اللغة العربية في إدخالات النصوص والأرقام */
330
- input, textarea, .stTextInput>div>div>input, .stNumberInput>div>div>input {
331
- direction: rtl;
332
- text-align: right;
333
- }
334
-
335
- /* أنماط قائمة الخيارات */
336
- .stSelectbox [data-baseweb="select"] {
337
- direction: rtl;
338
- text-align: right;
339
- }
340
-
341
- /* أنماط تحرير البيانات */
342
- .stDataEditor {
343
- direction: rtl;
344
- }
345
-
346
- /* أنماط للنسخة المحمولة */
347
- @media (max-width: 768px) {
348
- .header-container {
349
- flex-direction: column;
350
- align-items: flex-start;
351
- }
352
-
353
- .header-info {
354
- margin-top: 10px;
355
- }
356
-
357
- .nav-menu ul {
358
- flex-wrap: wrap;
359
- }
360
-
361
- .nav-menu li {
362
- margin-bottom: 5px;
363
- margin-left: 10px;
364
- }
365
-
366
- .module-title {
367
- font-size: 24px;
368
- }
369
-
370
- .main-title {
371
- font-size: 24px;
372
- }
373
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
static/images/README.md DELETED
@@ -1,40 +0,0 @@
1
- # مجلد الصور والأيقونات
2
-
3
- يحتوي هذا المجلد على جميع الصور والأيقونات المستخدمة في نظام تسعير المناقصات.
4
-
5
- ## هيكل المجلد
6
-
7
- - `logo.png`: شعار النظام الرئيسي
8
- - `logo-sm.png`: نسخة مصغرة من الشعار للاستخدام في الواجهات الصغيرة
9
- - `favicon.ico`: أيقونة المفضلة للمتصفح
10
- - `icons/`: مجلد الأيقونات المستخدمة في النظام
11
- - `backgrounds/`: مجلد خلفيات النظام
12
- - `users/`: مجلد لصور المستخدمين الافتراضية
13
- - `charts/`: صور للمخططات الثابتة
14
- - `report-templates/`: قوالب التقارير المطبوعة والمصدرة
15
-
16
- ## إرشادات استخدام الصور
17
-
18
- - استخدم الصور بتنسيق PNG للشعارات والأيقونات
19
- - استخدم تنسيق SVG للأيقونات كلما أمكن ذلك للحفاظ على جودة العرض
20
- - الاحتفاظ بنسخة عالية الدقة من الشعار بتنسيق PSD أو AI
21
-
22
- ## أيقونات النظام
23
-
24
- يستخدم النظام مجموعة أيقونات Font Awesome للعناصر المختلفة في الواجهة. يمكنك استخدامها عن طريق:
25
-
26
- ```html
27
- <i class="fas fa-chart-bar"></i> <!-- مخطط شريطي -->
28
- <i class="fas fa-file-invoice"></i> <!-- فاتورة -->
29
- <i class="fas fa-project-diagram"></i> <!-- مشروع -->
30
- <i class="fas fa-tasks"></i> <!-- مهام -->
31
- <i class="fas fa-calculator"></i> <!-- حاسبة -->
32
- ```
33
-
34
- لمزيد من الأيقونات، يمكنك زيارة [موقع Font Awesome](https://fontawesome.com/icons).
35
-
36
- ## الصور الافتراضية
37
-
38
- - `default-project.png`: صورة افتراضية للمشاريع
39
- - `default-user.png`: صورة افتراضية للمستخدمين
40
- - `default-client.png`: صورة افتراضية للعملاء
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
static/images/logo.png DELETED
Binary file (62.5 kB)
 
static/js/charts.js DELETED
@@ -1,348 +0,0 @@
1
- /**
2
- * ملف رسم وتهيئة المخططات البيانية
3
- */
4
-
5
- // دالة التهيئة عند تحميل الصفحة
6
- document.addEventListener('DOMContentLoaded', function() {
7
- // تهيئة المخططات
8
- initializeCharts();
9
- });
10
-
11
- /**
12
- * تهيئة جميع المخططات في الصفحة
13
- */
14
- function initializeCharts() {
15
- // التحقق من توفر مكتبة Chart.js
16
- if (typeof Chart === 'undefined') {
17
- console.warn('مكتبة Chart.js غير متوفرة. لا يمكن تهيئة المخططات.');
18
- return;
19
- }
20
-
21
- // تعيين الخيارات العامة للمخططات
22
- Chart.defaults.font.family = "'Tajawal', sans-serif";
23
- Chart.defaults.font.size = 14;
24
- Chart.defaults.color = '#333';
25
- Chart.defaults.plugins.tooltip.rtl = true;
26
- Chart.defaults.plugins.tooltip.titleAlign = 'right';
27
- Chart.defaults.plugins.tooltip.bodyAlign = 'right';
28
- Chart.defaults.plugins.legend.rtl = true;
29
- Chart.defaults.plugins.legend.labels.textAlign = 'right';
30
-
31
- // إنشاء مخططات مختلفة بناءً على نوع المخطط
32
- initializeBarCharts();
33
- initializeLineCharts();
34
- initializePieCharts();
35
- initializeRadarCharts();
36
- initializeGaugeCharts();
37
- initializeDashboardCharts();
38
- }
39
-
40
- /**
41
- * تهيئة المخططات الشريطية
42
- */
43
- function initializeBarCharts() {
44
- const barChartElements = document.querySelectorAll('.bar-chart');
45
-
46
- barChartElements.forEach(element => {
47
- const ctx = element.getContext('2d');
48
- const dataUrl = element.getAttribute('data-url');
49
-
50
- // استدعاء البيانات من الخادم إذا كان متوفرًا
51
- if (dataUrl) {
52
- fetch(dataUrl)
53
- .then(response => response.json())
54
- .then(data => {
55
- createBarChart(ctx, element, data);
56
- })
57
- .catch(error => {
58
- console.error('خطأ في تحميل بيانات المخطط:', error);
59
- // استخدام بيانات افتراضية في حال حدوث خطأ
60
- createBarChart(ctx, element, getDefaultBarChartData());
61
- });
62
- } else {
63
- // استخدام البيانات المضمنة من سمة data-config
64
- let chartData;
65
- try {
66
- chartData = JSON.parse(element.getAttribute('data-config') || '{}');
67
- } catch (e) {
68
- console.error('تنسيق بيانات المخطط غير صالح:', e);
69
- chartData = getDefaultBarChartData();
70
- }
71
-
72
- createBarChart(ctx, element, chartData);
73
- }
74
- });
75
- }
76
-
77
- /**
78
- * إنشاء مخطط شريطي
79
- */
80
- function createBarChart(ctx, element, data) {
81
- const isVertical = element.getAttribute('data-orientation') !== 'horizontal';
82
- const isStacked = element.getAttribute('data-stacked') === 'true';
83
-
84
- // تكوين الخيارات
85
- const options = {
86
- indexAxis: isVertical ? 'x' : 'y',
87
- scales: {
88
- x: {
89
- beginAtZero: true,
90
- grid: {
91
- display: false
92
- }
93
- },
94
- y: {
95
- beginAtZero: true,
96
- grid: {
97
- display: true,
98
- color: '#f0f0f0'
99
- }
100
- }
101
- },
102
- plugins: {
103
- title: {
104
- display: data.title ? true : false,
105
- text: data.title || '',
106
- align: 'right',
107
- font: {
108
- size: 16,
109
- weight: 'bold'
110
- }
111
- },
112
- legend: {
113
- display: (data.datasets && data.datasets.length > 1) ? true : false,
114
- position: 'top',
115
- align: 'end'
116
- }
117
- },
118
- responsive: true,
119
- maintainAspectRatio: false
120
- };
121
-
122
- // إضافة خيارات للمخطط المكدس إذا لزم الأمر
123
- if (isStacked) {
124
- options.scales.x.stacked = true;
125
- options.scales.y.stacked = true;
126
- }
127
-
128
- // إنشاء المخطط
129
- new Chart(ctx, {
130
- type: 'bar',
131
- data: {
132
- labels: data.labels || [],
133
- datasets: data.datasets || []
134
- },
135
- options: options
136
- });
137
- }
138
-
139
- /**
140
- * تهيئة المخططات الخطية
141
- */
142
- function initializeLineCharts() {
143
- const lineChartElements = document.querySelectorAll('.line-chart');
144
-
145
- lineChartElements.forEach(element => {
146
- const ctx = element.getContext('2d');
147
- const dataUrl = element.getAttribute('data-url');
148
-
149
- // استدعاء البيانات من الخادم إذا كان متوفرًا
150
- if (dataUrl) {
151
- fetch(dataUrl)
152
- .then(response => response.json())
153
- .then(data => {
154
- createLineChart(ctx, element, data);
155
- })
156
- .catch(error => {
157
- console.error('خطأ في تحميل بيانات المخطط:', error);
158
- createLineChart(ctx, element, getDefaultLineChartData());
159
- });
160
- } else {
161
- // استخدام البيانات المضمنة
162
- let chartData;
163
- try {
164
- chartData = JSON.parse(element.getAttribute('data-config') || '{}');
165
- } catch (e) {
166
- console.error('تنسيق بيانات المخطط غير صالح:', e);
167
- chartData = getDefaultLineChartData();
168
- }
169
-
170
- createLineChart(ctx, element, chartData);
171
- }
172
- });
173
- }
174
-
175
- /**
176
- * إنشاء مخطط خطي
177
- */
178
- function createLineChart(ctx, element, data) {
179
- const isCurved = element.getAttribute('data-curved') === 'true';
180
- const showPoints = element.getAttribute('data-points') !== 'false';
181
-
182
- // تكوين الخيارات
183
- const options = {
184
- scales: {
185
- x: {
186
- grid: {
187
- display: false
188
- }
189
- },
190
- y: {
191
- beginAtZero: element.getAttribute('data-start-at-zero') === 'true',
192
- grid: {
193
- color: '#f0f0f0'
194
- }
195
- }
196
- },
197
- elements: {
198
- line: {
199
- tension: isCurved ? 0.4 : 0,
200
- borderWidth: 2
201
- },
202
- point: {
203
- radius: showPoints ? 4 : 0,
204
- hoverRadius: showPoints ? 6 : 0
205
- }
206
- },
207
- plugins: {
208
- title: {
209
- display: data.title ? true : false,
210
- text: data.title || '',
211
- align: 'right',
212
- font: {
213
- size: 16,
214
- weight: 'bold'
215
- }
216
- },
217
- legend: {
218
- position: 'top',
219
- align: 'end'
220
- }
221
- },
222
- responsive: true,
223
- maintainAspectRatio: false,
224
- interaction: {
225
- mode: 'index',
226
- intersect: false
227
- }
228
- };
229
-
230
- // إنشاء المخطط
231
- new Chart(ctx, {
232
- type: 'line',
233
- data: {
234
- labels: data.labels || [],
235
- datasets: data.datasets || []
236
- },
237
- options: options
238
- });
239
- }
240
-
241
- /**
242
- * تهيئة المخططات الدائرية
243
- */
244
- function initializePieCharts() {
245
- const pieChartElements = document.querySelectorAll('.pie-chart, .doughnut-chart');
246
-
247
- pieChartElements.forEach(element => {
248
- const ctx = element.getContext('2d');
249
- const dataUrl = element.getAttribute('data-url');
250
- const isDoughnut = element.classList.contains('doughnut-chart');
251
-
252
- // استدعاء البيانات من الخادم إذا كان متوفرًا
253
- if (dataUrl) {
254
- fetch(dataUrl)
255
- .then(response => response.json())
256
- .then(data => {
257
- createPieChart(ctx, element, data, isDoughnut);
258
- })
259
- .catch(error => {
260
- console.error('خطأ في تحميل بيانات المخطط:', error);
261
- createPieChart(ctx, element, getDefaultPieChartData(), isDoughnut);
262
- });
263
- } else {
264
- // استخدام البيانات المضمنة
265
- let chartData;
266
- try {
267
- chartData = JSON.parse(element.getAttribute('data-config') || '{}');
268
- } catch (e) {
269
- console.error('تنسيق بيانات المخطط غير صالح:', e);
270
- chartData = getDefaultPieChartData();
271
- }
272
-
273
- createPieChart(ctx, element, chartData, isDoughnut);
274
- }
275
- });
276
- }
277
-
278
- /**
279
- * إنشاء مخطط دائري
280
- */
281
- function createPieChart(ctx, element, data, isDoughnut) {
282
- // تكوين الخيارات
283
- const options = {
284
- plugins: {
285
- title: {
286
- display: data.title ? true : false,
287
- text: data.title || '',
288
- align: 'right',
289
- font: {
290
- size: 16,
291
- weight: 'bold'
292
- }
293
- },
294
- legend: {
295
- position: 'bottom',
296
- align: 'start',
297
- rtl: true,
298
- labels: {
299
- boxWidth: 12,
300
- padding: 15
301
- }
302
- }
303
- },
304
- responsive: true,
305
- maintainAspectRatio: false
306
- };
307
-
308
- // إضافة خيارات لمخطط الدونات إذا لزم الأمر
309
- if (isDoughnut) {
310
- options.cutout = '60%';
311
- options.plugins.tooltip = {
312
- callbacks: {
313
- title: function(tooltipItems) {
314
- return tooltipItems[0].label;
315
- },
316
- label: function(context) {
317
- const value = context.raw;
318
- const total = context.chart.getDatasetMeta(0).total;
319
- const percentage = Math.round((value / total) * 100);
320
- return percentage + '% (' + value + ')';
321
- }
322
- }
323
- };
324
- }
325
-
326
- // إنشاء المخطط
327
- new Chart(ctx, {
328
- type: isDoughnut ? 'doughnut' : 'pie',
329
- data: {
330
- labels: data.labels || [],
331
- datasets: [{
332
- data: data.values || [],
333
- backgroundColor: data.colors || getDefaultColors(),
334
- borderWidth: 1,
335
- borderColor: '#fff'
336
- }]
337
- },
338
- options: options
339
- });
340
- }
341
-
342
- /**
343
- * تهيئة مخططات الرادار
344
- */
345
- function initializeRadarCharts() {
346
- const radarChartElements = document.querySelectorAll('.radar-chart');
347
-
348
- radarChartElements.forEach(element => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
static/js/main.js DELETED
@@ -1,416 +0,0 @@
1
- /**
2
- * ملف السكربت الرئيسي لنظام تسعير المناقصات
3
- */
4
-
5
- // دالة التهيئة عند تحميل الصفحة
6
- document.addEventListener('DOMContentLoaded', function() {
7
- // تفعيل تلميحات الأدوات
8
- initializeTooltips();
9
-
10
- // تفعيل التحقق من الإدخال في النماذج
11
- initializeFormValidation();
12
-
13
- // تفعيل وظيفة البحث والتصفية
14
- initializeSearchAndFilters();
15
-
16
- // تفعيل وظائف التصدير
17
- initializeExportFunctions();
18
-
19
- // تفعيل تحديثات البيانات المباشرة
20
- initializeLiveDataUpdates();
21
-
22
- // تفعيل التأثيرات البصرية
23
- initializeVisualEffects();
24
- });
25
-
26
- /**
27
- * تفعيل تلميحات الأدوات
28
- */
29
- function initializeTooltips() {
30
- // يمكن استخدام مكتبة Bootstrap للتلميحات إذا تم تحميلها
31
- if (typeof bootstrap !== 'undefined' && bootstrap.Tooltip) {
32
- const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
33
- [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
34
- } else {
35
- // تنفيذ بسيط للتلميحات إذا لم تكن مكتبة Bootstrap متاحة
36
- const tooltips = document.querySelectorAll('[data-tooltip]');
37
- tooltips.forEach(element => {
38
- element.addEventListener('mouseenter', function() {
39
- const tooltipText = this.getAttribute('data-tooltip');
40
- const tooltip = document.createElement('div');
41
- tooltip.className = 'custom-tooltip';
42
- tooltip.textContent = tooltipText;
43
- document.body.appendChild(tooltip);
44
-
45
- const rect = this.getBoundingClientRect();
46
- tooltip.style.left = rect.left + (rect.width / 2) - (tooltip.offsetWidth / 2) + 'px';
47
- tooltip.style.top = rect.bottom + 10 + 'px';
48
-
49
- this.addEventListener('mouseleave', function() {
50
- document.body.removeChild(tooltip);
51
- }, { once: true });
52
- });
53
- });
54
- }
55
- }
56
-
57
- /**
58
- * تفعيل التحقق من الإدخال في النماذج
59
- */
60
- function initializeFormValidation() {
61
- const forms = document.querySelectorAll('.needs-validation');
62
-
63
- forms.forEach(form => {
64
- form.addEventListener('submit', function(event) {
65
- if (!form.checkValidity()) {
66
- event.preventDefault();
67
- event.stopPropagation();
68
- }
69
-
70
- form.classList.add('was-validated');
71
- });
72
-
73
- // التحقق المباشر من الإدخال
74
- const inputs = form.querySelectorAll('input, select, textarea');
75
- inputs.forEach(input => {
76
- input.addEventListener('input', function() {
77
- validateInput(this);
78
- });
79
-
80
- input.addEventListener('blur', function() {
81
- validateInput(this);
82
- });
83
- });
84
- });
85
- }
86
-
87
- /**
88
- * التحقق من إدخال حقل معين
89
- */
90
- function validateInput(input) {
91
- // التحقق من صحة الإدخال
92
- if (input.checkValidity()) {
93
- input.classList.remove('is-invalid');
94
- input.classList.add('is-valid');
95
- } else {
96
- input.classList.remove('is-valid');
97
- input.classList.add('is-invalid');
98
- }
99
-
100
- // تحقق خاص بحقول الأرقام
101
- if (input.type === 'number') {
102
- const min = parseFloat(input.getAttribute('min'));
103
- const max = parseFloat(input.getAttribute('max'));
104
- const value = parseFloat(input.value);
105
-
106
- if (!isNaN(value)) {
107
- if (!isNaN(min) && value < min) {
108
- input.setCustomValidity(`القيمة يجب أن تكون أكبر من أو تساوي ${min}`);
109
- } else if (!isNaN(max) && value > max) {
110
- input.setCustomValidity(`القيمة يجب أن تكون أقل من أو تساوي ${max}`);
111
- } else {
112
- input.setCustomValidity('');
113
- }
114
- }
115
- }
116
- }
117
-
118
- /**
119
- * تفعيل وظيفة البحث والتصفية
120
- */
121
- function initializeSearchAndFilters() {
122
- // تنفيذ البحث في الجداول
123
- const searchInputs = document.querySelectorAll('.table-search');
124
- searchInputs.forEach(input => {
125
- input.addEventListener('input', function() {
126
- const table = document.querySelector(this.getAttribute('data-table'));
127
- const term = this.value.toLowerCase();
128
-
129
- if (table) {
130
- const rows = table.querySelectorAll('tbody tr');
131
- rows.forEach(row => {
132
- const text = row.textContent.toLowerCase();
133
- row.style.display = text.includes(term) ? '' : 'none';
134
- });
135
- }
136
- });
137
- });
138
-
139
- // تنفيذ تصفية الجداول
140
- const filterSelects = document.querySelectorAll('.table-filter');
141
- filterSelects.forEach(select => {
142
- select.addEventListener('change', function() {
143
- const table = document.querySelector(this.getAttribute('data-table'));
144
- const column = parseInt(this.getAttribute('data-column'));
145
- const value = this.value;
146
-
147
- if (table) {
148
- const rows = table.querySelectorAll('tbody tr');
149
- rows.forEach(row => {
150
- const cell = row.querySelectorAll('td')[column];
151
- if (cell) {
152
- row.style.display = (value === 'all' || cell.textContent === value) ? '' : 'none';
153
- }
154
- });
155
- }
156
- });
157
- });
158
- }
159
-
160
- /**
161
- * تفعيل وظائف التصدير
162
- */
163
- function initializeExportFunctions() {
164
- // تصدير إلى CSV
165
- const csvButtons = document.querySelectorAll('.export-csv');
166
- csvButtons.forEach(button => {
167
- button.addEventListener('click', function() {
168
- const tableId = this.getAttribute('data-table');
169
- exportTableToCSV(tableId, this.getAttribute('data-filename') || 'export.csv');
170
- });
171
- });
172
-
173
- // تصدير إلى PDF
174
- const pdfButtons = document.querySelectorAll('.export-pdf');
175
- pdfButtons.forEach(button => {
176
- button.addEventListener('click', function() {
177
- const tableId = this.getAttribute('data-table');
178
- exportTableToPDF(tableId, this.getAttribute('data-filename') || 'export.pdf');
179
- });
180
- });
181
-
182
- // تصدير إلى Excel
183
- const excelButtons = document.querySelectorAll('.export-excel');
184
- excelButtons.forEach(button => {
185
- button.addEventListener('click', function() {
186
- const tableId = this.getAttribute('data-table');
187
- exportTableToExcel(tableId, this.getAttribute('data-filename') || 'export.xlsx');
188
- });
189
- });
190
- }
191
-
192
- /**
193
- * تصدير جدول إلى CSV
194
- */
195
- function exportTableToCSV(tableId, filename) {
196
- const table = document.getElementById(tableId);
197
- if (!table) return;
198
-
199
- let csv = [];
200
- const rows = table.querySelectorAll('tr');
201
-
202
- for (let i = 0; i < rows.length; i++) {
203
- const row = [], cols = rows[i].querySelectorAll('td, th');
204
-
205
- for (let j = 0; j < cols.length; j++) {
206
- // تنظيف النص وإحاطته بعلامات اقتباس للتوافق مع تنسيق CSV
207
- let text = cols[j].innerText;
208
- text = text.replace(/"/g, '""');
209
- row.push('"' + text + '"');
210
- }
211
-
212
- csv.push(row.join(','));
213
- }
214
-
215
- // تحويل المصفوفة إلى نص
216
- const csvText = csv.join('\n');
217
-
218
- // إنشاء رابط تنزيل
219
- const blob = new Blob([csvText], { type: 'text/csv;charset=utf-8;' });
220
- const link = document.createElement('a');
221
-
222
- // تحديد اسم الملف
223
- link.setAttribute('download', filename);
224
-
225
- // إنشاء URL من Blob
226
- link.href = URL.createObjectURL(blob);
227
- link.style.visibility = 'hidden';
228
-
229
- // إضافة الرابط وتنفيذ النقر عليه
230
- document.body.appendChild(link);
231
- link.click();
232
- document.body.removeChild(link);
233
- }
234
-
235
- /**
236
- * تصدير جدول إلى PDF (يتطلب مكتبة خارجية مثل jsPDF)
237
- */
238
- function exportTableToPDF(tableId, filename) {
239
- // التحقق من وجود مكتبة jsPDF
240
- if (typeof jsPDF === 'undefined') {
241
- console.error('مكتبة jsPDF غير متوفرة. يرجى تضمينها لاستخدام هذه الوظيفة.');
242
- return;
243
- }
244
-
245
- const table = document.getElementById(tableId);
246
- if (!table) return;
247
-
248
- // إنشاء مستند PDF جديد
249
- const doc = new jsPDF('l', 'pt', 'a4');
250
-
251
- // تحويل الجدول إلى PDF
252
- doc.autoTable({
253
- html: '#' + tableId,
254
- startY: 20,
255
- theme: 'grid',
256
- headStyles: { fillColor: [41, 128, 185], textColor: 255 },
257
- bodyStyles: { textColor: 50 },
258
- alternateRowStyles: { fillColor: [245, 245, 245] }
259
- });
260
-
261
- // حفظ المستند
262
- doc.save(filename);
263
- }
264
-
265
- /**
266
- * تصدير جدول إلى Excel (يتطلب مكتبة خارجية مثل SheetJS)
267
- */
268
- function exportTableToExcel(tableId, filename) {
269
- // التحقق من وجود مكتبة SheetJS
270
- if (typeof XLSX === 'undefined') {
271
- console.error('مكتبة SheetJS (XLSX) غير متوفرة. يرجى تضمينها لاستخدام هذه الوظيفة.');
272
- return;
273
- }
274
-
275
- const table = document.getElementById(tableId);
276
- if (!table) return;
277
-
278
- // تحويل جدول HTML إلى دفتر عمل
279
- const wb = XLSX.utils.table_to_book(table);
280
-
281
- // حفظ الملف
282
- XLSX.writeFile(wb, filename);
283
- }
284
-
285
- /**
286
- * تفعيل تحديثات البيانات المباشرة
287
- */
288
- function initializeLiveDataUpdates() {
289
- // تنفيذ إذا كانت الواجهة تستخدم تحديثات مباشرة
290
- const liveDataElements = document.querySelectorAll('[data-live-update]');
291
-
292
- if (liveDataElements.length > 0) {
293
- // إعداد تحديثات دورية
294
- setInterval(function() {
295
- liveDataElements.forEach(element => {
296
- const url = element.getAttribute('data-live-update');
297
-
298
- // استدعاء البيانات من الخادم
299
- fetch(url)
300
- .then(response => response.json())
301
- .then(data => {
302
- // تحديث محتوى العنصر
303
- updateElementContent(element, data);
304
- })
305
- .catch(error => {
306
- console.error('خطأ في تحديث البيانات:', error);
307
- });
308
- });
309
- }, 30000); // تحديث كل 30 ثانية
310
- }
311
- }
312
-
313
- /**
314
- * تحديث محتوى عنصر بناءً على البيانات
315
- */
316
- function updateElementContent(element, data) {
317
- const updateType = element.getAttribute('data-update-type') || 'text';
318
-
319
- switch (updateType) {
320
- case 'text':
321
- element.textContent = data.value;
322
- break;
323
- case 'html':
324
- element.innerHTML = data.value;
325
- break;
326
- case 'attribute':
327
- const attributeName = element.getAttribute('data-update-attribute');
328
- if (attributeName) {
329
- element.setAttribute(attributeName, data.value);
330
- }
331
- break;
332
- case 'progress':
333
- element.style.width = data.value + '%';
334
- element.textContent = data.value + '%';
335
- break;
336
- case 'chart':
337
- // يفترض وجود مكتبة Chart.js
338
- if (typeof Chart !== 'undefined' && element.chart) {
339
- updateChart(element.chart, data);
340
- }
341
- break;
342
- }
343
-
344
- // تطبيق تأثير التحديث
345
- element.classList.add('updated');
346
- setTimeout(() => { element.classList.remove('updated'); }, 2000);
347
- }
348
-
349
- /**
350
- * تحديث مخطط باستخدام Chart.js
351
- */
352
- function updateChart(chart, data) {
353
- if (data.labels) {
354
- chart.data.labels = data.labels;
355
- }
356
-
357
- if (data.datasets) {
358
- chart.data.datasets = data.datasets;
359
- } else if (data.values) {
360
- // تحديث قيم مجموعة البيانات الأولى فقط
361
- chart.data.datasets[0].data = data.values;
362
- }
363
-
364
- chart.update();
365
- }
366
-
367
- /**
368
- * تفعيل التأثيرات البصرية
369
- */
370
- function initializeVisualEffects() {
371
- // تأثير التمرير السلس للروابط الداخلية
372
- document.querySelectorAll('a[href^="#"]').forEach(anchor => {
373
- anchor.addEventListener('click', function(e) {
374
- e.preventDefault();
375
- const targetId = this.getAttribute('href');
376
- const targetElement = document.querySelector(targetId);
377
-
378
- if (targetElement) {
379
- targetElement.scrollIntoView({
380
- behavior: 'smooth',
381
- block: 'start'
382
- });
383
- }
384
- });
385
- });
386
-
387
- // تأثير الظهور عند التمرير
388
- const fadeElements = document.querySelectorAll('.fade-in-element');
389
- if (fadeElements.length > 0) {
390
- const fadeObserver = new IntersectionObserver((entries) => {
391
- entries.forEach(entry => {
392
- if (entry.isIntersecting) {
393
- entry.target.classList.add('visible');
394
- fadeObserver.unobserve(entry.target);
395
- }
396
- });
397
- }, { threshold: 0.1 });
398
-
399
- fadeElements.forEach(element => {
400
- fadeObserver.observe(element);
401
- });
402
- }
403
-
404
- // تفعيل الرسوم المتحركة عند التفاعل
405
- const animatedElements = document.querySelectorAll('.animated-element');
406
- animatedElements.forEach(element => {
407
- element.addEventListener('mouseenter', function() {
408
- const animation = this.getAttribute('data-animation') || 'pulse';
409
- this.classList.add(animation);
410
- });
411
-
412
- element.addEventListener('animationend', function() {
413
- this.classList.remove(this.getAttribute('data-animation') || 'pulse');
414
- });
415
- });
416
- }