dars-framework 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. dars/__init__.py +0 -0
  2. dars/all.py +52 -0
  3. dars/cli/__init__.py +0 -0
  4. dars/cli/hot_reload.py +33 -0
  5. dars/cli/main.py +637 -0
  6. dars/cli/preview.py +419 -0
  7. dars/cli/translations.py +389 -0
  8. dars/components/__init__.py +0 -0
  9. dars/components/advanced/__init__.py +8 -0
  10. dars/components/advanced/accordion.py +21 -0
  11. dars/components/advanced/card.py +28 -0
  12. dars/components/advanced/modal.py +40 -0
  13. dars/components/advanced/navbar.py +31 -0
  14. dars/components/advanced/table.py +24 -0
  15. dars/components/advanced/tabs.py +26 -0
  16. dars/components/basic/__init__.py +34 -0
  17. dars/components/basic/button.py +29 -0
  18. dars/components/basic/checkbox.py +34 -0
  19. dars/components/basic/container.py +23 -0
  20. dars/components/basic/datepicker.py +139 -0
  21. dars/components/basic/image.py +36 -0
  22. dars/components/basic/input.py +50 -0
  23. dars/components/basic/link.py +31 -0
  24. dars/components/basic/page.py +20 -0
  25. dars/components/basic/progressbar.py +17 -0
  26. dars/components/basic/radiobutton.py +34 -0
  27. dars/components/basic/select.py +81 -0
  28. dars/components/basic/slider.py +63 -0
  29. dars/components/basic/spinner.py +11 -0
  30. dars/components/basic/text.py +22 -0
  31. dars/components/basic/textarea.py +46 -0
  32. dars/components/basic/tooltip.py +18 -0
  33. dars/components/layout/__init__.py +0 -0
  34. dars/components/layout/anchor.py +13 -0
  35. dars/components/layout/flex.py +26 -0
  36. dars/components/layout/grid.py +45 -0
  37. dars/core/__init__.py +0 -0
  38. dars/core/app.py +630 -0
  39. dars/core/component.py +25 -0
  40. dars/core/events.py +101 -0
  41. dars/core/properties.py +127 -0
  42. dars/docs/__init__.py +0 -0
  43. dars/exporters/__init__.py +0 -0
  44. dars/exporters/base.py +69 -0
  45. dars/exporters/web/__init__.py +0 -0
  46. dars/exporters/web/html_css_js.py +1406 -0
  47. dars/scripts/__init__.py +0 -0
  48. dars/scripts/script.py +38 -0
  49. dars/templates/__init__.py +0 -0
  50. dars/templates/examples/advanced/all_components_demo.py +87 -0
  51. dars/templates/examples/advanced/dashboard.py +440 -0
  52. dars/templates/examples/advanced/modern_web_app.py +452 -0
  53. dars/templates/examples/basic/flex_layout_responsive.py +13 -0
  54. dars/templates/examples/basic/form_components.py +516 -0
  55. dars/templates/examples/basic/grid_layout_responsive.py +13 -0
  56. dars/templates/examples/basic/hello_world.py +104 -0
  57. dars/templates/examples/basic/layout_multipage_demo.py +23 -0
  58. dars/templates/examples/basic/multipage_example.py +70 -0
  59. dars/templates/examples/basic/pwa_custom_icons.py +31 -0
  60. dars/templates/examples/basic/simple_form.py +377 -0
  61. dars/templates/examples/demo/complete_app.py +720 -0
  62. dars/templates/html/__init__.py +0 -0
  63. dars_framework-1.0.0.dist-info/METADATA +146 -0
  64. dars_framework-1.0.0.dist-info/RECORD +68 -0
  65. dars_framework-1.0.0.dist-info/WHEEL +5 -0
  66. dars_framework-1.0.0.dist-info/entry_points.txt +2 -0
  67. dars_framework-1.0.0.dist-info/licenses/LICENSE +21 -0
  68. dars_framework-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,720 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dars - Aplicación de Demostración Completa
