SaaS-FrameWork 0.1.2__tar.gz → 0.1.3__tar.gz
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.
- {saas_framework-0.1.2 → saas_framework-0.1.3}/MANIFEST.in +1 -1
- {saas_framework-0.1.2 → saas_framework-0.1.3}/PKG-INFO +18 -10
- {saas_framework-0.1.2 → saas_framework-0.1.3}/README.md +15 -9
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/data/DEx_DataTable.py +20 -4
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/feedback/DEx_AlertDialog.py +8 -2
- saas_framework-0.1.3/components/inputs/DEx_Dropdown.py +41 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_TextField.py +18 -2
- saas_framework-0.1.3/components/layout/DEx_AppShell.py +137 -0
- saas_framework-0.1.3/components/layout/DEx_Header.py +80 -0
- saas_framework-0.1.3/components/layout/DEx_Sidebar.py +177 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/metadata.py +9 -9
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/project.py +23 -19
- {saas_framework-0.1.2 → saas_framework-0.1.3}/pyproject.toml +5 -2
- saas_framework-0.1.2/components/inputs/DEx_Dropdown.py +0 -25
- saas_framework-0.1.2/components/layout/DEx_AppShell.py +0 -80
- saas_framework-0.1.2/components/layout/DEx_Header.py +0 -57
- saas_framework-0.1.2/components/layout/DEx_Sidebar.py +0 -131
- {saas_framework-0.1.2 → saas_framework-0.1.3}/SaaS_FrameWork.egg-info/SOURCES.txt +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/__init__.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/DEx_BtnFAB.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/DEx_BtnFilled.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/DEx_BtnGhost.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/DEx_BtnIcon.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/DEx_BtnPrimary.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/DEx_BtnSegmented.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/DEx_BtnText.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/DEx_BtnTonal.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/DEx_MenuBar.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/DEx_PopupMenu.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/buttons/__init__.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/cards/DEx_Card.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/cards/DEx_ContactCard.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/cards/DEx_MetricCard.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/cards/__init__.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/data/DEx_ExpansionPanel.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/data/DEx_ExpansionTile.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/data/DEx_GridView.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/data/DEx_ListTile.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/data/DEx_ListView.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/data/DEx_PipelineColumn.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/data/DEx_TreeView.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/data/__init__.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/feedback/DEx_Banner.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/feedback/DEx_BottomSheet.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/feedback/DEx_Notify.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/feedback/DEx_ProgressBar.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/feedback/DEx_ProgressRing.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/feedback/DEx_Shimmer.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/feedback/DEx_Tooltip.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/feedback/__init__.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_AutoComplete.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_Checkbox.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_Chip.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_DatePicker.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_FilePicker.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_Radio.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_SearchBar.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_SearchField.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_Slider.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_Switch.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_TagInput.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/DEx_TimePicker.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/inputs/__init__.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_AnimatedSwitcher.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_AppBar.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_Draggable.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_GestureDetector.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_Marquee.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_NavItem.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_NavigationBar.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_NavigationDrawer.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_NavigationRail.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_ResponsiveRow.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_Splitter.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_Stack.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/DEx_Tabs.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/layout/__init__.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/primitives/DEx_Avatar.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/primitives/DEx_Badge.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/primitives/DEx_Divider.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/primitives/DEx_Icon.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/primitives/DEx_Image.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/primitives/DEx_Markdown.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/primitives/DEx_SectionEyebrow.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/primitives/DEx_StatusDot.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/primitives/__init__.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/theme/DEx_ColorThemes.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/theme/DEx_Theme.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/theme/__init__.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/components/versioning.py +0 -0
- {saas_framework-0.1.2 → saas_framework-0.1.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SaaS-FrameWork
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: SaaS-FrameWork - sistema de componentes reutilizaveis para apps SaaS construido com Python e Flet
|
|
5
5
|
Author-email: Almir Duarte <almir.jg@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -13,6 +13,8 @@ Classifier: Topic :: Software Development :: User Interfaces
|
|
|
13
13
|
Requires-Python: >=3.13
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
Requires-Dist: flet==0.84.0
|
|
16
|
+
Provides-Extra: web
|
|
17
|
+
Requires-Dist: flet-web==0.84.0; extra == "web"
|
|
16
18
|
Provides-Extra: dev
|
|
17
19
|
Requires-Dist: flet==0.84.0; extra == "dev"
|
|
18
20
|
Requires-Dist: pytest<10,>=9.1; extra == "dev"
|
|
@@ -86,7 +88,7 @@ The following folders are repository assets and are intentionally excluded from
|
|
|
86
88
|
|
|
87
89
|
- `catalog/`: local visual catalog and inspection tool.
|
|
88
90
|
- `use_cases/`: executable examples for development and documentation.
|
|
89
|
-
- `
|
|
91
|
+
- `Diretrizes/`: project guidelines — prompts, design/component documentation, management artifacts, and QA evidence.
|
|
90
92
|
- `_base/`: preserved reference material.
|
|
91
93
|
|
|
92
94
|
This separation is enforced in `pyproject.toml` through `tool.setuptools.packages.find`.
|
|
@@ -98,8 +100,8 @@ Adding a public component requires all of the following:
|
|
|
98
100
|
- entry in `components/metadata.py`
|
|
99
101
|
- public export in `components/__init__.py`
|
|
100
102
|
- use case `use_cases/UC_<Name>_01.py`
|
|
101
|
-
- documentation `
|
|
102
|
-
- four structure images in `
|
|
103
|
+
- documentation `Diretrizes/design/components/Documentação/DEx_<Name>.md`
|
|
104
|
+
- four structure images in `Diretrizes/design/components/images/`
|
|
103
105
|
|
|
104
106
|
The repository governance tests fail when this contract is broken.
|
|
105
107
|
|
|
@@ -126,8 +128,14 @@ SaaS-Framework/
|
|
|
126
128
|
| |-- UC_TreeView_01.py
|
|
127
129
|
| `-- UC_ColorThemes_01.py
|
|
128
130
|
|-- catalog/
|
|
129
|
-
| `--
|
|
130
|
-
|--
|
|
131
|
+
| `-- catalog.py
|
|
132
|
+
|-- Diretrizes/
|
|
133
|
+
| |-- Dados/ data artifacts (DDL, DML, scripts)
|
|
134
|
+
| |-- Prompt/ prompt files
|
|
135
|
+
| |-- design/ design references and component docs/images
|
|
136
|
+
| | `-- components/
|
|
137
|
+
| |-- gestao/ roadmap, policies, and management reports
|
|
138
|
+
| `-- qa/ QA evidence
|
|
131
139
|
|-- AGENTS.md
|
|
132
140
|
|-- pyproject.toml
|
|
133
141
|
`-- README.md
|
|
@@ -153,14 +161,14 @@ Run the catalog as desktop app:
|
|
|
153
161
|
|
|
154
162
|
```cmd
|
|
155
163
|
call C:\Python\venv\.venv_313_FW\Scripts\activate.bat
|
|
156
|
-
flet run catalog/
|
|
164
|
+
flet run catalog/catalog.py
|
|
157
165
|
```
|
|
158
166
|
|
|
159
167
|
Run as web catalog only when browser validation is required:
|
|
160
168
|
|
|
161
169
|
```cmd
|
|
162
170
|
call C:\Python\venv\.venv_313_FW\Scripts\activate.bat
|
|
163
|
-
flet run --web --port 8550 catalog/
|
|
171
|
+
flet run --web --port 8550 catalog/catalog.py
|
|
164
172
|
```
|
|
165
173
|
|
|
166
174
|
Run a use case:
|
|
@@ -219,12 +227,12 @@ The script builds the package, checks the artifacts, and uploads to TestPyPI or
|
|
|
219
227
|
With the documented Flet environment:
|
|
220
228
|
|
|
221
229
|
```cmd
|
|
222
|
-
C:\Python\venv\.venv_313_FW\Scripts\python.exe -c "import catalog.
|
|
230
|
+
C:\Python\venv\.venv_313_FW\Scripts\python.exe -c "import catalog.constants as c; print(c.PROJECT_VERSION)"
|
|
223
231
|
```
|
|
224
232
|
|
|
225
233
|
## Catalog
|
|
226
234
|
|
|
227
|
-
The catalog entry point is `catalog/
|
|
235
|
+
The catalog entry point is `catalog/catalog.py`.
|
|
228
236
|
|
|
229
237
|
It follows the project window structure:
|
|
230
238
|
|
|
@@ -63,7 +63,7 @@ The following folders are repository assets and are intentionally excluded from
|
|
|
63
63
|
|
|
64
64
|
- `catalog/`: local visual catalog and inspection tool.
|
|
65
65
|
- `use_cases/`: executable examples for development and documentation.
|
|
66
|
-
- `
|
|
66
|
+
- `Diretrizes/`: project guidelines — prompts, design/component documentation, management artifacts, and QA evidence.
|
|
67
67
|
- `_base/`: preserved reference material.
|
|
68
68
|
|
|
69
69
|
This separation is enforced in `pyproject.toml` through `tool.setuptools.packages.find`.
|
|
@@ -75,8 +75,8 @@ Adding a public component requires all of the following:
|
|
|
75
75
|
- entry in `components/metadata.py`
|
|
76
76
|
- public export in `components/__init__.py`
|
|
77
77
|
- use case `use_cases/UC_<Name>_01.py`
|
|
78
|
-
- documentation `
|
|
79
|
-
- four structure images in `
|
|
78
|
+
- documentation `Diretrizes/design/components/Documentação/DEx_<Name>.md`
|
|
79
|
+
- four structure images in `Diretrizes/design/components/images/`
|
|
80
80
|
|
|
81
81
|
The repository governance tests fail when this contract is broken.
|
|
82
82
|
|
|
@@ -103,8 +103,14 @@ SaaS-Framework/
|
|
|
103
103
|
| |-- UC_TreeView_01.py
|
|
104
104
|
| `-- UC_ColorThemes_01.py
|
|
105
105
|
|-- catalog/
|
|
106
|
-
| `--
|
|
107
|
-
|--
|
|
106
|
+
| `-- catalog.py
|
|
107
|
+
|-- Diretrizes/
|
|
108
|
+
| |-- Dados/ data artifacts (DDL, DML, scripts)
|
|
109
|
+
| |-- Prompt/ prompt files
|
|
110
|
+
| |-- design/ design references and component docs/images
|
|
111
|
+
| | `-- components/
|
|
112
|
+
| |-- gestao/ roadmap, policies, and management reports
|
|
113
|
+
| `-- qa/ QA evidence
|
|
108
114
|
|-- AGENTS.md
|
|
109
115
|
|-- pyproject.toml
|
|
110
116
|
`-- README.md
|
|
@@ -130,14 +136,14 @@ Run the catalog as desktop app:
|
|
|
130
136
|
|
|
131
137
|
```cmd
|
|
132
138
|
call C:\Python\venv\.venv_313_FW\Scripts\activate.bat
|
|
133
|
-
flet run catalog/
|
|
139
|
+
flet run catalog/catalog.py
|
|
134
140
|
```
|
|
135
141
|
|
|
136
142
|
Run as web catalog only when browser validation is required:
|
|
137
143
|
|
|
138
144
|
```cmd
|
|
139
145
|
call C:\Python\venv\.venv_313_FW\Scripts\activate.bat
|
|
140
|
-
flet run --web --port 8550 catalog/
|
|
146
|
+
flet run --web --port 8550 catalog/catalog.py
|
|
141
147
|
```
|
|
142
148
|
|
|
143
149
|
Run a use case:
|
|
@@ -196,12 +202,12 @@ The script builds the package, checks the artifacts, and uploads to TestPyPI or
|
|
|
196
202
|
With the documented Flet environment:
|
|
197
203
|
|
|
198
204
|
```cmd
|
|
199
|
-
C:\Python\venv\.venv_313_FW\Scripts\python.exe -c "import catalog.
|
|
205
|
+
C:\Python\venv\.venv_313_FW\Scripts\python.exe -c "import catalog.constants as c; print(c.PROJECT_VERSION)"
|
|
200
206
|
```
|
|
201
207
|
|
|
202
208
|
## Catalog
|
|
203
209
|
|
|
204
|
-
The catalog entry point is `catalog/
|
|
210
|
+
The catalog entry point is `catalog/catalog.py`.
|
|
205
211
|
|
|
206
212
|
It follows the project window structure:
|
|
207
213
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import flet as ft
|
|
2
2
|
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
3
|
|
|
4
|
-
COMPONENT_VERSION = "0.0
|
|
4
|
+
COMPONENT_VERSION = "0.1.0"
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def _state_placeholder(state: str, empty_message: str, error_message: str) -> ft.Control:
|
|
@@ -44,10 +44,26 @@ def DEx_DataTable(
|
|
|
44
44
|
state: str | None = None,
|
|
45
45
|
empty_message: str = "Nenhum registro encontrado.",
|
|
46
46
|
error_message: str = "Erro ao carregar os dados.",
|
|
47
|
+
row_payloads: list | None = None,
|
|
47
48
|
) -> ft.Control:
|
|
48
|
-
"""Create the versioned data table with DEx headers, borders, and rows.
|
|
49
|
+
"""Create the versioned data table with DEx headers, borders, and rows.
|
|
50
|
+
|
|
51
|
+
row_payloads (BL13 do AutoFlow): um payload por linha; quando presente,
|
|
52
|
+
on_row_click recebe (evento, payload) — os produtos deixavam de religar
|
|
53
|
+
o clique linha a linha sobre o ft.DataTable retornado. Sem payloads, o
|
|
54
|
+
comportamento antigo (on_row_click(evento)) e preservado.
|
|
55
|
+
"""
|
|
49
56
|
if state in ("loading", "empty", "error"):
|
|
50
57
|
return _state_placeholder(state, empty_message, error_message)
|
|
58
|
+
|
|
59
|
+
def _handler(indice: int):
|
|
60
|
+
if on_row_click is None:
|
|
61
|
+
return None
|
|
62
|
+
if row_payloads is None:
|
|
63
|
+
return on_row_click
|
|
64
|
+
payload = row_payloads[indice] if indice < len(row_payloads) else None
|
|
65
|
+
return lambda e, p=payload: on_row_click(e, p)
|
|
66
|
+
|
|
51
67
|
return ft.DataTable(
|
|
52
68
|
columns=[
|
|
53
69
|
ft.DataColumn(
|
|
@@ -67,9 +83,9 @@ def DEx_DataTable(
|
|
|
67
83
|
ft.DataCell(ft.Text(cell, size=13, color=Colors.TEXT_PRIMARY))
|
|
68
84
|
for cell in row
|
|
69
85
|
],
|
|
70
|
-
on_select_change=
|
|
86
|
+
on_select_change=_handler(i),
|
|
71
87
|
)
|
|
72
|
-
for row in rows
|
|
88
|
+
for i, row in enumerate(rows)
|
|
73
89
|
],
|
|
74
90
|
border=ft.Border.all(1, Colors.BORDER),
|
|
75
91
|
border_radius=Spacing.CARD_BORDER_RADIUS,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import flet as ft
|
|
2
2
|
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
3
|
|
|
4
|
-
COMPONENT_VERSION = "0.0
|
|
4
|
+
COMPONENT_VERSION = "0.1.0"
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def DEx_AlertDialog(
|
|
@@ -9,8 +9,13 @@ def DEx_AlertDialog(
|
|
|
9
9
|
content: ft.Control | str | None = None,
|
|
10
10
|
actions: list[ft.Control] | None = None,
|
|
11
11
|
on_dismiss=None,
|
|
12
|
+
modal: bool = False,
|
|
12
13
|
) -> ft.AlertDialog:
|
|
13
|
-
"""Modal dialog for confirmations, alerts and short forms.
|
|
14
|
+
"""Modal dialog for confirmations, alerts and short forms.
|
|
15
|
+
|
|
16
|
+
modal (BL13 do AutoFlow): bloqueia o fechamento por clique fora — os
|
|
17
|
+
produtos ajustavam o atributo publico pos-construcao.
|
|
18
|
+
"""
|
|
14
19
|
body = (
|
|
15
20
|
ft.Text(content, size=13, color=Colors.TEXT_SECONDARY)
|
|
16
21
|
if isinstance(content, str)
|
|
@@ -21,6 +26,7 @@ def DEx_AlertDialog(
|
|
|
21
26
|
content=body,
|
|
22
27
|
actions=actions or [],
|
|
23
28
|
on_dismiss=on_dismiss,
|
|
29
|
+
modal=modal,
|
|
24
30
|
bgcolor=Colors.BG_ELEVATED,
|
|
25
31
|
shape=ft.RoundedRectangleBorder(radius=Spacing.CARD_BORDER_RADIUS),
|
|
26
32
|
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import flet as ft
|
|
2
|
+
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
|
+
|
|
4
|
+
COMPONENT_VERSION = "0.1.0"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _option(item) -> ft.dropdown.Option:
|
|
8
|
+
"""Aceita opcao como str (key=text) ou par (key, text) — BL13."""
|
|
9
|
+
if isinstance(item, (tuple, list)) and len(item) == 2:
|
|
10
|
+
key, text = item
|
|
11
|
+
return ft.dropdown.Option(key=str(key), text=str(text))
|
|
12
|
+
return ft.dropdown.Option(str(item))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def DEx_Dropdown(
|
|
16
|
+
label: str,
|
|
17
|
+
options: list,
|
|
18
|
+
on_change=None,
|
|
19
|
+
value: str | None = None,
|
|
20
|
+
width: int | None = None,
|
|
21
|
+
) -> ft.Dropdown:
|
|
22
|
+
"""Create the versioned styled dropdown selector.
|
|
23
|
+
|
|
24
|
+
options aceita list[str] (compat) ou list[(key, text)]; value/width
|
|
25
|
+
(BL13 do AutoFlow) evitam o ajuste pos-construcao nos produtos.
|
|
26
|
+
"""
|
|
27
|
+
dd = ft.Dropdown(
|
|
28
|
+
label=label,
|
|
29
|
+
options=[_option(o) for o in options],
|
|
30
|
+
value=value,
|
|
31
|
+
width=width,
|
|
32
|
+
border_color=Colors.BORDER,
|
|
33
|
+
focused_border_color=Colors.ACCENT,
|
|
34
|
+
label_style=ft.TextStyle(color=Colors.TEXT_SECONDARY, size=12),
|
|
35
|
+
text_style=ft.TextStyle(color=Colors.TEXT_PRIMARY, size=14),
|
|
36
|
+
bgcolor=Colors.BG_SURFACE,
|
|
37
|
+
border_radius=Spacing.BUTTON_BORDER_RADIUS,
|
|
38
|
+
)
|
|
39
|
+
if on_change is not None:
|
|
40
|
+
dd.on_change = on_change
|
|
41
|
+
return dd
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import flet as ft
|
|
2
2
|
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
3
|
|
|
4
|
-
COMPONENT_VERSION = "0.0
|
|
4
|
+
COMPONENT_VERSION = "0.1.0"
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def DEx_TextField(
|
|
@@ -10,8 +10,18 @@ def DEx_TextField(
|
|
|
10
10
|
icon=None,
|
|
11
11
|
password: bool = False,
|
|
12
12
|
on_change=None,
|
|
13
|
+
value: str = "",
|
|
14
|
+
width: int | None = None,
|
|
15
|
+
visible: bool = True,
|
|
16
|
+
multiline: bool = False,
|
|
17
|
+
min_lines: int | None = None,
|
|
18
|
+
max_lines: int | None = None,
|
|
13
19
|
) -> ft.TextField:
|
|
14
|
-
"""Create the versioned DEx text field for forms and filters.
|
|
20
|
+
"""Create the versioned DEx text field for forms and filters.
|
|
21
|
+
|
|
22
|
+
value/width/visible/multiline (BL13 do AutoFlow): os produtos ajustavam
|
|
23
|
+
esses atributos publicos pos-construcao; agora a fabrica os expoe.
|
|
24
|
+
"""
|
|
15
25
|
return ft.TextField(
|
|
16
26
|
label=label,
|
|
17
27
|
hint_text=hint,
|
|
@@ -19,6 +29,12 @@ def DEx_TextField(
|
|
|
19
29
|
password=password,
|
|
20
30
|
can_reveal_password=password,
|
|
21
31
|
on_change=on_change,
|
|
32
|
+
value=value,
|
|
33
|
+
width=width,
|
|
34
|
+
visible=visible,
|
|
35
|
+
multiline=multiline,
|
|
36
|
+
min_lines=min_lines,
|
|
37
|
+
max_lines=max_lines,
|
|
22
38
|
border_color=Colors.BORDER,
|
|
23
39
|
focused_border_color=Colors.ACCENT,
|
|
24
40
|
label_style=ft.TextStyle(color=Colors.TEXT_SECONDARY, size=12),
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import flet as ft
|
|
2
|
+
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
|
+
from components.layout.DEx_Sidebar import DEx_Sidebar
|
|
4
|
+
from components.layout.DEx_Header import DEx_Header
|
|
5
|
+
|
|
6
|
+
COMPONENT_VERSION = "0.1.0"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DEx_AppShell(ft.Row):
|
|
10
|
+
"""Versioned application shell with sidebar, header, and content host.
|
|
11
|
+
|
|
12
|
+
BL12 (demanda AutoFlow): o shell repassa a identidade e a navegacao do
|
|
13
|
+
produto para o DEx_Sidebar (nav_items, logo, secao, settings, usuario,
|
|
14
|
+
on_logout) e as opcoes do DEx_Header (busca/sino/ajuda). Defaults
|
|
15
|
+
reproduzem a vitrine do catalogo — retrocompativel.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
page: ft.Page,
|
|
21
|
+
title: str = "",
|
|
22
|
+
subtitle: str = "",
|
|
23
|
+
header_actions: list[ft.Control] | None = None,
|
|
24
|
+
nav_items: list[tuple] | None = None,
|
|
25
|
+
initial_route: str = "/dashboard",
|
|
26
|
+
logo_letter: str = "D",
|
|
27
|
+
logo_title: str = "DEx",
|
|
28
|
+
logo_subtitle: str = "Framework v4",
|
|
29
|
+
section_label: str = "NAVEGACAO",
|
|
30
|
+
settings_route: str | None = "/settings",
|
|
31
|
+
user_name: str | None = "Almir Duarte",
|
|
32
|
+
user_role: str | None = "Admin",
|
|
33
|
+
on_logout=None,
|
|
34
|
+
on_navigate=None,
|
|
35
|
+
show_search: bool = True,
|
|
36
|
+
on_search=None,
|
|
37
|
+
show_notifications: bool = True,
|
|
38
|
+
show_help: bool = True,
|
|
39
|
+
):
|
|
40
|
+
self._page_ref = page
|
|
41
|
+
self.title = title
|
|
42
|
+
self.subtitle = subtitle
|
|
43
|
+
self.header_actions = header_actions or []
|
|
44
|
+
self.nav_items = nav_items
|
|
45
|
+
self.logo_letter = logo_letter
|
|
46
|
+
self.logo_title = logo_title
|
|
47
|
+
self.logo_subtitle = logo_subtitle
|
|
48
|
+
self.section_label = section_label
|
|
49
|
+
self.settings_route = settings_route
|
|
50
|
+
self.user_name = user_name
|
|
51
|
+
self.user_role = user_role
|
|
52
|
+
self.on_logout = on_logout
|
|
53
|
+
self.on_navigate_produto = on_navigate
|
|
54
|
+
self.show_search = show_search
|
|
55
|
+
self.on_search = on_search
|
|
56
|
+
self.show_notifications = show_notifications
|
|
57
|
+
self.show_help = show_help
|
|
58
|
+
self._content = ft.Container(expand=True)
|
|
59
|
+
self._route = initial_route
|
|
60
|
+
|
|
61
|
+
page.bgcolor = Colors.BG_DEEP
|
|
62
|
+
page.padding = 0
|
|
63
|
+
page.spacing = 0
|
|
64
|
+
|
|
65
|
+
super().__init__(
|
|
66
|
+
controls=self._build_controls(),
|
|
67
|
+
spacing=0,
|
|
68
|
+
expand=True,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
def set_content(self, control: ft.Control, title: str = None, subtitle: str = None):
|
|
72
|
+
if title:
|
|
73
|
+
self.title = title
|
|
74
|
+
if subtitle:
|
|
75
|
+
self.subtitle = subtitle
|
|
76
|
+
self._content = ft.Container(
|
|
77
|
+
content=ft.Column(
|
|
78
|
+
[ft.Container(content=control, padding=ft.Padding.all(Spacing.LG))],
|
|
79
|
+
spacing=0,
|
|
80
|
+
expand=True,
|
|
81
|
+
horizontal_alignment=ft.CrossAxisAlignment.START,
|
|
82
|
+
),
|
|
83
|
+
expand=True,
|
|
84
|
+
bgcolor=Colors.BG_DEEP,
|
|
85
|
+
)
|
|
86
|
+
self.controls = self._build_controls()
|
|
87
|
+
try:
|
|
88
|
+
self.update()
|
|
89
|
+
except RuntimeError:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
def _on_navigate(self, route: str):
|
|
93
|
+
self._route = route
|
|
94
|
+
if self.on_navigate_produto:
|
|
95
|
+
self.on_navigate_produto(route)
|
|
96
|
+
self.controls = self._build_controls()
|
|
97
|
+
self.update()
|
|
98
|
+
|
|
99
|
+
def _build_controls(self) -> list[ft.Control]:
|
|
100
|
+
sidebar = DEx_Sidebar(
|
|
101
|
+
current_route=self._route,
|
|
102
|
+
on_navigate=self._on_navigate,
|
|
103
|
+
nav_items=self.nav_items,
|
|
104
|
+
logo_letter=self.logo_letter,
|
|
105
|
+
logo_title=self.logo_title,
|
|
106
|
+
logo_subtitle=self.logo_subtitle,
|
|
107
|
+
section_label=self.section_label,
|
|
108
|
+
settings_route=self.settings_route,
|
|
109
|
+
user_name=self.user_name,
|
|
110
|
+
user_role=self.user_role,
|
|
111
|
+
on_logout=self.on_logout,
|
|
112
|
+
)
|
|
113
|
+
header = DEx_Header(
|
|
114
|
+
self.title,
|
|
115
|
+
self.subtitle,
|
|
116
|
+
actions=self.header_actions,
|
|
117
|
+
show_search=self.show_search,
|
|
118
|
+
on_search=self.on_search,
|
|
119
|
+
show_notifications=self.show_notifications,
|
|
120
|
+
show_help=self.show_help,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
main_area = ft.Column(
|
|
124
|
+
[
|
|
125
|
+
ft.Row([header], spacing=0, expand=True),
|
|
126
|
+
ft.Container(
|
|
127
|
+
content=self._content,
|
|
128
|
+
expand=True,
|
|
129
|
+
clip_behavior=ft.ClipBehavior.HARD_EDGE,
|
|
130
|
+
),
|
|
131
|
+
],
|
|
132
|
+
spacing=0,
|
|
133
|
+
expand=True,
|
|
134
|
+
alignment=ft.MainAxisAlignment.START,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return [sidebar, main_area]
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import flet as ft
|
|
2
|
+
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
|
+
|
|
4
|
+
COMPONENT_VERSION = "0.1.0"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DEx_Header(ft.Container):
|
|
8
|
+
"""Versioned page header with title, subtitle, search, and actions.
|
|
9
|
+
|
|
10
|
+
BL12 (demanda AutoFlow): busca, sino e ajuda agora sao opcionais e a
|
|
11
|
+
busca aceita on_search (on_change) — defaults reproduzem a vitrine.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
title: str,
|
|
17
|
+
subtitle: str = "",
|
|
18
|
+
actions: list[ft.Control] | None = None,
|
|
19
|
+
show_search: bool = True,
|
|
20
|
+
on_search=None,
|
|
21
|
+
show_notifications: bool = True,
|
|
22
|
+
show_help: bool = True,
|
|
23
|
+
):
|
|
24
|
+
self.title = title
|
|
25
|
+
self.subtitle = subtitle
|
|
26
|
+
self.actions = actions or []
|
|
27
|
+
self.show_search = show_search
|
|
28
|
+
self.on_search = on_search
|
|
29
|
+
self.show_notifications = show_notifications
|
|
30
|
+
self.show_help = show_help
|
|
31
|
+
super().__init__(
|
|
32
|
+
content=self._build_content(),
|
|
33
|
+
height=Spacing.HEADER_HEIGHT,
|
|
34
|
+
bgcolor=Colors.BG_DEEP,
|
|
35
|
+
border=ft.Border.only(bottom=ft.BorderSide(1, Colors.BORDER)),
|
|
36
|
+
padding=ft.Padding.symmetric(horizontal=Spacing.LG),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def _build_content(self) -> ft.Row:
|
|
40
|
+
title_block = ft.Column(
|
|
41
|
+
[
|
|
42
|
+
ft.Text(self.title, size=20, weight=ft.FontWeight.W_700, color=Colors.TEXT_PRIMARY),
|
|
43
|
+
ft.Text(self.subtitle, size=12, color=Colors.TEXT_SECONDARY) if self.subtitle else ft.Container(),
|
|
44
|
+
],
|
|
45
|
+
spacing=2, tight=True,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
partes: list[ft.Control] = [title_block, ft.Container(expand=True)]
|
|
49
|
+
|
|
50
|
+
if self.show_search:
|
|
51
|
+
partes.append(
|
|
52
|
+
ft.TextField(
|
|
53
|
+
hint_text="Buscar...",
|
|
54
|
+
prefix_icon=ft.Icons.SEARCH,
|
|
55
|
+
on_change=self.on_search,
|
|
56
|
+
border_color=Colors.BORDER,
|
|
57
|
+
focused_border_color=Colors.ACCENT,
|
|
58
|
+
text_style=ft.TextStyle(color=Colors.TEXT_PRIMARY, size=13),
|
|
59
|
+
hint_style=ft.TextStyle(color=Colors.TEXT_MUTED, size=13),
|
|
60
|
+
bgcolor=Colors.BG_ELEVATED,
|
|
61
|
+
border_radius=8,
|
|
62
|
+
height=40,
|
|
63
|
+
content_padding=ft.Padding.symmetric(horizontal=12, vertical=8),
|
|
64
|
+
width=280,
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
icones: list[ft.Control] = []
|
|
69
|
+
if self.show_notifications:
|
|
70
|
+
icones.append(
|
|
71
|
+
ft.IconButton(ft.Icons.NOTIFICATIONS_NONE_ROUNDED, icon_color=Colors.TEXT_SECONDARY, icon_size=20)
|
|
72
|
+
)
|
|
73
|
+
icones.extend(self.actions)
|
|
74
|
+
if self.show_help:
|
|
75
|
+
icones.append(
|
|
76
|
+
ft.IconButton(ft.Icons.HELP_OUTLINE_ROUNDED, icon_color=Colors.TEXT_SECONDARY, icon_size=20)
|
|
77
|
+
)
|
|
78
|
+
partes.append(ft.Row(icones, spacing=0))
|
|
79
|
+
|
|
80
|
+
return ft.Row(partes, vertical_alignment=ft.CrossAxisAlignment.CENTER)
|