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
dars/cli/preview.py ADDED
@@ -0,0 +1,419 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dars Preview - Preview system for exported applications
4
+ """
5
+
6
+ import os
7
+ import sys
8
+ import webbrowser
9
+ import http.server
10
+ import socketserver
11
+ import threading
12
+ import time
13
+ from pathlib import Path
14
+
15
+ from rich.console import Console
16
+ from rich.panel import Panel
17
+ from rich.text import Text
18
+ from rich.table import Table
19
+ from rich import print as rprint
20
+
21
+ from dars.cli.translations import translator
22
+
23
+ console = Console()
24
+
25
+ class PreviewServer:
26
+ """Preview server for Dars applications"""
27
+
28
+ class DarsRequestHandler(http.server.SimpleHTTPRequestHandler):
29
+ def end_headers(self):
30
+ # CORS para desarrollo PWA si es necesario
31
+ self.send_header('Access-Control-Allow-Origin', '*')
32
+ super().end_headers()
33
+ def guess_type(self, path):
34
+ if path.endswith('sw.js'):
35
+ return 'application/javascript'
36
+ return super().guess_type(path)
37
+
38
+ def __init__(self, directory: str, port: int = 8000):
39
+ self.directory = os.path.abspath(directory)
40
+ self.port = port
41
+ self.server = None
42
+ self.server_thread = None
43
+
44
+ def start(self):
45
+ """Starts the preview server"""
46
+ try:
47
+ # Change to the application directory
48
+ os.chdir(self.directory)
49
+
50
+ # Create the server
51
+ handler = self.DarsRequestHandler
52
+ self.server = socketserver.TCPServer(("", self.port), handler)
53
+
54
+ # Start in a separate thread
55
+ self.server_thread = threading.Thread(target=self.server.serve_forever)
56
+ self.server_thread.daemon = True
57
+ self.server_thread.start()
58
+
59
+ return True
60
+
61
+ except Exception as e:
62
+ console.print(f"[red]{translator.get('server_start_error')}: {e}[/red]")
63
+ return False
64
+
65
+ def stop(self):
66
+ """Stops the preview server"""
67
+ if self.server:
68
+ self.server.shutdown()
69
+ self.server.server_close()
70
+
71
+ def get_url(self) -> str:
72
+ """Gets the server URL"""
73
+ return f"http://localhost:{self.port}"
74
+
75
+ def preview_html_app(directory: str, auto_open: bool = True, port: int = 8000):
76
+ """Previews an exported HTML application"""
77
+
78
+ # Verify that index.html exists
79
+ index_path = os.path.join(directory, "index.html")
80
+ if not os.path.exists(index_path):
81
+ console.print(f"[red]{translator.get('index_html_missing')} {directory}[/red]")
82
+ return False
83
+
84
+ # Create and start the server
85
+ server = PreviewServer(directory, port)
86
+
87
+ if not server.start():
88
+ return False
89
+
90
+ url = server.get_url()
91
+
92
+ # Show information
93
+ panel_content = f"""
94
+ [green]✓[/green] {translator.get('preview_server_started')}
95
+
96
+ [bold]URL:[/bold] {url}
97
+ [bold]{translator.get('directory')}:[/bold] {directory}
98
+ [bold]{translator.get('port')}:[/bold] {port}
99
+
100
+ [yellow]{translator.get('press_ctrl_c')}[/yellow]
101
+ """
102
+
103
+ console.print(Panel(panel_content, title="Dars Preview", border_style="green"))
104
+
105
+ # Open in browser if requested
106
+ if auto_open:
107
+ try:
108
+ webbrowser.open(url)
109
+ console.print(f"[cyan]{translator.get('opening_in_browser').format(url=url)}[/cyan]")
110
+ except Exception as e:
111
+ console.print(f"[yellow]{translator.get('browser_open_error')}: {e}[/yellow]")
112
+ console.print(f"[cyan]{translator.get('open_manually')}: {url}[/cyan]")
113
+
114
+ try:
115
+ # Keep the server running
116
+ while True:
117
+ time.sleep(1)
118
+ except KeyboardInterrupt:
119
+ console.print(f"\n[yellow]{translator.get('stopping_server')}[/yellow]")
120
+ server.stop()
121
+ console.print(f"[green]{translator.get('server_stopped')}[/green]")
122
+
123
+ return True
124
+
125
+ def preview_react_app(directory: str):
126
+ """Previews an exported React application"""
127
+
128
+ # Verify that package.json exists
129
+ package_path = os.path.join(directory, "package.json")
130
+ if not os.path.exists(package_path):
131
+ console.print(f"[red]{translator.get('package_json_not_found')} {directory}[/red]")
132
+ return False
133
+
134
+ console.print(Panel(
135
+ f"""
136
+ {translator.get('preview_react_instructions')}:
137
+
138
+ 1. {translator.get('navigate_to_directory')}:
139
+ [cyan]cd {directory}[/cyan]
140
+
141
+ 2. {translator.get('install_dependencies')}:
142
+ [cyan]npm install[/cyan]
143
+
144
+ 3. {translator.get('start_dev_server')}:
145
+ [cyan]npm start[/cyan]
146
+
147
+ {translator.get('app_will_open')} http://localhost:3000
148
+ """,
149
+ title=translator.get('react_preview'),
150
+ border_style="blue"
151
+ ))
152
+
153
+ return True
154
+
155
+ def preview_react_native_app(directory: str):
156
+ """Previews an exported React Native application"""
157
+
158
+ # Verify that package.json exists
159
+ package_path = os.path.join(directory, "package.json")
160
+ if not os.path.exists(package_path):
161
+ console.print(f"[red]{translator.get('package_json_not_found')} {directory}[/red]")
162
+ return False
163
+
164
+ console.print(Panel(
165
+ f"""
166
+ {translator.get('preview_react_native_instructions')}:
167
+
168
+ 1. {translator.get('navigate_to_directory')}:
169
+ [cyan]cd {directory}[/cyan]
170
+
171
+ 2. {translator.get('install_dependencies')}:
172
+ [cyan]npm install[/cyan]
173
+
174
+ 3. {translator.get('for_android')}:
175
+ [cyan]npm run android[/cyan]
176
+
177
+ 4. {translator.get('for_ios')}:
178
+ [cyan]npm run ios[/cyan]
179
+
180
+ 5. {translator.get('start_metro')}:
181
+ [cyan]npm start[/cyan]
182
+
183
+ [yellow]{translator.get('react_native_note')}[/yellow]
184
+ """,
185
+ title=translator.get('react_native_preview'),
186
+ border_style="green"
187
+ ))
188
+
189
+ return True
190
+
191
+ def preview_pyside6_app(directory: str):
192
+ """Previews an exported PySide6 application"""
193
+
194
+ # Verify that main.py exists
195
+ main_path = os.path.join(directory, "main.py")
196
+ if not os.path.exists(main_path):
197
+ console.print(f"[red]{translator.get('main_py_not_found')} {directory}[/red]")
198
+ return False
199
+
200
+ console.print(Panel(
201
+ f"""
202
+ {translator.get('run_pyside6_app')}:
203
+
204
+ 1. {translator.get('navigate_to_directory')}:
205
+ [cyan]cd {directory}[/cyan]
206
+
207
+ 2. {translator.get('install_dependencies')}:
208
+ [cyan]pip install -r requirements.txt[/cyan]
209
+
210
+ 3. {translator.get('run_application')}:
211
+ [cyan]python main.py[/cyan]
212
+
213
+ [yellow]{translator.get('pyside6_note')}[/yellow]
214
+ """,
215
+ title=translator.get('pyside6_preview'),
216
+ border_style="magenta"
217
+ ))
218
+
219
+ return True
220
+
221
+ def preview_csharp_app(directory: str):
222
+ """Previews an exported C# application"""
223
+
224
+ # Search for .csproj file
225
+ csproj_files = list(Path(directory).glob("*.csproj"))
226
+ if not csproj_files:
227
+ console.print(f"[red]{translator.get('csproj_not_found')} {directory}[/red]")
228
+ return False
229
+
230
+ csproj_file = csproj_files[0].name
231
+
232
+ console.print(Panel(
233
+ f"""
234
+ {translator.get('run_csharp_app')}:
235
+
236
+ 1. {translator.get('navigate_to_directory')}:
237
+ [cyan]cd {directory}[/cyan]
238
+
239
+ 2. {translator.get('restore_dependencies')}:
240
+ [cyan]dotnet restore[/cyan]
241
+
242
+ 3. {translator.get('build_application')}:
243
+ [cyan]dotnet build[/cyan]
244
+
245
+ 4. {translator.get('run_application')}:
246
+ [cyan]dotnet run[/cyan]
247
+
248
+ [yellow]{translator.get('dotnet_note')}[/yellow]
249
+ """,
250
+ title=translator.get('csharp_preview'),
251
+ border_style="red"
252
+ ))
253
+
254
+ return True
255
+
256
+ def preview_kotlin_app(directory: str):
257
+ """Previews an exported Kotlin application"""
258
+
259
+ # Verify that build.gradle.kts exists
260
+ gradle_path = os.path.join(directory, "build.gradle.kts")
261
+ if not os.path.exists(gradle_path):
262
+ console.print(f"[red]{translator.get('gradle_not_found')} {directory}[/red]")
263
+ return False
264
+
265
+ console.print(Panel(
266
+ f"""
267
+ {translator.get('run_kotlin_app')}:
268
+
269
+ 1. {translator.get('navigate_to_directory')}:
270
+ [cyan]cd {directory}[/cyan]
271
+
272
+ 2. {translator.get('for_desktop')}:
273
+ [cyan]./gradlew run[/cyan]
274
+
275
+ 3. {translator.get('for_android')}:
276
+ [cyan]./gradlew installDebug[/cyan]
277
+
278
+ 4. {translator.get('build_all_platforms')}:
279
+ [cyan]./gradlew build[/cyan]
280
+
281
+ [yellow]{translator.get('kotlin_note')}[/yellow]
282
+ """,
283
+ title=translator.get('kotlin_preview'),
284
+ border_style="yellow"
285
+ ))
286
+
287
+ return True
288
+
289
+ def auto_detect_format(directory: str) -> str:
290
+ """Automatically detects the format of the exported application"""
291
+
292
+ if os.path.exists(os.path.join(directory, "index.html")):
293
+ return "html"
294
+ elif os.path.exists(os.path.join(directory, "package.json")):
295
+ # Read package.json to distinguish between React and React Native
296
+ try:
297
+ import json
298
+ with open(os.path.join(directory, "package.json"), 'r') as f:
299
+ package_data = json.load(f)
300
+
301
+ if "react-native" in package_data.get("dependencies", {}):
302
+ return "react-native"
303
+ else:
304
+ return "react"
305
+ except:
306
+ return "react"
307
+ elif os.path.exists(os.path.join(directory, "main.py")):
308
+ return "pyside6"
309
+ elif list(Path(directory).glob("*.csproj")):
310
+ return "csharp"
311
+ elif os.path.exists(os.path.join(directory, "build.gradle.kts")):
312
+ return "kotlin"
313
+ else:
314
+ return "unknown"
315
+
316
+ def preview_app(directory: str, format_name: str = None, auto_open: bool = True, port: int = 8000):
317
+ """Previews an exported application"""
318
+
319
+ if not os.path.exists(directory):
320
+ console.print(f"[red]{translator.get('directory_not_exists').format(directory=directory)}[/red]")
321
+ return False
322
+
323
+ # Automatically detect format if not specified
324
+ if format_name is None:
325
+ format_name = auto_detect_format(directory)
326
+
327
+ if format_name == "unknown":
328
+ console.print(f"[red]{translator.get('format_not_detected').format(directory=directory)}[/red]")
329
+ return False
330
+
331
+ console.print(f"[cyan]{translator.get('detected_format')}: {format_name}[/cyan]")
332
+
333
+ # Call the corresponding previewer
334
+ preview_functions = {
335
+ "html": lambda: preview_html_app(directory, auto_open, port),
336
+ "react": lambda: preview_react_app(directory),
337
+ "react-native": lambda: preview_react_native_app(directory),
338
+ "pyside6": lambda: preview_pyside6_app(directory),
339
+ "csharp": lambda: preview_csharp_app(directory),
340
+ "kotlin": lambda: preview_kotlin_app(directory)
341
+ }
342
+
343
+ preview_function = preview_functions.get(format_name)
344
+ if preview_function:
345
+ return preview_function()
346
+ else:
347
+ console.print(f"[red]{translator.get('format_not_supported').format(format=format_name)}[/red]")
348
+ return False
349
+
350
+ if __name__ == "__main__":
351
+ import argparse
352
+ import sys
353
+
354
+ # First, create a simple parser just to extract the language
355
+ pre_parser = argparse.ArgumentParser(add_help=False)
356
+ pre_parser.add_argument("--lang", "-l", choices=["en", "es"], default="en")
357
+
358
+ # Parse known args to get language without triggering errors on other args
359
+ pre_args, _ = pre_parser.parse_known_args()
360
+
361
+ # Set language before creating the main parser and save preference if specified
362
+ # If --lang is in sys.argv, it means the user explicitly specified it
363
+ save_preference = "--lang" in sys.argv or "-l" in sys.argv
364
+ translator.set_language(pre_args.lang, save=save_preference)
365
+
366
+ # Check for help before parsing arguments to show Rich-styled help
367
+ if '-h' in sys.argv or '--help' in sys.argv:
368
+ # Show banner
369
+ console.print(Panel(
370
+ Text("Dars Preview", style="bold cyan", justify="center"),
371
+ subtitle=translator.get('preview_description'),
372
+ border_style="cyan"
373
+ ))
374
+
375
+ # Show usage
376
+ console.print(f"\n[bold cyan]{translator.get('usage')}:[/bold cyan]")
377
+ console.print("preview.py [-h] [--format FORMAT] [--no-open] [--port PORT] [--lang {en,es}] directory")
378
+
379
+ # Show positional arguments
380
+ console.print(f"\n[bold cyan]{translator.get('positional_arguments')}:[/bold cyan]")
381
+ pos_table = Table(show_header=False, box=None, padding=(0, 2, 0, 0), expand=True)
382
+ pos_table.add_column("Argument", style="bold green", width=20, no_wrap=True)
383
+ pos_table.add_column("Description", style="dim white", overflow="fold")
384
+ pos_table.add_row("directory", translator.get('directory_help'))
385
+ console.print(pos_table)
386
+
387
+ # Show options
388
+ console.print(f"\n[bold cyan]{translator.get('options')}:[/bold cyan]")
389
+ opt_table = Table(show_header=False, box=None, padding=(0, 2, 0, 0), expand=True)
390
+ opt_table.add_column("Option", style="bold green", width=30, no_wrap=True)
391
+ opt_table.add_column("Description", style="dim white", overflow="fold")
392
+ opt_table.add_row("-h, --help", "show this help message and exit")
393
+ opt_table.add_row("--format FORMAT, -f FORMAT", translator.get('format_help'))
394
+ opt_table.add_row("--no-open", translator.get('no_open_help'))
395
+ opt_table.add_row("--port PORT, -p PORT", translator.get('port_help'))
396
+ opt_table.add_row("--lang {en,es}, -l {en,es}", translator.get('lang_help'))
397
+ console.print(opt_table)
398
+
399
+ sys.exit(0)
400
+
401
+ # Now create the full parser with translated help text
402
+ parser = argparse.ArgumentParser(description=translator.get('preview_description'))
403
+ parser.add_argument("directory", help=translator.get('directory_help'))
404
+ parser.add_argument("--format", "-f", help=translator.get('format_help'))
405
+ parser.add_argument("--no-open", action="store_true", help=translator.get('no_open_help'))
406
+ parser.add_argument("--port", "-p", type=int, default=8000, help=translator.get('port_help'))
407
+ parser.add_argument("--lang", "-l", choices=["en", "es"], default="en", help=translator.get('lang_help'))
408
+
409
+ args = parser.parse_args()
410
+
411
+ success = preview_app(
412
+ args.directory,
413
+ args.format,
414
+ not args.no_open,
415
+ args.port
416
+ )
417
+
418
+ sys.exit(0 if success else 1)
419
+