dars-framework 1.2.3__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.
- dars/__init__.py +0 -0
- dars/all.py +69 -0
- dars/cli/__init__.py +0 -0
- dars/cli/doctor/__init__.py +1 -0
- dars/cli/doctor/detect.py +154 -0
- dars/cli/doctor/doctor.py +176 -0
- dars/cli/doctor/installers.py +100 -0
- dars/cli/doctor/persist.py +62 -0
- dars/cli/doctor/preflight.py +33 -0
- dars/cli/doctor/ui.py +54 -0
- dars/cli/hot_reload.py +33 -0
- dars/cli/main.py +1107 -0
- dars/cli/preview.py +448 -0
- dars/cli/translations.py +531 -0
- dars/components/__init__.py +0 -0
- dars/components/advanced/__init__.py +8 -0
- dars/components/advanced/accordion.py +26 -0
- dars/components/advanced/card.py +33 -0
- dars/components/advanced/modal.py +45 -0
- dars/components/advanced/navbar.py +44 -0
- dars/components/advanced/table.py +25 -0
- dars/components/advanced/tabs.py +31 -0
- dars/components/basic/__init__.py +34 -0
- dars/components/basic/button.py +55 -0
- dars/components/basic/checkbox.py +35 -0
- dars/components/basic/container.py +29 -0
- dars/components/basic/datepicker.py +139 -0
- dars/components/basic/image.py +36 -0
- dars/components/basic/input.py +57 -0
- dars/components/basic/link.py +31 -0
- dars/components/basic/markdown.py +86 -0
- dars/components/basic/page.py +20 -0
- dars/components/basic/progressbar.py +18 -0
- dars/components/basic/radiobutton.py +35 -0
- dars/components/basic/select.py +82 -0
- dars/components/basic/slider.py +63 -0
- dars/components/basic/spinner.py +12 -0
- dars/components/basic/text.py +23 -0
- dars/components/basic/textarea.py +46 -0
- dars/components/basic/tooltip.py +19 -0
- dars/components/layout/__init__.py +0 -0
- dars/components/layout/anchor.py +13 -0
- dars/components/layout/flex.py +26 -0
- dars/components/layout/grid.py +45 -0
- dars/config.py +134 -0
- dars/core/__init__.py +0 -0
- dars/core/app.py +957 -0
- dars/core/component.py +284 -0
- dars/core/events.py +102 -0
- dars/core/js_bridge.py +99 -0
- dars/core/properties.py +127 -0
- dars/core/state.py +309 -0
- dars/dars_tests/apps_test/health_check.py +56 -0
- dars/dars_tests/run_tests.py +275 -0
- dars/dars_tests/tests/test_advanced_components.py +69 -0
- dars/dars_tests/tests/test_basic_components.py +88 -0
- dars/dars_tests/tests/test_core_and_cli.py +17 -0
- dars/dars_tests/tests/test_layout_components.py +58 -0
- dars/dars_tests/tests/test_version_check.py +21 -0
- dars/docs/__init__.py +0 -0
- dars/docs/app.md +290 -0
- dars/docs/cli.md +80 -0
- dars/docs/components.md +1679 -0
- dars/docs/custom_components.md +30 -0
- dars/docs/events.md +45 -0
- dars/docs/exporters.md +162 -0
- dars/docs/getting_started.md +79 -0
- dars/docs/index.md +18 -0
- dars/docs/scripts.md +593 -0
- dars/docs/state_management.md +57 -0
- dars/exporters/__init__.py +0 -0
- dars/exporters/base.py +96 -0
- dars/exporters/web/OLD/html_css_js_OLD4.py +1538 -0
- dars/exporters/web/OLD/html_css_js_old.py +1406 -0
- dars/exporters/web/OLD/html_css_js_old2.py +1406 -0
- dars/exporters/web/__init__.py +0 -0
- dars/exporters/web/html_css_js.py +2675 -0
- dars/exporters/web/vdom.py +251 -0
- dars/js_lib.py +206 -0
- dars/scripts/__init__.py +0 -0
- dars/scripts/dscript.py +26 -0
- dars/scripts/script.py +39 -0
- dars/security.py +195 -0
- dars/templates/__init__.py +0 -0
- dars/templates/__pycache__/__init__.cpython-311.pyc +0 -0
- dars/templates/examples/README.md +4 -0
- dars/templates/examples/__pycache__/dynamic_event_demo.cpython-311.pyc +0 -0
- dars/templates/examples/advanced/Modal_Demo/advanced_modal_demo.py +275 -0
- dars/templates/examples/advanced/SimpleDashboard/dashboard.py +437 -0
- dars/templates/examples/advanced/SimpleModermWeb/modern_web_app.py +452 -0
- dars/templates/examples/advanced/VariousComponents/all_components_demo.py +87 -0
- dars/templates/examples/advanced/__init__.py +0 -0
- dars/templates/examples/advanced/dState/state_mods_demo.py +68 -0
- dars/templates/examples/basic/Forms/form_components.py +516 -0
- dars/templates/examples/basic/Forms/simple_form.py +379 -0
- dars/templates/examples/basic/HelloWorld/hello_world.py +56 -0
- dars/templates/examples/basic/Layouts/flex_layout_responsive.py +13 -0
- dars/templates/examples/basic/Layouts/grid_layout_responsive.py +12 -0
- dars/templates/examples/basic/Layouts/layout_multipage_demo.py +23 -0
- dars/templates/examples/basic/Multipage/multipage_example.py +67 -0
- dars/templates/examples/basic/PWA/icon-192x192.png +0 -0
- dars/templates/examples/basic/PWA/icon-512x512.png +0 -0
- dars/templates/examples/basic/PWA/pwa_custom_icons.py +33 -0
- dars/templates/examples/basic/__init__.py +0 -0
- dars/templates/examples/demo/__pycache__/complete_app.cpython-311.pyc +0 -0
- dars/templates/examples/demo/complete_app.py +21 -0
- dars/templates/examples/markdown/MarkdownTemplate/README.md +159 -0
- dars/templates/examples/markdown/MarkdownTemplate/markdown_template.py +21 -0
- dars/templates/examples/markdown/MarkdownTemplate/other_docs.md +1 -0
- dars/templates/examples/markdown/__init__.py +0 -0
- dars/templates/html/__init__.py +0 -0
- dars/version.py +2 -0
- dars_framework-1.2.3.dist-info/METADATA +15 -0
- dars_framework-1.2.3.dist-info/RECORD +118 -0
- dars_framework-1.2.3.dist-info/WHEEL +5 -0
- dars_framework-1.2.3.dist-info/entry_points.txt +2 -0
- dars_framework-1.2.3.dist-info/licenses/LICENSE +21 -0
- dars_framework-1.2.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import importlib, inspect, sys, os
|
|
2
|
+
from dars.core.component import Component
|
|
3
|
+
from dars.components.basic.text import Text
|
|
4
|
+
|
|
5
|
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'dars'))
|
|
6
|
+
if project_root not in sys.path:
|
|
7
|
+
sys.path.insert(0, project_root)
|
|
8
|
+
|
|
9
|
+
failures = []
|
|
10
|
+
|
|
11
|
+
def test_advanced_components():
|
|
12
|
+
base_pkg = 'dars.components.advanced'
|
|
13
|
+
try:
|
|
14
|
+
pkg = importlib.import_module(base_pkg)
|
|
15
|
+
except Exception as e:
|
|
16
|
+
raise AssertionError(f'Could not import {base_pkg}: {e}')
|
|
17
|
+
|
|
18
|
+
pkg_path = os.path.dirname(pkg.__file__)
|
|
19
|
+
for fname in os.listdir(pkg_path):
|
|
20
|
+
if not fname.endswith('.py') or fname.startswith('__'):
|
|
21
|
+
continue
|
|
22
|
+
|
|
23
|
+
modname = f"{base_pkg}.{fname[:-3]}"
|
|
24
|
+
try:
|
|
25
|
+
m = importlib.import_module(modname)
|
|
26
|
+
except Exception as e:
|
|
27
|
+
failures.append((modname, 'import', repr(e)))
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
for _name, obj in inspect.getmembers(m, inspect.isclass):
|
|
31
|
+
try:
|
|
32
|
+
if obj is Component:
|
|
33
|
+
continue
|
|
34
|
+
if issubclass(obj, Component):
|
|
35
|
+
# Proporciona argumentos específicos para cada componente avanzado
|
|
36
|
+
if _name == 'Accordion':
|
|
37
|
+
instance = obj(sections=[{'title': 'Test', 'content': 'Content'}])
|
|
38
|
+
elif _name == 'Table':
|
|
39
|
+
instance = obj(columns=['Col1'], data=[['Data1']])
|
|
40
|
+
elif _name == 'Tabs':
|
|
41
|
+
instance = obj(tabs=['Tab1'], panels=[Text('Panel1')])
|
|
42
|
+
elif _name == 'Card':
|
|
43
|
+
instance = obj(title='Test Card')
|
|
44
|
+
elif _name == 'Modal':
|
|
45
|
+
instance = obj(title='Test Modal')
|
|
46
|
+
elif _name == 'Navbar':
|
|
47
|
+
instance = obj(brand='Test Navbar')
|
|
48
|
+
else:
|
|
49
|
+
# Intenta con argumentos mínimos para otros componentes
|
|
50
|
+
try:
|
|
51
|
+
instance = obj()
|
|
52
|
+
except TypeError:
|
|
53
|
+
instance = obj(id='test')
|
|
54
|
+
|
|
55
|
+
# Verifica que la instancia se creó correctamente
|
|
56
|
+
assert instance is not None, f"Failed to create instance of {_name}"
|
|
57
|
+
|
|
58
|
+
except Exception as e:
|
|
59
|
+
failures.append((f"{modname}.{_name}", 'init', repr(e)))
|
|
60
|
+
|
|
61
|
+
assert not failures, failures
|
|
62
|
+
|
|
63
|
+
if __name__ == '__main__':
|
|
64
|
+
try:
|
|
65
|
+
test_advanced_components()
|
|
66
|
+
print('test_advanced_components: OK')
|
|
67
|
+
except AssertionError as e:
|
|
68
|
+
print('test_advanced_components: FAIL', e)
|
|
69
|
+
sys.exit(1)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import importlib, inspect, sys, os
|
|
2
|
+
from dars.core.component import Component
|
|
3
|
+
|
|
4
|
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'dars'))
|
|
5
|
+
if project_root not in sys.path:
|
|
6
|
+
sys.path.insert(0, project_root)
|
|
7
|
+
|
|
8
|
+
failures = []
|
|
9
|
+
|
|
10
|
+
def test_basic_components():
|
|
11
|
+
base_pkg = 'dars.components.basic'
|
|
12
|
+
try:
|
|
13
|
+
pkg = importlib.import_module(base_pkg)
|
|
14
|
+
except Exception as e:
|
|
15
|
+
failures.append((base_pkg, 'import', repr(e)))
|
|
16
|
+
return
|
|
17
|
+
|
|
18
|
+
pkg_path = os.path.dirname(pkg.__file__)
|
|
19
|
+
for fname in os.listdir(pkg_path):
|
|
20
|
+
if not fname.endswith('.py') or fname.startswith('__'):
|
|
21
|
+
continue
|
|
22
|
+
|
|
23
|
+
modname = f"{base_pkg}.{fname[:-3]}"
|
|
24
|
+
try:
|
|
25
|
+
m = importlib.import_module(modname)
|
|
26
|
+
except Exception as e:
|
|
27
|
+
failures.append((modname, 'import', repr(e)))
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
for _name, obj in inspect.getmembers(m, inspect.isclass):
|
|
31
|
+
try:
|
|
32
|
+
if obj is Component:
|
|
33
|
+
continue
|
|
34
|
+
if issubclass(obj, Component):
|
|
35
|
+
# Proporciona argumentos específicos para cada componente
|
|
36
|
+
if _name == 'Image':
|
|
37
|
+
instance = obj(src='test.png')
|
|
38
|
+
elif _name == 'Link':
|
|
39
|
+
instance = obj(text='Test', href='#')
|
|
40
|
+
elif _name == 'Markdown':
|
|
41
|
+
instance = obj(content='# Test')
|
|
42
|
+
elif _name == 'ProgressBar':
|
|
43
|
+
instance = obj(value=50)
|
|
44
|
+
elif _name == 'Tooltip':
|
|
45
|
+
from dars.components.basic.text import Text
|
|
46
|
+
instance = obj(text='Tip', child=Text('Hover me'))
|
|
47
|
+
elif _name == 'Button':
|
|
48
|
+
instance = obj(text='Test Button')
|
|
49
|
+
elif _name == 'Input':
|
|
50
|
+
instance = obj()
|
|
51
|
+
elif _name == 'Textarea':
|
|
52
|
+
instance = obj()
|
|
53
|
+
elif _name == 'Checkbox':
|
|
54
|
+
instance = obj(label='Test Checkbox')
|
|
55
|
+
elif _name == 'RadioButton':
|
|
56
|
+
instance = obj(label='Test Radio', name='test_radio')
|
|
57
|
+
elif _name == 'Select':
|
|
58
|
+
instance = obj(options=[{'value': 'test', 'label': 'Test'}])
|
|
59
|
+
elif _name == 'Slider':
|
|
60
|
+
instance = obj()
|
|
61
|
+
elif _name == 'DatePicker':
|
|
62
|
+
instance = obj()
|
|
63
|
+
elif _name == 'Container':
|
|
64
|
+
instance = obj()
|
|
65
|
+
elif _name == 'Text':
|
|
66
|
+
instance = obj(text='Test Text')
|
|
67
|
+
else:
|
|
68
|
+
# Intenta con argumentos mínimos para otros componentes
|
|
69
|
+
try:
|
|
70
|
+
instance = obj()
|
|
71
|
+
except TypeError:
|
|
72
|
+
instance = obj(id='test', class_name='c', style={})
|
|
73
|
+
|
|
74
|
+
# Verifica que la instancia se creó correctamente
|
|
75
|
+
assert instance is not None, f"Failed to create instance of {_name}"
|
|
76
|
+
|
|
77
|
+
except Exception as e:
|
|
78
|
+
failures.append((f"{modname}.{_name}", 'init', repr(e)))
|
|
79
|
+
|
|
80
|
+
assert not failures, failures
|
|
81
|
+
|
|
82
|
+
if __name__ == '__main__':
|
|
83
|
+
try:
|
|
84
|
+
test_basic_components()
|
|
85
|
+
print('test_basic_components: OK')
|
|
86
|
+
except AssertionError as e:
|
|
87
|
+
print('test_basic_components: FAIL', e)
|
|
88
|
+
sys.exit(1)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import importlib, sys, os
|
|
2
|
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'dars'))
|
|
3
|
+
if project_root not in sys.path:
|
|
4
|
+
sys.path.insert(0, project_root)
|
|
5
|
+
|
|
6
|
+
def test_core_imports():
|
|
7
|
+
import dars.core.app as app
|
|
8
|
+
import dars.core.component as component
|
|
9
|
+
import dars.cli.main as cli_main
|
|
10
|
+
# smoke tests: ensure some expected names exist
|
|
11
|
+
assert hasattr(app, 'App') or hasattr(app, 'Page'), 'app module missing App/Page'
|
|
12
|
+
assert hasattr(component, 'Component'), 'component missing Component'
|
|
13
|
+
assert hasattr(cli_main, 'main') or hasattr(cli_main, 'run'), 'cli main missing entrypoint'
|
|
14
|
+
print('core_and_cli: OK')
|
|
15
|
+
|
|
16
|
+
if __name__ == '__main__':
|
|
17
|
+
test_core_imports()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import importlib, inspect, sys, os
|
|
2
|
+
from dars.core.component import Component
|
|
3
|
+
|
|
4
|
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'dars'))
|
|
5
|
+
if project_root not in sys.path:
|
|
6
|
+
sys.path.insert(0, project_root)
|
|
7
|
+
|
|
8
|
+
failures = []
|
|
9
|
+
|
|
10
|
+
def test_layout_components():
|
|
11
|
+
base_pkg = 'dars.components.layout'
|
|
12
|
+
try:
|
|
13
|
+
pkg = importlib.import_module(base_pkg)
|
|
14
|
+
except Exception as e:
|
|
15
|
+
raise AssertionError(f'Could not import {base_pkg}: {e}')
|
|
16
|
+
|
|
17
|
+
pkg_path = os.path.dirname(pkg.__file__)
|
|
18
|
+
for fname in os.listdir(pkg_path):
|
|
19
|
+
if not fname.endswith('.py') or fname.startswith('__'):
|
|
20
|
+
continue
|
|
21
|
+
|
|
22
|
+
modname = f"{base_pkg}.{fname[:-3]}"
|
|
23
|
+
try:
|
|
24
|
+
m = importlib.import_module(modname)
|
|
25
|
+
except Exception as e:
|
|
26
|
+
failures.append((modname, 'import', repr(e)))
|
|
27
|
+
continue
|
|
28
|
+
|
|
29
|
+
for _name, obj in inspect.getmembers(m, inspect.isclass):
|
|
30
|
+
try:
|
|
31
|
+
if obj is Component:
|
|
32
|
+
continue
|
|
33
|
+
if issubclass(obj, Component):
|
|
34
|
+
# Intenta crear una instancia con argumentos mínimos
|
|
35
|
+
try:
|
|
36
|
+
instance = obj()
|
|
37
|
+
except TypeError:
|
|
38
|
+
try:
|
|
39
|
+
instance = obj(id='test')
|
|
40
|
+
except Exception as e:
|
|
41
|
+
failures.append((f"{modname}.{_name}", 'init', repr(e)))
|
|
42
|
+
|
|
43
|
+
# Verifica que la instancia se creó correctamente
|
|
44
|
+
if 'instance' in locals():
|
|
45
|
+
assert instance is not None, f"Failed to create instance of {_name}"
|
|
46
|
+
|
|
47
|
+
except Exception as e:
|
|
48
|
+
failures.append((f"{modname}.{_name}", 'inspect', repr(e)))
|
|
49
|
+
|
|
50
|
+
assert not failures, failures
|
|
51
|
+
|
|
52
|
+
if __name__ == '__main__':
|
|
53
|
+
try:
|
|
54
|
+
test_layout_components()
|
|
55
|
+
print('test_layout_components: OK')
|
|
56
|
+
except AssertionError as e:
|
|
57
|
+
print('test_layout_components: FAIL', e)
|
|
58
|
+
sys.exit(1)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import importlib, sys, os
|
|
2
|
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'dars'))
|
|
3
|
+
if project_root not in sys.path:
|
|
4
|
+
sys.path.insert(0, project_root)
|
|
5
|
+
import dars.version as ver
|
|
6
|
+
|
|
7
|
+
# Latest version observed on PyPI / mirrors during analysis: 1.1.3
|
|
8
|
+
LATEST_KNOWN = '1.1.3'
|
|
9
|
+
|
|
10
|
+
def test_version_comparison():
|
|
11
|
+
local = getattr(ver, '__version__', None)
|
|
12
|
+
assert local is not None, 'local version not found in dars.version'
|
|
13
|
+
print(f'local_version={local}; latest_known={LATEST_KNOWN}')
|
|
14
|
+
# The test will not fail if local is newer (dev), but will warn via printing when local differs.
|
|
15
|
+
if local != LATEST_KNOWN:
|
|
16
|
+
print('WARNING: local package version differs from LATEST_KNOWN (see test output).')
|
|
17
|
+
else:
|
|
18
|
+
print('version_check: OK')
|
|
19
|
+
|
|
20
|
+
if __name__ == '__main__':
|
|
21
|
+
test_version_comparison()
|
dars/docs/__init__.py
ADDED
|
File without changes
|
dars/docs/app.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# App Class and PWA Features in Dars Framework
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `App` class is the core of any Dars Framework application. It represents the complete application and manages all configuration, components, pages, and functionalities, including Progressive Web App (PWA) support.
|
|
6
|
+
|
|
7
|
+
## Basic Structure
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
class App:
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
title: str = "Dars App",
|
|
14
|
+
description: str = "",
|
|
15
|
+
author: str = "",
|
|
16
|
+
keywords: List[str] = None,
|
|
17
|
+
language: str = "en",
|
|
18
|
+
favicon: str = "",
|
|
19
|
+
icon: str = "",
|
|
20
|
+
apple_touch_icon: str = "",
|
|
21
|
+
manifest: str = "",
|
|
22
|
+
theme_color: str = "#000000",
|
|
23
|
+
background_color: str = "#ffffff",
|
|
24
|
+
service_worker_path: str = "",
|
|
25
|
+
service_worker_enabled: bool = False,
|
|
26
|
+
**config
|
|
27
|
+
):
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Global Styles Management
|
|
31
|
+
|
|
32
|
+
### Enhanced add_global_style() Method
|
|
33
|
+
|
|
34
|
+
The `App` class now includes an enhanced `add_global_style()` method that supports both inline style definitions and external CSS file imports.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
#### Usage Examples
|
|
38
|
+
|
|
39
|
+
**1. Inline Style Definition (Traditional)**
|
|
40
|
+
```python
|
|
41
|
+
app.add_global_style(
|
|
42
|
+
selector=".my-button",
|
|
43
|
+
styles={
|
|
44
|
+
"background-color": "#4CAF50",
|
|
45
|
+
"color": "white",
|
|
46
|
+
"padding": "10px 20px",
|
|
47
|
+
"border-radius": "5px"
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**2. External CSS File Import (New in v1.1.2)**
|
|
53
|
+
```python
|
|
54
|
+
app.add_global_style(file_path="styles.css")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**3. Combined Usage**
|
|
58
|
+
```python
|
|
59
|
+
# Add inline styles
|
|
60
|
+
app.add_global_style(
|
|
61
|
+
selector=".primary-btn",
|
|
62
|
+
styles={
|
|
63
|
+
"background-color": "#007bff",
|
|
64
|
+
"color": "white"
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Import external CSS file
|
|
69
|
+
app.add_global_style(file_path="components.css")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### Practical Example with External CSS
|
|
73
|
+
|
|
74
|
+
**main.py:**
|
|
75
|
+
```python
|
|
76
|
+
from dars.all import *
|
|
77
|
+
|
|
78
|
+
app = App(title="Dars Styling Test")
|
|
79
|
+
|
|
80
|
+
index = Page(
|
|
81
|
+
Container(
|
|
82
|
+
Button("Styled Button", class_name="button-styling-test"),
|
|
83
|
+
id="page_sub_container"
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
app.add_page(name="index", root=index, title="index", index=True)
|
|
88
|
+
app.add_global_style(file_path="styles.css")
|
|
89
|
+
|
|
90
|
+
if __name__ == "__main__":
|
|
91
|
+
app.rTimeCompile(add_file_types=".py, .css")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**styles.css:**
|
|
95
|
+
```css
|
|
96
|
+
.button-styling-test {
|
|
97
|
+
background-color: rgb(51, 255, 0);
|
|
98
|
+
padding: 15px 30px;
|
|
99
|
+
border-radius: 8px;
|
|
100
|
+
border: none;
|
|
101
|
+
font-weight: bold;
|
|
102
|
+
cursor: pointer;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.button-styling-test:hover {
|
|
106
|
+
background-color: rgb(30, 200, 0);
|
|
107
|
+
transform: scale(1.05);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
#page_sub_container {
|
|
111
|
+
padding: 20px;
|
|
112
|
+
background-color: #f5f5f5;
|
|
113
|
+
min-height: 100vh;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Hot Reload for CSS Files
|
|
118
|
+
|
|
119
|
+
When using `app.rTimeCompile()` with the `add_file_types=".css"` parameter, the development server automatically watches for changes in CSS files and reloads the application when modifications are detected.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
# Watch for both Python and CSS file changes
|
|
123
|
+
app.rTimeCompile(add_file_types=".py, .css")
|
|
124
|
+
|
|
125
|
+
# Or watch for CSS files only
|
|
126
|
+
app.rTimeCompile(add_file_types=".css")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Benefits of External CSS Import
|
|
130
|
+
|
|
131
|
+
1. **Separation of Concerns**: Keep styles separate from application logic
|
|
132
|
+
2. **Better Organization**: Maintain complex stylesheets in dedicated files
|
|
133
|
+
3. **Team Collaboration**: Designers and developers can work simultaneously
|
|
134
|
+
4. **CSS Preprocessors**: Use SASS, LESS, or other preprocessors
|
|
135
|
+
5. **Performance**: Browser caching for external CSS files
|
|
136
|
+
|
|
137
|
+
### Backward Compatibility
|
|
138
|
+
|
|
139
|
+
The enhanced method maintains full backward compatibility - existing code using `add_global_style(selector, styles)` will continue to work without modification.
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
## PWA Configuration Properties
|
|
143
|
+
|
|
144
|
+
The App class includes these PWA-specific properties:
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
# Icons and visual resources
|
|
148
|
+
self.favicon = favicon # Path to traditional favicon
|
|
149
|
+
self.icon = icon # Main icon for PWA (multiple sizes)
|
|
150
|
+
self.apple_touch_icon = apple_touch_icon # Icon for Apple devices
|
|
151
|
+
self.manifest = manifest # Path to manifest.json file
|
|
152
|
+
|
|
153
|
+
# Colors and theme
|
|
154
|
+
self.theme_color = theme_color # Theme color (#RRGGBB)
|
|
155
|
+
self.background_color = background_color # Background color for splash screens
|
|
156
|
+
|
|
157
|
+
# Service Worker
|
|
158
|
+
self.service_worker_path = service_worker_path # Path to service worker file
|
|
159
|
+
self.service_worker_enabled = service_worker_enabled # Enable/disable
|
|
160
|
+
|
|
161
|
+
# Additional PWA configuration
|
|
162
|
+
self.pwa_enabled = config.get('pwa_enabled', False)
|
|
163
|
+
self.pwa_name = config.get('pwa_name', title)
|
|
164
|
+
self.pwa_short_name = config.get('pwa_short_name', title[:12])
|
|
165
|
+
self.pwa_display = config.get('pwa_display', 'standalone')
|
|
166
|
+
self.pwa_orientation = config.get('pwa_orientation', 'portrait')
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Meta Tag Generation for PWA
|
|
170
|
+
|
|
171
|
+
The App class provides methods to generate PWA meta tags:
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
def get_meta_tags(self) -> Dict[str, str]:
|
|
175
|
+
"""Returns all meta tags as a dictionary"""
|
|
176
|
+
meta_tags = {}
|
|
177
|
+
|
|
178
|
+
# Viewport configured for responsiveness
|
|
179
|
+
viewport_parts = []
|
|
180
|
+
for key, value in self.config['viewport'].items():
|
|
181
|
+
if key == 'initial_scale':
|
|
182
|
+
viewport_parts.append(f'initial-scale={value}')
|
|
183
|
+
elif key == 'user_scalable':
|
|
184
|
+
viewport_parts.append(f'user-scalable={value}')
|
|
185
|
+
else:
|
|
186
|
+
viewport_parts.append(f'{key.replace("_", "-")}={value}')
|
|
187
|
+
meta_tags['viewport'] = ', '.join(viewport_parts)
|
|
188
|
+
|
|
189
|
+
# Specific tags for PWA
|
|
190
|
+
meta_tags['theme-color'] = self.theme_color
|
|
191
|
+
if self.pwa_enabled:
|
|
192
|
+
meta_tags['mobile-web-app-capable'] = 'yes'
|
|
193
|
+
meta_tags['apple-mobile-web-app-capable'] = 'yes'
|
|
194
|
+
meta_tags['apple-mobile-web-app-status-bar-style'] = 'default'
|
|
195
|
+
meta_tags['apple-mobile-web-app-title'] = self.pwa_short_name
|
|
196
|
+
|
|
197
|
+
return meta_tags
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Integration with HTML/CSS/JS Exporter
|
|
201
|
+
|
|
202
|
+
The `HTMLCSSJSExporter` uses the PWA configuration from the App class to generate:
|
|
203
|
+
|
|
204
|
+
1. **manifest.json file** - Progressive web app configuration
|
|
205
|
+
2. **Meta tags** - To indicate PWA capabilities in different browsers
|
|
206
|
+
3. **Icon references** - For multiple devices and sizes
|
|
207
|
+
4. **Service Worker registration** - For offline functionality
|
|
208
|
+
|
|
209
|
+
### Example of Generated Manifest.json
|
|
210
|
+
|
|
211
|
+
```json
|
|
212
|
+
{
|
|
213
|
+
"name": "App Name",
|
|
214
|
+
"short_name": "Short Name",
|
|
215
|
+
"description": "Application description",
|
|
216
|
+
"start_url": "/",
|
|
217
|
+
"display": "standalone",
|
|
218
|
+
"background_color": "#ffffff",
|
|
219
|
+
"theme_color": "#000000",
|
|
220
|
+
"orientation": "portrait",
|
|
221
|
+
"icons": [
|
|
222
|
+
{
|
|
223
|
+
"src": "icon-192x192.png",
|
|
224
|
+
"sizes": "192x192",
|
|
225
|
+
"type": "image/png"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"src": "icon-512x512.png",
|
|
229
|
+
"sizes": "512x512",
|
|
230
|
+
"type": "image/png"
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Service Worker Registration Script
|
|
237
|
+
|
|
238
|
+
The exporter automatically generates code to register the service worker:
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
if ('serviceWorker' in navigator && '{service_worker_path}') {
|
|
242
|
+
window.addEventListener('load', function() {
|
|
243
|
+
navigator.serviceWorker.register('{service_worker_path}')
|
|
244
|
+
.then(function(registration) {
|
|
245
|
+
console.log('ServiceWorker registration successful');
|
|
246
|
+
})
|
|
247
|
+
.catch(function(error) {
|
|
248
|
+
console.log('ServiceWorker registration failed: ', error);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Complete PWA App Configuration Example
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
# Create a complete PWA application
|
|
258
|
+
app = App(
|
|
259
|
+
title="My PWA App",
|
|
260
|
+
description="An amazing progressive application",
|
|
261
|
+
author="My Company",
|
|
262
|
+
keywords=["pwa", "webapp", "productivity"],
|
|
263
|
+
language="en",
|
|
264
|
+
favicon="assets/favicon.ico",
|
|
265
|
+
icon="assets/icon-192x192.png",
|
|
266
|
+
apple_touch_icon="assets/apple-touch-icon.png",
|
|
267
|
+
theme_color="#4A90E2",
|
|
268
|
+
background_color="#FFFFFF",
|
|
269
|
+
service_worker_path="sw.js",
|
|
270
|
+
service_worker_enabled=True,
|
|
271
|
+
pwa_enabled=True,
|
|
272
|
+
pwa_name="My App",
|
|
273
|
+
pwa_short_name="MyApp",
|
|
274
|
+
pwa_display="standalone"
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# Add pages and components
|
|
278
|
+
app.add_page("home", HomeComponent(), title="Home", index=True)
|
|
279
|
+
app.add_page("about", AboutComponent(), title="About")
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Implementation Considerations
|
|
283
|
+
|
|
284
|
+
### Browser Compatibility
|
|
285
|
+
|
|
286
|
+
Dars Framework's PWA implementation is compatible with:
|
|
287
|
+
- Chrome/Chromium (full support)
|
|
288
|
+
- Firefox (basic support)
|
|
289
|
+
- Safari (limited support on iOS)
|
|
290
|
+
- Edge (full support)
|
dars/docs/cli.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Dars CLI Reference
|
|
2
|
+
|
|
3
|
+
The Dars Command Line Interface (CLI) lets you manage your projects, export apps, and preview results quickly from the terminal.
|
|
4
|
+
|
|
5
|
+
## How to Use the CLI
|
|
6
|
+
|
|
7
|
+
Open your terminal in your project directory and use any of the following commands:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Show information about your app
|
|
11
|
+
dars info my_app.py
|
|
12
|
+
|
|
13
|
+
# Export to different formats
|
|
14
|
+
dars export my_app.py --format html --output ./output
|
|
15
|
+
|
|
16
|
+
# List supported export formats
|
|
17
|
+
dars formats
|
|
18
|
+
|
|
19
|
+
# Initialize a new project
|
|
20
|
+
dars init my_new_project
|
|
21
|
+
|
|
22
|
+
# Initialize a project with a specific template
|
|
23
|
+
dars init my_new_project -t demo/complete_app
|
|
24
|
+
|
|
25
|
+
# Preview an exported app
|
|
26
|
+
dars preview ./output_directory
|
|
27
|
+
|
|
28
|
+
# Help
|
|
29
|
+
dars --help
|
|
30
|
+
|
|
31
|
+
# Version
|
|
32
|
+
dars -v
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Main Commands Table
|
|
36
|
+
| Command | What it does |
|
|
37
|
+
|-----------------------------------------|--------------------------------------------|
|
|
38
|
+
| `dars export my_app.py --format html` | Export app to HTML/CSS/JS in `./my_app_web` |
|
|
39
|
+
| `dars preview ./my_app_web` | Preview exported app locally |
|
|
40
|
+
| `dars init my_project` | Create a new Dars project |
|
|
41
|
+
| `dars info my_app.py` | Show info about your app |
|
|
42
|
+
| `dars formats` | List supported export formats |
|
|
43
|
+
| `dars --help` | Show help and all CLI options |
|
|
44
|
+
|
|
45
|
+
## Using Official Templates
|
|
46
|
+
|
|
47
|
+
Dars provides official templates to help you start new projects quickly. Templates include ready-to-use apps for forms, layouts, dashboards, multipage, and more.
|
|
48
|
+
|
|
49
|
+
### How to Use a Template
|
|
50
|
+
|
|
51
|
+
1. **Initialize a new project with a template:**
|
|
52
|
+
```bash
|
|
53
|
+
dars init my_new_project -t basic/HelloWorld
|
|
54
|
+
# ...and more (see below)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
You can see the templates available with
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
dars init --list-templates
|
|
61
|
+
dars init -L
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
2. **Export the template to HTML/CSS/JS:**
|
|
65
|
+
```bash
|
|
66
|
+
dars export main.py --format html --output ./hello_output
|
|
67
|
+
dars export main.py --format html --output ./dashboard_output
|
|
68
|
+
# ...etc
|
|
69
|
+
```
|
|
70
|
+
3. **Preview the exported app:**
|
|
71
|
+
```bash
|
|
72
|
+
dars preview ./hello_output
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Tips
|
|
76
|
+
- Use `dars --help` for a full list of commands and options.
|
|
77
|
+
- You can preview apps either live (with `app.rTimeCompile()`) or from exported files with `dars preview`.
|
|
78
|
+
- Templates are available for quick project setup: use `dars init my_project -t <template>`.
|
|
79
|
+
|
|
80
|
+
For more, see the [Getting Started](getting_started.md) guide and the main documentation index.
|