SaaS-FrameWork 0.1.1__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.
- components/__init__.py +119 -0
- components/buttons/DEx_BtnFAB.py +37 -0
- components/buttons/DEx_BtnFilled.py +20 -0
- components/buttons/DEx_BtnGhost.py +20 -0
- components/buttons/DEx_BtnIcon.py +18 -0
- components/buttons/DEx_BtnPrimary.py +21 -0
- components/buttons/DEx_BtnSegmented.py +45 -0
- components/buttons/DEx_BtnText.py +19 -0
- components/buttons/DEx_BtnTonal.py +20 -0
- components/buttons/DEx_MenuBar.py +61 -0
- components/buttons/DEx_PopupMenu.py +43 -0
- components/buttons/__init__.py +0 -0
- components/cards/DEx_Card.py +23 -0
- components/cards/DEx_ContactCard.py +52 -0
- components/cards/DEx_MetricCard.py +36 -0
- components/cards/__init__.py +0 -0
- components/data/DEx_DataTable.py +82 -0
- components/data/DEx_ExpansionPanel.py +39 -0
- components/data/DEx_ExpansionTile.py +29 -0
- components/data/DEx_GridView.py +65 -0
- components/data/DEx_ListTile.py +27 -0
- components/data/DEx_ListView.py +65 -0
- components/data/DEx_PipelineColumn.py +74 -0
- components/data/DEx_TreeView.py +536 -0
- components/data/__init__.py +0 -0
- components/feedback/DEx_AlertDialog.py +26 -0
- components/feedback/DEx_Banner.py +19 -0
- components/feedback/DEx_BottomSheet.py +37 -0
- components/feedback/DEx_Notify.py +15 -0
- components/feedback/DEx_ProgressBar.py +34 -0
- components/feedback/DEx_ProgressRing.py +52 -0
- components/feedback/DEx_Shimmer.py +84 -0
- components/feedback/DEx_Tooltip.py +24 -0
- components/feedback/__init__.py +0 -0
- components/inputs/DEx_AutoComplete.py +29 -0
- components/inputs/DEx_Checkbox.py +27 -0
- components/inputs/DEx_Chip.py +33 -0
- components/inputs/DEx_DatePicker.py +72 -0
- components/inputs/DEx_Dropdown.py +25 -0
- components/inputs/DEx_FilePicker.py +70 -0
- components/inputs/DEx_Radio.py +37 -0
- components/inputs/DEx_SearchBar.py +37 -0
- components/inputs/DEx_SearchField.py +9 -0
- components/inputs/DEx_Slider.py +49 -0
- components/inputs/DEx_Switch.py +22 -0
- components/inputs/DEx_TextField.py +29 -0
- components/inputs/DEx_TimePicker.py +71 -0
- components/inputs/__init__.py +0 -0
- components/layout/DEx_AnimatedSwitcher.py +43 -0
- components/layout/DEx_AppBar.py +48 -0
- components/layout/DEx_AppShell.py +80 -0
- components/layout/DEx_Draggable.py +67 -0
- components/layout/DEx_GestureDetector.py +52 -0
- components/layout/DEx_Header.py +57 -0
- components/layout/DEx_NavItem.py +61 -0
- components/layout/DEx_NavigationBar.py +30 -0
- components/layout/DEx_NavigationDrawer.py +60 -0
- components/layout/DEx_NavigationRail.py +42 -0
- components/layout/DEx_ResponsiveRow.py +42 -0
- components/layout/DEx_Sidebar.py +131 -0
- components/layout/DEx_Stack.py +73 -0
- components/layout/DEx_Tabs.py +110 -0
- components/layout/__init__.py +0 -0
- components/metadata.py +98 -0
- components/primitives/DEx_Avatar.py +87 -0
- components/primitives/DEx_Badge.py +18 -0
- components/primitives/DEx_Divider.py +13 -0
- components/primitives/DEx_Icon.py +46 -0
- components/primitives/DEx_Image.py +55 -0
- components/primitives/DEx_Markdown.py +21 -0
- components/primitives/DEx_SectionEyebrow.py +22 -0
- components/primitives/DEx_StatusDot.py +8 -0
- components/primitives/__init__.py +0 -0
- components/project.py +23 -0
- components/theme/DEx_ColorThemes.py +375 -0
- components/theme/DEx_Theme.py +136 -0
- components/theme/__init__.py +4 -0
- components/versioning.py +103 -0
- saas_framework-0.1.1.dist-info/METADATA +450 -0
- saas_framework-0.1.1.dist-info/RECORD +82 -0
- saas_framework-0.1.1.dist-info/WHEEL +5 -0
- saas_framework-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import flet as ft
|
|
2
|
+
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
|
+
|
|
4
|
+
COMPONENT_VERSION = "0.0.1"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def DEx_ExpansionTile(
|
|
8
|
+
title: str,
|
|
9
|
+
controls: list[ft.Control],
|
|
10
|
+
subtitle: str = "",
|
|
11
|
+
leading: ft.Control | None = None,
|
|
12
|
+
initially_expanded: bool = False,
|
|
13
|
+
on_change=None,
|
|
14
|
+
) -> ft.ExpansionTile:
|
|
15
|
+
"""Expandable list tile that reveals nested content."""
|
|
16
|
+
return ft.ExpansionTile(
|
|
17
|
+
title=ft.Text(title, size=14, color=Colors.TEXT_PRIMARY),
|
|
18
|
+
subtitle=ft.Text(subtitle, size=11, color=Colors.TEXT_SECONDARY) if subtitle else None,
|
|
19
|
+
leading=leading,
|
|
20
|
+
controls=controls,
|
|
21
|
+
expanded=initially_expanded,
|
|
22
|
+
on_change=on_change,
|
|
23
|
+
text_color=Colors.TEXT_PRIMARY,
|
|
24
|
+
icon_color=Colors.TEXT_SECONDARY,
|
|
25
|
+
collapsed_text_color=Colors.TEXT_SECONDARY,
|
|
26
|
+
collapsed_icon_color=Colors.TEXT_MUTED,
|
|
27
|
+
bgcolor=ft.Colors.TRANSPARENT,
|
|
28
|
+
collapsed_bgcolor=ft.Colors.TRANSPARENT,
|
|
29
|
+
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import flet as ft
|
|
2
|
+
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
|
+
|
|
4
|
+
COMPONENT_VERSION = "0.0.1"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _state_placeholder(state: str, empty_message: str, error_message: str) -> ft.Control:
|
|
8
|
+
if state == "loading":
|
|
9
|
+
return ft.Container(
|
|
10
|
+
content=ft.Column(
|
|
11
|
+
[ft.ProgressRing(width=32, height=32, stroke_width=3, color=Colors.ACCENT)],
|
|
12
|
+
alignment=ft.MainAxisAlignment.CENTER,
|
|
13
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
14
|
+
),
|
|
15
|
+
padding=Spacing.XL,
|
|
16
|
+
)
|
|
17
|
+
if state == "empty":
|
|
18
|
+
return ft.Container(
|
|
19
|
+
content=ft.Column(
|
|
20
|
+
[ft.Icon(ft.Icons.INBOX_ROUNDED, size=40, color=Colors.TEXT_MUTED),
|
|
21
|
+
ft.Text(empty_message, size=13, color=Colors.TEXT_MUTED)],
|
|
22
|
+
alignment=ft.MainAxisAlignment.CENTER,
|
|
23
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
24
|
+
spacing=Spacing.SM,
|
|
25
|
+
),
|
|
26
|
+
padding=Spacing.XL,
|
|
27
|
+
)
|
|
28
|
+
return ft.Container(
|
|
29
|
+
content=ft.Column(
|
|
30
|
+
[ft.Icon(ft.Icons.ERROR_ROUNDED, size=40, color=Colors.DANGER),
|
|
31
|
+
ft.Text(error_message, size=13, color=Colors.DANGER)],
|
|
32
|
+
alignment=ft.MainAxisAlignment.CENTER,
|
|
33
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
34
|
+
spacing=Spacing.SM,
|
|
35
|
+
),
|
|
36
|
+
padding=Spacing.XL,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def DEx_GridView(
|
|
41
|
+
controls: list[ft.Control],
|
|
42
|
+
runs_count: int = 3,
|
|
43
|
+
max_extent: int | None = None,
|
|
44
|
+
spacing: int | None = None,
|
|
45
|
+
run_spacing: int | None = None,
|
|
46
|
+
height: int | None = None,
|
|
47
|
+
padding: int | None = None,
|
|
48
|
+
state: str | None = None,
|
|
49
|
+
empty_message: str = "Nenhum item encontrado.",
|
|
50
|
+
error_message: str = "Erro ao carregar os itens.",
|
|
51
|
+
) -> ft.Control:
|
|
52
|
+
"""Responsive grid for cards, images and repeated items."""
|
|
53
|
+
if state in ("loading", "empty", "error"):
|
|
54
|
+
return _state_placeholder(state, empty_message, error_message)
|
|
55
|
+
|
|
56
|
+
_spacing = spacing if spacing is not None else Spacing.MD
|
|
57
|
+
return ft.GridView(
|
|
58
|
+
controls=controls,
|
|
59
|
+
runs_count=runs_count if max_extent is None else None,
|
|
60
|
+
max_extent=max_extent,
|
|
61
|
+
spacing=_spacing,
|
|
62
|
+
run_spacing=run_spacing if run_spacing is not None else _spacing,
|
|
63
|
+
height=height,
|
|
64
|
+
padding=padding or Spacing.XS,
|
|
65
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import flet as ft
|
|
2
|
+
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
|
+
|
|
4
|
+
COMPONENT_VERSION = "0.0.1"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def DEx_ListTile(
|
|
8
|
+
title: str,
|
|
9
|
+
subtitle: str = "",
|
|
10
|
+
leading: ft.Control | None = None,
|
|
11
|
+
trailing: ft.Control | None = None,
|
|
12
|
+
on_click=None,
|
|
13
|
+
selected: bool = False,
|
|
14
|
+
dense: bool = False,
|
|
15
|
+
) -> ft.ListTile:
|
|
16
|
+
"""Styled list tile for use in lists, drawers and menus."""
|
|
17
|
+
return ft.ListTile(
|
|
18
|
+
title=ft.Text(title, size=13 if dense else 14, color=Colors.TEXT_PRIMARY),
|
|
19
|
+
subtitle=ft.Text(subtitle, size=11, color=Colors.TEXT_SECONDARY) if subtitle else None,
|
|
20
|
+
leading=leading,
|
|
21
|
+
trailing=trailing,
|
|
22
|
+
on_click=on_click,
|
|
23
|
+
selected=selected,
|
|
24
|
+
selected_color=Colors.ACCENT,
|
|
25
|
+
bgcolor=ft.Colors.TRANSPARENT,
|
|
26
|
+
dense=dense,
|
|
27
|
+
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import flet as ft
|
|
2
|
+
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
|
+
|
|
4
|
+
COMPONENT_VERSION = "0.0.1"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _state_placeholder(state: str, empty_message: str, error_message: str) -> ft.Control:
|
|
8
|
+
if state == "loading":
|
|
9
|
+
return ft.Container(
|
|
10
|
+
content=ft.Column(
|
|
11
|
+
[ft.ProgressRing(width=32, height=32, stroke_width=3, color=Colors.ACCENT)],
|
|
12
|
+
alignment=ft.MainAxisAlignment.CENTER,
|
|
13
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
14
|
+
),
|
|
15
|
+
padding=Spacing.XL,
|
|
16
|
+
)
|
|
17
|
+
if state == "empty":
|
|
18
|
+
return ft.Container(
|
|
19
|
+
content=ft.Column(
|
|
20
|
+
[ft.Icon(ft.Icons.INBOX_ROUNDED, size=40, color=Colors.TEXT_MUTED),
|
|
21
|
+
ft.Text(empty_message, size=13, color=Colors.TEXT_MUTED)],
|
|
22
|
+
alignment=ft.MainAxisAlignment.CENTER,
|
|
23
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
24
|
+
spacing=Spacing.SM,
|
|
25
|
+
),
|
|
26
|
+
padding=Spacing.XL,
|
|
27
|
+
)
|
|
28
|
+
return ft.Container(
|
|
29
|
+
content=ft.Column(
|
|
30
|
+
[ft.Icon(ft.Icons.ERROR_ROUNDED, size=40, color=Colors.DANGER),
|
|
31
|
+
ft.Text(error_message, size=13, color=Colors.DANGER)],
|
|
32
|
+
alignment=ft.MainAxisAlignment.CENTER,
|
|
33
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
34
|
+
spacing=Spacing.SM,
|
|
35
|
+
),
|
|
36
|
+
padding=Spacing.XL,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def DEx_ListView(
|
|
41
|
+
controls: list[ft.Control],
|
|
42
|
+
divider: bool = True,
|
|
43
|
+
spacing: int = 0,
|
|
44
|
+
padding: int | None = None,
|
|
45
|
+
height: int | None = None,
|
|
46
|
+
state: str | None = None,
|
|
47
|
+
empty_message: str = "Nenhum item encontrado.",
|
|
48
|
+
error_message: str = "Erro ao carregar os itens.",
|
|
49
|
+
) -> ft.Control:
|
|
50
|
+
"""Scrollable vertical list with optional dividers between items."""
|
|
51
|
+
if state in ("loading", "empty", "error"):
|
|
52
|
+
return _state_placeholder(state, empty_message, error_message)
|
|
53
|
+
|
|
54
|
+
items: list[ft.Control] = []
|
|
55
|
+
for i, ctrl in enumerate(controls):
|
|
56
|
+
items.append(ctrl)
|
|
57
|
+
if divider and i < len(controls) - 1:
|
|
58
|
+
items.append(ft.Divider(height=1, color=Colors.BORDER))
|
|
59
|
+
|
|
60
|
+
return ft.ListView(
|
|
61
|
+
controls=items,
|
|
62
|
+
spacing=spacing,
|
|
63
|
+
padding=padding or Spacing.XS,
|
|
64
|
+
height=height,
|
|
65
|
+
)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import flet as ft
|
|
2
|
+
from components.theme.DEx_Theme import Colors, Spacing
|
|
3
|
+
from components.primitives.DEx_SectionEyebrow import DEx_SectionEyebrow
|
|
4
|
+
from components.primitives.DEx_Divider import DEx_Divider
|
|
5
|
+
|
|
6
|
+
COMPONENT_VERSION = "0.0.1"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _state_placeholder(state: str, empty_message: str, error_message: str) -> ft.Control:
|
|
10
|
+
if state == "loading":
|
|
11
|
+
return ft.Container(
|
|
12
|
+
content=ft.Column(
|
|
13
|
+
[ft.ProgressRing(width=28, height=28, stroke_width=3, color=Colors.ACCENT)],
|
|
14
|
+
alignment=ft.MainAxisAlignment.CENTER,
|
|
15
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
16
|
+
),
|
|
17
|
+
padding=Spacing.XL,
|
|
18
|
+
)
|
|
19
|
+
if state == "empty":
|
|
20
|
+
return ft.Container(
|
|
21
|
+
content=ft.Column(
|
|
22
|
+
[ft.Icon(ft.Icons.INBOX_ROUNDED, size=36, color=Colors.TEXT_MUTED),
|
|
23
|
+
ft.Text(empty_message, size=12, color=Colors.TEXT_MUTED, text_align=ft.TextAlign.CENTER)],
|
|
24
|
+
alignment=ft.MainAxisAlignment.CENTER,
|
|
25
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
26
|
+
spacing=Spacing.SM,
|
|
27
|
+
),
|
|
28
|
+
padding=Spacing.LG,
|
|
29
|
+
)
|
|
30
|
+
return ft.Container(
|
|
31
|
+
content=ft.Column(
|
|
32
|
+
[ft.Icon(ft.Icons.ERROR_ROUNDED, size=36, color=Colors.DANGER),
|
|
33
|
+
ft.Text(error_message, size=12, color=Colors.DANGER, text_align=ft.TextAlign.CENTER)],
|
|
34
|
+
alignment=ft.MainAxisAlignment.CENTER,
|
|
35
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
36
|
+
spacing=Spacing.SM,
|
|
37
|
+
),
|
|
38
|
+
padding=Spacing.LG,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def DEx_PipelineColumn(
|
|
43
|
+
stage_number: str,
|
|
44
|
+
stage_name: str,
|
|
45
|
+
count: int,
|
|
46
|
+
total_value: str,
|
|
47
|
+
cards: list[ft.Control],
|
|
48
|
+
state: str | None = None,
|
|
49
|
+
empty_message: str = "Nenhum card nesta etapa.",
|
|
50
|
+
error_message: str = "Erro ao carregar os cards.",
|
|
51
|
+
) -> ft.Container:
|
|
52
|
+
"""Create the versioned pipeline column for grouped workflow cards."""
|
|
53
|
+
body = (
|
|
54
|
+
_state_placeholder(state, empty_message, error_message)
|
|
55
|
+
if state in ("loading", "empty", "error")
|
|
56
|
+
else ft.Column([*cards], spacing=Spacing.SM, scroll=ft.ScrollMode.AUTO)
|
|
57
|
+
)
|
|
58
|
+
return ft.Container(
|
|
59
|
+
content=ft.Column([
|
|
60
|
+
DEx_SectionEyebrow(stage_number, stage_name),
|
|
61
|
+
ft.Row([
|
|
62
|
+
ft.Text(f"{count} itens", size=12, color=Colors.TEXT_SECONDARY),
|
|
63
|
+
ft.Text(total_value, size=12, weight=ft.FontWeight.W_700, color=Colors.DATA),
|
|
64
|
+
], alignment=ft.MainAxisAlignment.SPACE_BETWEEN),
|
|
65
|
+
DEx_Divider(),
|
|
66
|
+
body,
|
|
67
|
+
], spacing=Spacing.SM),
|
|
68
|
+
width=260,
|
|
69
|
+
bgcolor=Colors.BG_SURFACE,
|
|
70
|
+
border=ft.Border.all(1, Colors.BORDER),
|
|
71
|
+
border_radius=Spacing.CARD_BORDER_RADIUS,
|
|
72
|
+
padding=Spacing.MD,
|
|
73
|
+
expand=False,
|
|
74
|
+
)
|