4
+ Una aplicación que demuestra todas las características principales de Dars
5
+ """
6
+
7
+ import sys
8
+ import os
9
+
10
+ from dars.core.app import App
11
+ from dars.components.basic.text import Text
12
+ from dars.components.basic.button import Button
13
+ from dars.components.basic.input import Input
14
+ from dars.components.basic.container import Container
15
+ from dars.scripts.script import InlineScript, FileScript
16
+
17
+ # Crear la aplicación con configuración avanzada
18
+ app = App(
19
+ title="Dars - Demostración Completa",
20
+ theme="light",
21
+ responsive=True
22
+ )
23
+
24
+ # Estilos globales
25
+ app.add_global_style("body", {
26
+ 'margin': '0',
27
+ 'padding': '0',
28
+ 'font-family': '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
29
+ 'background-color': '#f8f9fa'
30
+ })
31
+
32
+ app.add_global_style(".fade-in", {
33
+ 'opacity': '0',
34
+ 'transition': 'opacity 0.5s ease-in-out'
35
+ })
36
+
37
+ # Contenedor principal
38
+ main_container = Container(
39
+ id="main-app",
40
+ style={
41
+ 'min-height': '100vh',
42
+ 'display': 'flex',
43
+ 'flex-direction': 'column'
44
+ }
45
+ )
46
+
47
+ # Header/Navegación
48
+ header = Container(
49
+ id="header",
50
+ style={
51
+ 'background': 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
52
+ 'color': 'white',
53
+ 'padding': '20px 0',
54
+ 'box-shadow': '0 2px 10px rgba(0,0,0,0.1)'
55
+ }
56
+ )
57
+
58
+ nav_container = Container(
59
+ style={
60
+ 'max-width': '1200px',
61
+ 'margin': '0 auto',
62
+ 'padding': '0 20px',
63
+ 'display': 'flex',
64
+ 'justify-content': 'space-between',
65
+ 'align-items': 'center'
66
+ }
67
+ )
68
+
69
+ logo = Text(
70
+ text="🚀 Dars Demo",
71
+ style={
72
+ 'font-size': '28px',
73
+ 'font-weight': 'bold'
74
+ }
75
+ )
76
+
77
+ nav_menu = Container(
78
+ style={
79
+ 'display': 'flex',
80
+ 'gap': '30px'
81
+ }
82
+ )
83
+
84
+ nav_items = ["Inicio", "Componentes", "Formularios", "Dashboard", "Acerca"]
85
+ for item in nav_items:
86
+ nav_button = Button(
87
+ id=f"nav-{item.lower()}",
88
+ text=item,
89
+ style={
90
+ 'background': 'transparent',
91
+ 'color': 'white',
92
+ 'border': '2px solid transparent',
93
+ 'padding': '8px 16px',
94
+ 'border-radius': '20px',
95
+ 'cursor': 'pointer',
96
+ 'transition': 'all 0.3s ease'
97
+ }
98
+ )
99
+ nav_menu.add_child(nav_button)
100
+
101
+ # Área de contenido principal
102
+ content_area = Container(
103
+ id="content-area",
104
+ style={
105
+ 'flex': '1',
106
+ 'max-width': '1200px',
107
+ 'margin': '0 auto',
108
+ 'padding': '40px 20px'
109
+ }
110
+ )
111
+
112
+ # Sección Hero
113
+ hero_section = Container(
114
+ id="hero",
115
+ class_name="fade-in",
116
+ style={
117
+ 'text-align': 'center',
118
+ 'padding': '60px 0',
119
+ 'background': 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
120
+ 'border-radius': '20px',
121
+ 'margin-bottom': '40px',
122
+ 'color': 'white'
123
+ }
124
+ )
125
+
126
+ hero_title = Text(
127
+ text="Bienvenido a Dars",
128
+ style={
129
+ 'font-size': '48px',
130
+ 'font-weight': 'bold',
131
+ 'margin-bottom': '20px'
132
+ }
133
+ )
134
+
135
+ hero_subtitle = Text(
136
+ text="Framework de UI multiplataforma en Python",
137
+ style={
138
+ 'font-size': '24px',
139
+ 'margin-bottom': '30px',
140
+ 'opacity': '0.9'
141
+ }
142
+ )
143
+
144
+ hero_description = Text(
145
+ text="Crea interfaces de usuario modernas con Python y expórtalas a HTML, React, React Native, PySide6, C# y Kotlin",
146
+ style={
147
+ 'font-size': '18px',
148
+ 'margin-bottom': '40px',
149
+ 'max-width': '600px',
150
+ 'margin-left': 'auto',
151
+ 'margin-right': 'auto',
152
+ 'line-height': '1.6'
153
+ }
154
+ )
155
+
156
+ hero_cta = Button(
157
+ id="hero-cta",
158
+ text="🚀 Comenzar Ahora",
159
+ style={
160
+ 'background-color': 'white',
161
+ 'color': '#f5576c',
162
+ 'padding': '15px 30px',
163
+ 'border': 'none',
164
+ 'border-radius': '30px',
165
+ 'font-size': '18px',
166
+ 'font-weight': 'bold',
167
+ 'cursor': 'pointer',
168
+ 'box-shadow': '0 4px 15px rgba(0,0,0,0.2)'
169
+ }
170
+ )
171
+
172
+ # Sección de características
173
+ features_section = Container(
174
+ id="features",
175
+ class_name="fade-in",
176
+ style={
177
+ 'margin-bottom': '40px'
178
+ }
179
+ )
180
+
181
+ features_title = Text(
182
+ text="Características Principales",
183
+ style={
184
+ 'font-size': '36px',
185
+ 'font-weight': 'bold',
186
+ 'text-align': 'center',
187
+ 'margin-bottom': '40px',
188
+ 'color': '#2c3e50'
189
+ }
190
+ )
191
+
192
+ features_grid = Container(
193
+ style={
194
+ 'display': 'grid',
195
+ 'grid-template-columns': 'repeat(auto-fit, minmax(300px, 1fr))',
196
+ 'gap': '30px'
197
+ }
198
+ )
199
+
200
+ # Función para crear tarjetas de características
201
+ def crear_feature_card(icono, titulo, descripcion):
202
+ card = Container(
203
+ style={
204
+ 'background': 'white',
205
+ 'padding': '30px',
206
+ 'border-radius': '15px',
207
+ 'box-shadow': '0 5px 20px rgba(0,0,0,0.1)',
208
+ 'text-align': 'center',
209
+ 'transition': 'transform 0.3s ease'
210
+ }
211
+ )
212
+
213
+ card_icon = Text(
214
+ text=icono,
215
+ style={
216
+ 'font-size': '48px',
217
+ 'margin-bottom': '20px'
218
+ }
219
+ )
220
+
221
+ card_title = Text(
222
+ text=titulo,
223
+ style={
224
+ 'font-size': '24px',
225
+ 'font-weight': 'bold',
226
+ 'margin-bottom': '15px',
227
+ 'color': '#2c3e50'
228
+ }
229
+ )
230
+
231
+ card_description = Text(
232
+ text=descripcion,
233
+ style={
234
+ 'font-size': '16px',
235
+ 'line-height': '1.6',
236
+ 'color': '#6c757d'
237
+ }
238
+ )
239
+
240
+ card.add_child(card_icon)
241
+ card.add_child(card_title)
242
+ card.add_child(card_description)
243
+
244
+ return card
245
+
246
+ # Crear tarjetas de características
247
+ features_data = [
248
+ ("🐍", "Python Puro", "Escribe interfaces de usuario usando únicamente Python, sin necesidad de aprender otros lenguajes."),
249
+ ("🌐", "Multiplataforma", "Exporta a HTML, React, React Native, PySide6, C# y Kotlin desde un solo código fuente."),
250
+ ("⚡", "Fácil de Usar", "Sintaxis simple e intuitiva que permite crear aplicaciones complejas con pocas líneas de código."),
251
+ ("🎨", "Personalizable", "Sistema de estilos flexible que soporta CSS moderno y temas personalizados."),
252
+ ("🔧", "Extensible", "Arquitectura modular que permite agregar nuevos componentes y exportadores fácilmente."),
253
+ ("📱", "Responsive", "Interfaces que se adaptan automáticamente a diferentes tamaños de pantalla y dispositivos.")
254
+ ]
255
+
256
+ for icono, titulo, descripcion in features_data:
257
+ features_grid.add_child(crear_feature_card(icono, titulo, descripcion))
258
+
259
+ # Sección de demostración interactiva
260
+ demo_section = Container(
261
+ id="demo",
262
+ class_name="fade-in",
263
+ style={
264
+ 'background': 'white',
265
+ 'padding': '40px',
266
+ 'border-radius': '15px',
267
+ 'box-shadow': '0 5px 20px rgba(0,0,0,0.1)',
268
+ 'margin-bottom': '40px'
269
+ }
270
+ )
271
+
272
+ demo_title = Text(
273
+ text="Demostración Interactiva",
274
+ style={
275
+ 'font-size': '32px',
276
+ 'font-weight': 'bold',
277
+ 'text-align': 'center',
278
+ 'margin-bottom': '30px',
279
+ 'color': '#2c3e50'
280
+ }
281
+ )
282
+
283
+ # Formulario de demostración
284
+ demo_form = Container(
285
+ style={
286
+ 'max-width': '500px',
287
+ 'margin': '0 auto'
288
+ }
289
+ )
290
+
291
+ form_title = Text(
292
+ text="Prueba los Componentes",
293
+ style={
294
+ 'font-size': '20px',
295
+ 'margin-bottom': '20px',
296
+ 'color': '#495057'
297
+ }
298
+ )
299
+
300
+ # Campos del formulario
301
+ name_input = Input(
302
+ id="demo-name",
303
+ placeholder="Tu nombre",
304
+ style={
305
+ 'width': '100%',
306
+ 'padding': '12px',
307
+ 'border': '2px solid #e9ecef',
308
+ 'border-radius': '8px',
309
+ 'font-size': '16px',
310
+ 'margin-bottom': '15px'
311
+ }
312
+ )
313
+
314
+ email_input = Input(
315
+ id="demo-email",
316
+ placeholder="tu@email.com",
317
+ input_type="email",
318
+ style={
319
+ 'width': '100%',
320
+ 'padding': '12px',
321
+ 'border': '2px solid #e9ecef',
322
+ 'border-radius': '8px',
323
+ 'font-size': '16px',
324
+ 'margin-bottom': '15px'
325
+ }
326
+ )
327
+
328
+ message_input = Input(
329
+ id="demo-message",
330
+ placeholder="Tu mensaje...",
331
+ style={
332
+ 'width': '100%',
333
+ 'padding': '12px',
334
+ 'border': '2px solid #e9ecef',
335
+ 'border-radius': '8px',
336
+ 'font-size': '16px',
337
+ 'margin-bottom': '20px',
338
+ 'min-height': '100px'
339
+ }
340
+ )
341
+
342
+ demo_button = Button(
343
+ id="demo-submit",
344
+ text="Enviar Demostración",
345
+ style={
346
+ 'width': '100%',
347
+ 'background': 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
348
+ 'color': 'white',
349
+ 'padding': '15px',
350
+ 'border': 'none',
351
+ 'border-radius': '8px',
352
+ 'font-size': '16px',
353
+ 'font-weight': 'bold',
354
+ 'cursor': 'pointer'
355
+ }
356
+ )
357
+
358
+ # Resultado de la demostración
359
+ demo_result = Container(
360
+ id="demo-result",
361
+ style={
362
+ 'margin-top': '20px',
363
+ 'padding': '20px',
364
+ 'background-color': '#f8f9fa',
365
+ 'border-radius': '8px',
366
+ 'display': 'none'
367
+ }
368
+ )
369
+
370
+ result_text = Text(
371
+ id="result-text",
372
+ text="",
373
+ style={
374
+ 'font-size': '16px',
375
+ 'color': '#495057'
376
+ }
377
+ )
378
+
379
+ # Footer
380
+ footer = Container(
381
+ style={
382
+ 'background-color': '#2c3e50',
383
+ 'color': 'white',
384
+ 'text-align': 'center',
385
+ 'padding': '40px 20px',
386
+ 'margin-top': 'auto'
387
+ }
388
+ )
389
+
390
+ footer_text = Text(
391
+ text="© 2024 PyWebUI Framework - Creado con ❤️ en Python",
392
+ style={
393
+ 'font-size': '16px'
394
+ }
395
+ )
396
+
397
+ # Script principal de la aplicación
398
+ main_script = InlineScript(r"""
399
+ // Estado global de la aplicación
400
+ const AppState = {
401
+ currentSection: 'inicio',
402
+ animationDelay: 100,
403
+ isLoaded: false
404
+ };
405
+
406
+ // Utilidades
407
+ const Utils = {
408
+ // Animación de fade in
409
+ fadeIn: function(element, delay = 0) {
410
+ setTimeout(() => {
411
+ element.style.opacity = '1';
412
+ }, delay);
413
+ },
414
+
415
+ // Scroll suave
416
+ smoothScroll: function(target) {
417
+ document.querySelector(target).scrollIntoView({
418
+ behavior: 'smooth'
419
+ });
420
+ },
421
+
422
+ // Validar email
423
+ isValidEmail: function(email) {
424
+ const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
425
+ return regex.test(email);
426
+ }
427
+ };
428
+
429
+ // Gestión de navegación
430
+ const Navigation = {
431
+ init: function() {
432
+ const navButtons = document.querySelectorAll('[id^="nav-"]');
433
+ navButtons.forEach(button => {
434
+ button.addEventListener('click', this.handleNavClick.bind(this));
435
+
436
+ // Efectos hover
437
+ button.addEventListener('mouseenter', function() {
438
+ this.style.borderColor = 'white';
439
+ this.style.backgroundColor = 'rgba(255,255,255,0.1)';
440
+ });
441
+
442
+ button.addEventListener('mouseleave', function() {
443
+ this.style.borderColor = 'transparent';
444
+ this.style.backgroundColor = 'transparent';
445
+ });
446
+ });
447
+ },
448
+
449
+ handleNavClick: function(event) {
450
+ const section = event.target.textContent.toLowerCase();
451
+ this.navigateToSection(section);
452
+ },
453
+
454
+ navigateToSection: function(section) {
455
+ AppState.currentSection = section;
456
+
457
+ // Aquí podrías implementar navegación real entre secciones
458
+ console.log(`Navegando a: ${section}`);
459
+
460
+ // Ejemplo de scroll a sección
461
+ if (section === 'componentes') {
462
+ Utils.smoothScroll('#demo');
463
+ }
464
+ }
465
+ };
466
+
467
+ // Gestión de animaciones
468
+ const Animations = {
469
+ init: function() {
470
+ this.setupIntersectionObserver();
471
+ this.animateHero();
472
+ this.setupCardHovers();
473
+ },
474
+
475
+ setupIntersectionObserver: function() {
476
+ const observer = new IntersectionObserver((entries) => {
477
+ entries.forEach(entry => {
478
+ if (entry.isIntersecting) {
479
+ Utils.fadeIn(entry.target, 200);
480
+ }
481
+ });
482
+ }, { threshold: 0.1 });
483
+
484
+ document.querySelectorAll('.fade-in').forEach(el => {
485
+ observer.observe(el);
486
+ });
487
+ },
488
+
489
+ animateHero: function() {
490
+ const hero = document.getElementById('hero');
491
+ if (hero) {
492
+ Utils.fadeIn(hero, 300);
493
+ }
494
+ },
495
+
496
+ setupCardHovers: function() {
497
+ const cards = document.querySelectorAll('#features > div > div');
498
+ cards.forEach(card => {
499
+ card.addEventListener('mouseenter', function() {
500
+ this.style.transform = 'translateY(-10px)';
501
+ this.style.boxShadow = '0 10px 30px rgba(0,0,0,0.15)';
502
+ });
503
+
504
+ card.addEventListener('mouseleave', function() {
505
+ this.style.transform = 'translateY(0)';
506
+ this.style.boxShadow = '0 5px 20px rgba(0,0,0,0.1)';
507
+ });
508
+ });
509
+ }
510
+ };
511
+
512
+ // Gestión del formulario de demostración
513
+ const DemoForm = {
514
+ init: function() {
515
+ const submitButton = document.getElementById('demo-submit');
516
+ if (submitButton) {
517
+ submitButton.addEventListener('click', this.handleSubmit.bind(this));
518
+ }
519
+
520
+ // Validación en tiempo real
521
+ const inputs = ['demo-name', 'demo-email', 'demo-message'];
522
+ inputs.forEach(id => {
523
+ const input = document.getElementById(id);
524
+ if (input) {
525
+ input.addEventListener('input', this.validateField.bind(this));
526
+ input.addEventListener('blur', this.validateField.bind(this));
527
+ }
528
+ });
529
+ },
530
+
531
+ validateField: function(event) {
532
+ const field = event.target;
533
+ const value = field.value.trim();
534
+
535
+ // Limpiar estilos previos
536
+ field.style.borderColor = '#e9ecef';
537
+
538
+ if (field.id === 'demo-email' && value) {
539
+ if (Utils.isValidEmail(value)) {
540
+ field.style.borderColor = '#28a745';
541
+ } else {
542
+ field.style.borderColor = '#dc3545';
543
+ }
544
+ } else if (value) {
545
+ field.style.borderColor = '#28a745';
546
+ }
547
+ },
548
+
549
+ handleSubmit: function(event) {
550
+ event.preventDefault();
551
+
552
+ const name = document.getElementById('demo-name').value.trim();
553
+ const email = document.getElementById('demo-email').value.trim();
554
+ const message = document.getElementById('demo-message').value.trim();
555
+
556
+ // Validación
557
+ if (!name || !email || !message) {
558
+ this.showResult('Por favor, completa todos los campos.', 'error');
559
+ return;
560
+ }
561
+
562
+ if (!Utils.isValidEmail(email)) {
563
+ this.showResult('Por favor, ingresa un email válido.', 'error');
564
+ return;
565
+ }
566
+
567
+ // Simular envío
568
+ this.simulateSubmission(name, email, message);
569
+ },
570
+
571
+ simulateSubmission: function(name, email, message) {
572
+ const button = document.getElementById('demo-submit');
573
+ const originalText = button.textContent;
574
+
575
+ button.textContent = 'Enviando...';
576
+ button.disabled = true;
577
+ button.style.opacity = '0.7';
578
+
579
+ setTimeout(() => {
580
+ this.showResult(`¡Gracias ${name}! Tu mensaje ha sido enviado correctamente. Te contactaremos en ${email}.`, 'success');
581
+
582
+ // Limpiar formulario
583
+ document.getElementById('demo-name').value = '';
584
+ document.getElementById('demo-email').value = '';
585
+ document.getElementById('demo-message').value = '';
586
+
587
+ // Restaurar botón
588
+ button.textContent = originalText;
589
+ button.disabled = false;
590
+ button.style.opacity = '1';
591
+ }, 2000);
592
+ },
593
+
594
+ showResult: function(message, type) {
595
+ const resultContainer = document.getElementById('demo-result');
596
+ const resultText = document.getElementById('result-text');
597
+
598
+ if (resultContainer && resultText) {
599
+ resultText.textContent = message;
600
+ resultContainer.style.display = 'block';
601
+ resultContainer.style.backgroundColor = type === 'success' ? '#d4edda' : '#f8d7da';
602
+ resultContainer.style.color = type === 'success' ? '#155724' : '#721c24';
603
+ resultContainer.style.borderLeft = `4px solid ${type === 'success' ? '#28a745' : '#dc3545'}`;
604
+
605
+ // Auto-ocultar después de 5 segundos
606
+ setTimeout(() => {
607
+ resultContainer.style.display = 'none';
608
+ }, 5000);
609
+ }
610
+ }
611
+ };
612
+
613
+ // Efectos especiales
614
+ const SpecialEffects = {
615
+ init: function() {
616
+ this.setupHeroCTA();
617
+ this.setupParallax();
618
+ },
619
+
620
+ setupHeroCTA: function() {
621
+ const ctaButton = document.getElementById('hero-cta');
622
+ if (ctaButton) {
623
+ ctaButton.addEventListener('click', function() {
624
+ Utils.smoothScroll('#demo');
625
+ });
626
+
627
+ ctaButton.addEventListener('mouseenter', function() {
628
+ this.style.transform = 'translateY(-2px)';
629
+ this.style.boxShadow = '0 6px 20px rgba(0,0,0,0.3)';
630
+ });
631
+
632
+ ctaButton.addEventListener('mouseleave', function() {
633
+ this.style.transform = 'translateY(0)';
634
+ this.style.boxShadow = '0 4px 15px rgba(0,0,0,0.2)';
635
+ });
636
+ }
637
+ },
638
+
639
+ setupParallax: function() {
640
+ window.addEventListener('scroll', function() {
641
+ const scrolled = window.pageYOffset;
642
+ const hero = document.getElementById('hero');
643
+
644
+ if (hero) {
645
+ const speed = scrolled * 0.5;
646
+ hero.style.transform = `translateY(${speed}px)`;
647
+ }
648
+ });
649
+ }
650
+ };
651
+
652
+ // Inicialización principal
653
+ document.addEventListener('DOMContentLoaded', function() {
654
+ console.log('🚀 Dars Demo App iniciada');
655
+
656
+ // Inicializar módulos
657
+ Navigation.init();
658
+ Animations.init();
659
+ DemoForm.init();
660
+ SpecialEffects.init();
661
+
662
+ // Marcar como cargada
663
+ AppState.isLoaded = true;
664
+
665
+ // Mensaje de bienvenida
666
+ setTimeout(() => {
667
+ console.log('✨ Todas las funcionalidades cargadas correctamente');
668
+ }, 1000);
669
+ });
670
+
671
+ // Manejo de errores globales
672
+ window.addEventListener('error', function(e) {
673
+ console.error('Error en la aplicación:', e.error);
674
+ });
675
+ """)
676
+
677
+ # Ensamblar la aplicación
678
+ nav_container.add_child(logo)
679
+ nav_container.add_child(nav_menu)
680
+ header.add_child(nav_container)
681
+
682
+ hero_section.add_child(hero_title)
683
+ hero_section.add_child(hero_subtitle)
684
+ hero_section.add_child(hero_description)
685
+ hero_section.add_child(hero_cta)
686
+
687
+ features_section.add_child(features_title)
688
+ features_section.add_child(features_grid)
689
+
690
+ demo_form.add_child(form_title)
691
+ demo_form.add_child(name_input)
692
+ demo_form.add_child(email_input)
693
+ demo_form.add_child(message_input)
694
+ demo_form.add_child(demo_button)
695
+
696
+ demo_result.add_child(result_text)
697
+ demo_form.add_child(demo_result)
698
+
699
+ demo_section.add_child(demo_title)
700
+ demo_section.add_child(demo_form)
701
+
702
+ content_area.add_child(hero_section)
703
+ content_area.add_child(features_section)
704
+ content_area.add_child(demo_section)
705
+
706
+ footer.add_child(footer_text)
707
+
708
+ main_container.add_child(header)
709
+ main_container.add_child(content_area)
710
+ main_container.add_child(footer)
711
+
712
+ app.set_root(main_container)
713
+ app.add_script(main_script)
714
+
715
+ # Para exportar esta aplicación, ejecuta:
716
+ # dars export examples/demo/complete_app.py --format html --output ./complete_app_output
717
+
718
+ if __name__ == "__main__":
719
+ app.rTimeCompile() # Preview/compilación rápida
720
+
File without changes