fh-matui 0.9.7__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.
- fh_matui/__init__.py +1 -0
- fh_matui/_modidx.py +192 -0
- fh_matui/app_pages.py +291 -0
- fh_matui/components.py +1200 -0
- fh_matui/core.py +230 -0
- fh_matui/datatable.py +870 -0
- fh_matui/foundations.py +59 -0
- fh_matui/web_pages.py +919 -0
- fh_matui-0.9.7.dist-info/METADATA +243 -0
- fh_matui-0.9.7.dist-info/RECORD +14 -0
- fh_matui-0.9.7.dist-info/WHEEL +5 -0
- fh_matui-0.9.7.dist-info/entry_points.txt +2 -0
- fh_matui-0.9.7.dist-info/licenses/LICENSE +201 -0
- fh_matui-0.9.7.dist-info/top_level.txt +1 -0
fh_matui/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.9.6"
|
fh_matui/_modidx.py
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Autogenerated by nbdev
|
|
2
|
+
|
|
3
|
+
d = { 'settings': { 'branch': 'master',
|
|
4
|
+
'doc_baseurl': '/fh-matui',
|
|
5
|
+
'doc_host': 'https://abhisheksreesaila.github.io',
|
|
6
|
+
'git_url': 'https://github.com/abhisheksreesaila/fh-matui',
|
|
7
|
+
'lib_path': 'fh_matui'},
|
|
8
|
+
'syms': { 'fh_matui.app_pages': {'fh_matui.app_pages.LoginScreen': ('app_pages.html#loginscreen', 'fh_matui/app_pages.py')},
|
|
9
|
+
'fh_matui.components': { 'fh_matui.components.Abbr': ('components.html#abbr', 'fh_matui/components.py'),
|
|
10
|
+
'fh_matui.components.Blockquote': ('components.html#blockquote', 'fh_matui/components.py'),
|
|
11
|
+
'fh_matui.components.BottomNav': ('components.html#bottomnav', 'fh_matui/components.py'),
|
|
12
|
+
'fh_matui.components.Card': ('components.html#card', 'fh_matui/components.py'),
|
|
13
|
+
'fh_matui.components.CheckboxX': ('components.html#checkboxx', 'fh_matui/components.py'),
|
|
14
|
+
'fh_matui.components.CodeBlock': ('components.html#codeblock', 'fh_matui/components.py'),
|
|
15
|
+
'fh_matui.components.CodeSpan': ('components.html#codespan', 'fh_matui/components.py'),
|
|
16
|
+
'fh_matui.components.ContainerT': ('components.html#containert', 'fh_matui/components.py'),
|
|
17
|
+
'fh_matui.components.CookiesBanner': ('components.html#cookiesbanner', 'fh_matui/components.py'),
|
|
18
|
+
'fh_matui.components.DivCentered': ('components.html#divcentered', 'fh_matui/components.py'),
|
|
19
|
+
'fh_matui.components.DivFullySpaced': ('components.html#divfullyspaced', 'fh_matui/components.py'),
|
|
20
|
+
'fh_matui.components.DivHStacked': ('components.html#divhstacked', 'fh_matui/components.py'),
|
|
21
|
+
'fh_matui.components.DivLAligned': ('components.html#divlaligned', 'fh_matui/components.py'),
|
|
22
|
+
'fh_matui.components.DivRAligned': ('components.html#divraligned', 'fh_matui/components.py'),
|
|
23
|
+
'fh_matui.components.DivVStacked': ('components.html#divvstacked', 'fh_matui/components.py'),
|
|
24
|
+
'fh_matui.components.Em': ('components.html#em', 'fh_matui/components.py'),
|
|
25
|
+
'fh_matui.components.FAQItem': ('components.html#faqitem', 'fh_matui/components.py'),
|
|
26
|
+
'fh_matui.components.Field': ('components.html#field', 'fh_matui/components.py'),
|
|
27
|
+
'fh_matui.components.FormField': ('components.html#formfield', 'fh_matui/components.py'),
|
|
28
|
+
'fh_matui.components.FormGrid': ('components.html#formgrid', 'fh_matui/components.py'),
|
|
29
|
+
'fh_matui.components.FormLabel': ('components.html#formlabel', 'fh_matui/components.py'),
|
|
30
|
+
'fh_matui.components.FormModal': ('components.html#formmodal', 'fh_matui/components.py'),
|
|
31
|
+
'fh_matui.components.Grid': ('components.html#grid', 'fh_matui/components.py'),
|
|
32
|
+
'fh_matui.components.GridCell': ('components.html#gridcell', 'fh_matui/components.py'),
|
|
33
|
+
'fh_matui.components.GridSpanT': ('components.html#gridspant', 'fh_matui/components.py'),
|
|
34
|
+
'fh_matui.components.Icon': ('components.html#icon', 'fh_matui/components.py'),
|
|
35
|
+
'fh_matui.components.LabelInput': ('components.html#labelinput', 'fh_matui/components.py'),
|
|
36
|
+
'fh_matui.components.Layout': ('components.html#layout', 'fh_matui/components.py'),
|
|
37
|
+
'fh_matui.components.LoadingIndicator': ('components.html#loadingindicator', 'fh_matui/components.py'),
|
|
38
|
+
'fh_matui.components.Mark': ('components.html#mark', 'fh_matui/components.py'),
|
|
39
|
+
'fh_matui.components.Modal': ('components.html#modal', 'fh_matui/components.py'),
|
|
40
|
+
'fh_matui.components.ModalBody': ('components.html#modalbody', 'fh_matui/components.py'),
|
|
41
|
+
'fh_matui.components.ModalButton': ('components.html#modalbutton', 'fh_matui/components.py'),
|
|
42
|
+
'fh_matui.components.ModalCancel': ('components.html#modalcancel', 'fh_matui/components.py'),
|
|
43
|
+
'fh_matui.components.ModalConfirm': ('components.html#modalconfirm', 'fh_matui/components.py'),
|
|
44
|
+
'fh_matui.components.ModalFooter': ('components.html#modalfooter', 'fh_matui/components.py'),
|
|
45
|
+
'fh_matui.components.ModalTitle': ('components.html#modaltitle', 'fh_matui/components.py'),
|
|
46
|
+
'fh_matui.components.NavBar': ('components.html#navbar', 'fh_matui/components.py'),
|
|
47
|
+
'fh_matui.components.NavCloseLi': ('components.html#navcloseli', 'fh_matui/components.py'),
|
|
48
|
+
'fh_matui.components.NavContainer': ('components.html#navcontainer', 'fh_matui/components.py'),
|
|
49
|
+
'fh_matui.components.NavDividerLi': ('components.html#navdividerli', 'fh_matui/components.py'),
|
|
50
|
+
'fh_matui.components.NavHeaderLi': ('components.html#navheaderli', 'fh_matui/components.py'),
|
|
51
|
+
'fh_matui.components.NavSideBarContainer': ( 'components.html#navsidebarcontainer',
|
|
52
|
+
'fh_matui/components.py'),
|
|
53
|
+
'fh_matui.components.NavSideBarHeader': ('components.html#navsidebarheader', 'fh_matui/components.py'),
|
|
54
|
+
'fh_matui.components.NavSideBarLinks': ('components.html#navsidebarlinks', 'fh_matui/components.py'),
|
|
55
|
+
'fh_matui.components.NavSubtitle': ('components.html#navsubtitle', 'fh_matui/components.py'),
|
|
56
|
+
'fh_matui.components.NavToggleButton': ('components.html#navtogglebutton', 'fh_matui/components.py'),
|
|
57
|
+
'fh_matui.components.Pagination': ('components.html#pagination', 'fh_matui/components.py'),
|
|
58
|
+
'fh_matui.components.Progress': ('components.html#progress', 'fh_matui/components.py'),
|
|
59
|
+
'fh_matui.components.Q': ('components.html#q', 'fh_matui/components.py'),
|
|
60
|
+
'fh_matui.components.Radio': ('components.html#radio', 'fh_matui/components.py'),
|
|
61
|
+
'fh_matui.components.Range': ('components.html#range', 'fh_matui/components.py'),
|
|
62
|
+
'fh_matui.components.Select': ('components.html#select', 'fh_matui/components.py'),
|
|
63
|
+
'fh_matui.components.Small': ('components.html#small', 'fh_matui/components.py'),
|
|
64
|
+
'fh_matui.components.Snackbar': ('components.html#snackbar', 'fh_matui/components.py'),
|
|
65
|
+
'fh_matui.components.SpaceT': ('components.html#spacet', 'fh_matui/components.py'),
|
|
66
|
+
'fh_matui.components.Strong': ('components.html#strong', 'fh_matui/components.py'),
|
|
67
|
+
'fh_matui.components.Sub': ('components.html#sub', 'fh_matui/components.py'),
|
|
68
|
+
'fh_matui.components.Sup': ('components.html#sup', 'fh_matui/components.py'),
|
|
69
|
+
'fh_matui.components.Switch': ('components.html#switch', 'fh_matui/components.py'),
|
|
70
|
+
'fh_matui.components.Table': ('components.html#table', 'fh_matui/components.py'),
|
|
71
|
+
'fh_matui.components.TableControls': ('components.html#tablecontrols', 'fh_matui/components.py'),
|
|
72
|
+
'fh_matui.components.TableFromDicts': ('components.html#tablefromdicts', 'fh_matui/components.py'),
|
|
73
|
+
'fh_matui.components.TableFromLists': ('components.html#tablefromlists', 'fh_matui/components.py'),
|
|
74
|
+
'fh_matui.components.Tbody': ('components.html#tbody', 'fh_matui/components.py'),
|
|
75
|
+
'fh_matui.components.Td': ('components.html#td', 'fh_matui/components.py'),
|
|
76
|
+
'fh_matui.components.TextArea': ('components.html#textarea', 'fh_matui/components.py'),
|
|
77
|
+
'fh_matui.components.TextPresets': ('components.html#textpresets', 'fh_matui/components.py'),
|
|
78
|
+
'fh_matui.components.TextT': ('components.html#textt', 'fh_matui/components.py'),
|
|
79
|
+
'fh_matui.components.Tfoot': ('components.html#tfoot', 'fh_matui/components.py'),
|
|
80
|
+
'fh_matui.components.Th': ('components.html#th', 'fh_matui/components.py'),
|
|
81
|
+
'fh_matui.components.Thead': ('components.html#thead', 'fh_matui/components.py'),
|
|
82
|
+
'fh_matui.components.Toast': ('components.html#toast', 'fh_matui/components.py'),
|
|
83
|
+
'fh_matui.components.Toolbar': ('components.html#toolbar', 'fh_matui/components.py'),
|
|
84
|
+
'fh_matui.components._AnchorChain': ('components.html#_anchorchain', 'fh_matui/components.py'),
|
|
85
|
+
'fh_matui.components._ButtonChain': ('components.html#_buttonchain', 'fh_matui/components.py'),
|
|
86
|
+
'fh_matui.components._get_form_config': ('components.html#_get_form_config', 'fh_matui/components.py'),
|
|
87
|
+
'fh_matui.components._has_space_token': ('components.html#_has_space_token', 'fh_matui/components.py'),
|
|
88
|
+
'fh_matui.components._make_anchor_property': ( 'components.html#_make_anchor_property',
|
|
89
|
+
'fh_matui/components.py'),
|
|
90
|
+
'fh_matui.components._make_button_property': ( 'components.html#_make_button_property',
|
|
91
|
+
'fh_matui/components.py'),
|
|
92
|
+
'fh_matui.components._snap_to_valid_cols': ( 'components.html#_snap_to_valid_cols',
|
|
93
|
+
'fh_matui/components.py'),
|
|
94
|
+
'fh_matui.components._wrap_grid_children': ( 'components.html#_wrap_grid_children',
|
|
95
|
+
'fh_matui/components.py')},
|
|
96
|
+
'fh_matui.core': { 'fh_matui.core.BeerCssChain': ('core.html#beercsschain', 'fh_matui/core.py'),
|
|
97
|
+
'fh_matui.core.BeerCssChain.__init__': ('core.html#beercsschain.__init__', 'fh_matui/core.py'),
|
|
98
|
+
'fh_matui.core.BeerCssChain.__iter__': ('core.html#beercsschain.__iter__', 'fh_matui/core.py'),
|
|
99
|
+
'fh_matui.core.BeerCssChain.__repr__': ('core.html#beercsschain.__repr__', 'fh_matui/core.py'),
|
|
100
|
+
'fh_matui.core.BeerCssChain.__str__': ('core.html#beercsschain.__str__', 'fh_matui/core.py'),
|
|
101
|
+
'fh_matui.core._ThemeChain': ('core.html#_themechain', 'fh_matui/core.py'),
|
|
102
|
+
'fh_matui.core._ThemeChain.__init__': ('core.html#_themechain.__init__', 'fh_matui/core.py'),
|
|
103
|
+
'fh_matui.core._ThemeChain.headers': ('core.html#_themechain.headers', 'fh_matui/core.py'),
|
|
104
|
+
'fh_matui.core._ThemeNamespace': ('core.html#_themenamespace', 'fh_matui/core.py'),
|
|
105
|
+
'fh_matui.core._ThemeNamespace.amber': ('core.html#_themenamespace.amber', 'fh_matui/core.py'),
|
|
106
|
+
'fh_matui.core._ThemeNamespace.blue': ('core.html#_themenamespace.blue', 'fh_matui/core.py'),
|
|
107
|
+
'fh_matui.core._ThemeNamespace.blue_grey': ('core.html#_themenamespace.blue_grey', 'fh_matui/core.py'),
|
|
108
|
+
'fh_matui.core._ThemeNamespace.brown': ('core.html#_themenamespace.brown', 'fh_matui/core.py'),
|
|
109
|
+
'fh_matui.core._ThemeNamespace.cyan': ('core.html#_themenamespace.cyan', 'fh_matui/core.py'),
|
|
110
|
+
'fh_matui.core._ThemeNamespace.deep_orange': ('core.html#_themenamespace.deep_orange', 'fh_matui/core.py'),
|
|
111
|
+
'fh_matui.core._ThemeNamespace.deep_purple': ('core.html#_themenamespace.deep_purple', 'fh_matui/core.py'),
|
|
112
|
+
'fh_matui.core._ThemeNamespace.gray': ('core.html#_themenamespace.gray', 'fh_matui/core.py'),
|
|
113
|
+
'fh_matui.core._ThemeNamespace.green': ('core.html#_themenamespace.green', 'fh_matui/core.py'),
|
|
114
|
+
'fh_matui.core._ThemeNamespace.grey': ('core.html#_themenamespace.grey', 'fh_matui/core.py'),
|
|
115
|
+
'fh_matui.core._ThemeNamespace.indigo': ('core.html#_themenamespace.indigo', 'fh_matui/core.py'),
|
|
116
|
+
'fh_matui.core._ThemeNamespace.light_blue': ('core.html#_themenamespace.light_blue', 'fh_matui/core.py'),
|
|
117
|
+
'fh_matui.core._ThemeNamespace.light_green': ('core.html#_themenamespace.light_green', 'fh_matui/core.py'),
|
|
118
|
+
'fh_matui.core._ThemeNamespace.lime': ('core.html#_themenamespace.lime', 'fh_matui/core.py'),
|
|
119
|
+
'fh_matui.core._ThemeNamespace.neutral': ('core.html#_themenamespace.neutral', 'fh_matui/core.py'),
|
|
120
|
+
'fh_matui.core._ThemeNamespace.orange': ('core.html#_themenamespace.orange', 'fh_matui/core.py'),
|
|
121
|
+
'fh_matui.core._ThemeNamespace.pink': ('core.html#_themenamespace.pink', 'fh_matui/core.py'),
|
|
122
|
+
'fh_matui.core._ThemeNamespace.purple': ('core.html#_themenamespace.purple', 'fh_matui/core.py'),
|
|
123
|
+
'fh_matui.core._ThemeNamespace.red': ('core.html#_themenamespace.red', 'fh_matui/core.py'),
|
|
124
|
+
'fh_matui.core._ThemeNamespace.rose': ('core.html#_themenamespace.rose', 'fh_matui/core.py'),
|
|
125
|
+
'fh_matui.core._ThemeNamespace.slate': ('core.html#_themenamespace.slate', 'fh_matui/core.py'),
|
|
126
|
+
'fh_matui.core._ThemeNamespace.stone': ('core.html#_themenamespace.stone', 'fh_matui/core.py'),
|
|
127
|
+
'fh_matui.core._ThemeNamespace.teal': ('core.html#_themenamespace.teal', 'fh_matui/core.py'),
|
|
128
|
+
'fh_matui.core._ThemeNamespace.violet': ('core.html#_themenamespace.violet', 'fh_matui/core.py'),
|
|
129
|
+
'fh_matui.core._ThemeNamespace.yellow': ('core.html#_themenamespace.yellow', 'fh_matui/core.py'),
|
|
130
|
+
'fh_matui.core._ThemeNamespace.zinc': ('core.html#_themenamespace.zinc', 'fh_matui/core.py')},
|
|
131
|
+
'fh_matui.datatable': { 'fh_matui.datatable.CrudContext': ('datatable.html#crudcontext', 'fh_matui/datatable.py'),
|
|
132
|
+
'fh_matui.datatable.DataTable': ('datatable.html#datatable', 'fh_matui/datatable.py'),
|
|
133
|
+
'fh_matui.datatable.DataTableResource': ('datatable.html#datatableresource', 'fh_matui/datatable.py'),
|
|
134
|
+
'fh_matui.datatable.DataTableResource.__init__': ( 'datatable.html#datatableresource.__init__',
|
|
135
|
+
'fh_matui/datatable.py'),
|
|
136
|
+
'fh_matui.datatable.DataTableResource._build_context': ( 'datatable.html#datatableresource._build_context',
|
|
137
|
+
'fh_matui/datatable.py'),
|
|
138
|
+
'fh_matui.datatable.DataTableResource._call_hook': ( 'datatable.html#datatableresource._call_hook',
|
|
139
|
+
'fh_matui/datatable.py'),
|
|
140
|
+
'fh_matui.datatable.DataTableResource._error_toast': ( 'datatable.html#datatableresource._error_toast',
|
|
141
|
+
'fh_matui/datatable.py'),
|
|
142
|
+
'fh_matui.datatable.DataTableResource._filter_by_search': ( 'datatable.html#datatableresource._filter_by_search',
|
|
143
|
+
'fh_matui/datatable.py'),
|
|
144
|
+
'fh_matui.datatable.DataTableResource._get_filtered_data': ( 'datatable.html#datatableresource._get_filtered_data',
|
|
145
|
+
'fh_matui/datatable.py'),
|
|
146
|
+
'fh_matui.datatable.DataTableResource._handle_action': ( 'datatable.html#datatableresource._handle_action',
|
|
147
|
+
'fh_matui/datatable.py'),
|
|
148
|
+
'fh_matui.datatable.DataTableResource._handle_save': ( 'datatable.html#datatableresource._handle_save',
|
|
149
|
+
'fh_matui/datatable.py'),
|
|
150
|
+
'fh_matui.datatable.DataTableResource._handle_table': ( 'datatable.html#datatableresource._handle_table',
|
|
151
|
+
'fh_matui/datatable.py'),
|
|
152
|
+
'fh_matui.datatable.DataTableResource._paginate': ( 'datatable.html#datatableresource._paginate',
|
|
153
|
+
'fh_matui/datatable.py'),
|
|
154
|
+
'fh_matui.datatable.DataTableResource._register_routes': ( 'datatable.html#datatableresource._register_routes',
|
|
155
|
+
'fh_matui/datatable.py'),
|
|
156
|
+
'fh_matui.datatable.DataTableResource._success_toast': ( 'datatable.html#datatableresource._success_toast',
|
|
157
|
+
'fh_matui/datatable.py'),
|
|
158
|
+
'fh_matui.datatable.DataTableResource._wrap_modal': ( 'datatable.html#datatableresource._wrap_modal',
|
|
159
|
+
'fh_matui/datatable.py'),
|
|
160
|
+
'fh_matui.datatable.DataTableResource._wrap_response': ( 'datatable.html#datatableresource._wrap_response',
|
|
161
|
+
'fh_matui/datatable.py'),
|
|
162
|
+
'fh_matui.datatable._action_menu': ('datatable.html#_action_menu', 'fh_matui/datatable.py'),
|
|
163
|
+
'fh_matui.datatable._is_htmx_request': ('datatable.html#_is_htmx_request', 'fh_matui/datatable.py'),
|
|
164
|
+
'fh_matui.datatable._page_size_select': ('datatable.html#_page_size_select', 'fh_matui/datatable.py'),
|
|
165
|
+
'fh_matui.datatable._safe_int': ('datatable.html#_safe_int', 'fh_matui/datatable.py'),
|
|
166
|
+
'fh_matui.datatable._to_dict': ('datatable.html#_to_dict', 'fh_matui/datatable.py'),
|
|
167
|
+
'fh_matui.datatable.table_state_from_request': ( 'datatable.html#table_state_from_request',
|
|
168
|
+
'fh_matui/datatable.py')},
|
|
169
|
+
'fh_matui.foundations': { 'fh_matui.foundations.VEnum': ('foundations.html#venum', 'fh_matui/foundations.py'),
|
|
170
|
+
'fh_matui.foundations.VEnum.__add__': ('foundations.html#venum.__add__', 'fh_matui/foundations.py'),
|
|
171
|
+
'fh_matui.foundations.VEnum.__radd__': ('foundations.html#venum.__radd__', 'fh_matui/foundations.py'),
|
|
172
|
+
'fh_matui.foundations.VEnum.__str__': ('foundations.html#venum.__str__', 'fh_matui/foundations.py'),
|
|
173
|
+
'fh_matui.foundations.dedupe_preserve_order': ( 'foundations.html#dedupe_preserve_order',
|
|
174
|
+
'fh_matui/foundations.py'),
|
|
175
|
+
'fh_matui.foundations.normalize_tokens': ( 'foundations.html#normalize_tokens',
|
|
176
|
+
'fh_matui/foundations.py'),
|
|
177
|
+
'fh_matui.foundations.stringify': ('foundations.html#stringify', 'fh_matui/foundations.py')},
|
|
178
|
+
'fh_matui.web_pages': { 'fh_matui.web_pages.ContentPage': ('web_pages.html#contentpage', 'fh_matui/web_pages.py'),
|
|
179
|
+
'fh_matui.web_pages.FAQSection': ('web_pages.html#faqsection', 'fh_matui/web_pages.py'),
|
|
180
|
+
'fh_matui.web_pages.FeatureShowcase': ('web_pages.html#featureshowcase', 'fh_matui/web_pages.py'),
|
|
181
|
+
'fh_matui.web_pages.FeaturesGrid': ('web_pages.html#featuresgrid', 'fh_matui/web_pages.py'),
|
|
182
|
+
'fh_matui.web_pages.HeroSection': ('web_pages.html#herosection', 'fh_matui/web_pages.py'),
|
|
183
|
+
'fh_matui.web_pages.LandingNavBar': ('web_pages.html#landingnavbar', 'fh_matui/web_pages.py'),
|
|
184
|
+
'fh_matui.web_pages.LandingPageSimple': ('web_pages.html#landingpagesimple', 'fh_matui/web_pages.py'),
|
|
185
|
+
'fh_matui.web_pages.MarkdownSection': ('web_pages.html#markdownsection', 'fh_matui/web_pages.py'),
|
|
186
|
+
'fh_matui.web_pages.PageFooter': ('web_pages.html#pagefooter', 'fh_matui/web_pages.py'),
|
|
187
|
+
'fh_matui.web_pages.PricingSection': ('web_pages.html#pricingsection', 'fh_matui/web_pages.py'),
|
|
188
|
+
'fh_matui.web_pages._SectionWave': ('web_pages.html#_sectionwave', 'fh_matui/web_pages.py'),
|
|
189
|
+
'fh_matui.web_pages._calc_savings_pct': ('web_pages.html#_calc_savings_pct', 'fh_matui/web_pages.py'),
|
|
190
|
+
'fh_matui.web_pages._pricing_card': ('web_pages.html#_pricing_card', 'fh_matui/web_pages.py'),
|
|
191
|
+
'fh_matui.web_pages._pricing_toggle_js': ( 'web_pages.html#_pricing_toggle_js',
|
|
192
|
+
'fh_matui/web_pages.py')}}}
|
fh_matui/app_pages.py
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"""Pre-built page layouts for authenticated app experiences (login, dashboard, admin)."""
|
|
2
|
+
|
|
3
|
+
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/03_app_pages.ipynb.
|
|
4
|
+
|
|
5
|
+
# %% auto 0
|
|
6
|
+
__all__ = ['LoginScreen']
|
|
7
|
+
|
|
8
|
+
# %% ../nbs/03_app_pages.ipynb 2
|
|
9
|
+
from fastcore.utils import *
|
|
10
|
+
from fasthtml.common import *
|
|
11
|
+
from fasthtml.jupyter import *
|
|
12
|
+
from fastlite import *
|
|
13
|
+
import fasthtml.components as fc
|
|
14
|
+
from fasthtml.common import A, Button as FhButton, I, Span
|
|
15
|
+
from .foundations import normalize_tokens, stringify, VEnum
|
|
16
|
+
from .core import *
|
|
17
|
+
from .components import *
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# %% ../nbs/03_app_pages.ipynb 6
|
|
22
|
+
# Default inspirational quotes for login screen (fully customizable via parameter)
|
|
23
|
+
_DEFAULT_LOGIN_QUOTES = [
|
|
24
|
+
"The only way to do great work is to love what you do. — Steve Jobs",
|
|
25
|
+
"Innovation distinguishes between a leader and a follower. — Steve Jobs",
|
|
26
|
+
"Stay hungry, stay foolish. — Steve Jobs",
|
|
27
|
+
"The best time to plant a tree was 20 years ago. The second best time is now. — Chinese Proverb",
|
|
28
|
+
"Success is not final, failure is not fatal: it is the courage to continue that counts. — Winston Churchill",
|
|
29
|
+
"The future belongs to those who believe in the beauty of their dreams. — Eleanor Roosevelt",
|
|
30
|
+
"It does not matter how slowly you go as long as you do not stop. — Confucius",
|
|
31
|
+
"Everything you've ever wanted is on the other side of fear. — George Addair",
|
|
32
|
+
"The only limit to our realization of tomorrow is our doubts of today. — Franklin D. Roosevelt",
|
|
33
|
+
"Believe you can and you're halfway there. — Theodore Roosevelt",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
# CSS for login screen: gradient background and quote rotation
|
|
37
|
+
_LOGIN_SCREEN_CSS = """
|
|
38
|
+
/* Hero gradient background - uses current theme colors */
|
|
39
|
+
.login-brand-panel {
|
|
40
|
+
position: relative;
|
|
41
|
+
background: linear-gradient(135deg,
|
|
42
|
+
var(--primary-container) 0%,
|
|
43
|
+
var(--surface-container) 50%,
|
|
44
|
+
var(--secondary-container) 100%);
|
|
45
|
+
overflow: hidden;
|
|
46
|
+
transition: background 1s ease-in-out;
|
|
47
|
+
}
|
|
48
|
+
.login-brand-panel::before {
|
|
49
|
+
content: '';
|
|
50
|
+
position: absolute;
|
|
51
|
+
inset: 0;
|
|
52
|
+
background: radial-gradient(circle at 20% 80%, var(--primary) 0%, transparent 50%),
|
|
53
|
+
radial-gradient(circle at 80% 20%, var(--secondary) 0%, transparent 50%);
|
|
54
|
+
opacity: 0.15;
|
|
55
|
+
pointer-events: none;
|
|
56
|
+
}
|
|
57
|
+
.login-brand-content {
|
|
58
|
+
position: relative;
|
|
59
|
+
z-index: 1;
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
height: 100%;
|
|
63
|
+
min-height: 100vh;
|
|
64
|
+
padding: 2rem;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Branding anchored at top-left */
|
|
68
|
+
.login-branding {
|
|
69
|
+
flex-shrink: 0;
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
gap: 0.75rem;
|
|
73
|
+
justify-content: flex-start;
|
|
74
|
+
}
|
|
75
|
+
.login-branding img {
|
|
76
|
+
max-height: 3rem;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Quote in center - larger and prominent */
|
|
80
|
+
.login-quotes-wrapper {
|
|
81
|
+
flex: 1;
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
justify-content: center;
|
|
85
|
+
}
|
|
86
|
+
.login-quotes {
|
|
87
|
+
position: relative;
|
|
88
|
+
min-height: 6rem;
|
|
89
|
+
max-width: 500px;
|
|
90
|
+
width: 100%;
|
|
91
|
+
}
|
|
92
|
+
.login-quote {
|
|
93
|
+
position: absolute;
|
|
94
|
+
width: 100%;
|
|
95
|
+
opacity: 0;
|
|
96
|
+
animation: quote-fade 100s infinite;
|
|
97
|
+
text-align: center;
|
|
98
|
+
font-style: italic;
|
|
99
|
+
font-size: 1.25rem;
|
|
100
|
+
line-height: 1.6;
|
|
101
|
+
}
|
|
102
|
+
/* Stagger each quote: 10 quotes × 10s each = 100s total cycle */
|
|
103
|
+
.login-quote:nth-child(1) { animation-delay: 0s; }
|
|
104
|
+
.login-quote:nth-child(2) { animation-delay: 10s; }
|
|
105
|
+
.login-quote:nth-child(3) { animation-delay: 20s; }
|
|
106
|
+
.login-quote:nth-child(4) { animation-delay: 30s; }
|
|
107
|
+
.login-quote:nth-child(5) { animation-delay: 40s; }
|
|
108
|
+
.login-quote:nth-child(6) { animation-delay: 50s; }
|
|
109
|
+
.login-quote:nth-child(7) { animation-delay: 60s; }
|
|
110
|
+
.login-quote:nth-child(8) { animation-delay: 70s; }
|
|
111
|
+
.login-quote:nth-child(9) { animation-delay: 80s; }
|
|
112
|
+
.login-quote:nth-child(10) { animation-delay: 90s; }
|
|
113
|
+
|
|
114
|
+
@keyframes quote-fade {
|
|
115
|
+
0%, 8% { opacity: 0; transform: translateY(10px); }
|
|
116
|
+
10%, 18% { opacity: 1; transform: translateY(0); }
|
|
117
|
+
20%, 100% { opacity: 0; transform: translateY(-10px); }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Mobile: hide quotes, simplify layout */
|
|
121
|
+
@media (max-width: 992px) {
|
|
122
|
+
.login-quotes-wrapper { display: none; }
|
|
123
|
+
.login-brand-content {
|
|
124
|
+
min-height: auto;
|
|
125
|
+
padding: 1.5rem;
|
|
126
|
+
}
|
|
127
|
+
.login-branding {
|
|
128
|
+
justify-content: center;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
# Minimal JS for cycling BeerCSS theme colors
|
|
134
|
+
_LOGIN_COLOR_CYCLE_JS = """
|
|
135
|
+
(function() {
|
|
136
|
+
const colors = ['primary', 'secondary', 'tertiary'];
|
|
137
|
+
let idx = 0;
|
|
138
|
+
const panel = document.querySelector('.login-brand-panel');
|
|
139
|
+
if (!panel) return;
|
|
140
|
+
|
|
141
|
+
setInterval(function() {
|
|
142
|
+
idx = (idx + 1) % colors.length;
|
|
143
|
+
panel.style.background = 'linear-gradient(135deg, var(--' + colors[idx] + '-container) 0%, var(--surface-container) 50%, var(--' + colors[(idx+1) % colors.length] + '-container) 100%)';
|
|
144
|
+
}, 30000);
|
|
145
|
+
})();
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
def LoginScreen(
|
|
149
|
+
title='Sign In',
|
|
150
|
+
subtitle='Choose your preferred sign-in method',
|
|
151
|
+
providers=None,
|
|
152
|
+
left_slot=None,
|
|
153
|
+
logo_src=None,
|
|
154
|
+
brand_name=None, # Brand name displayed at top-left of left panel
|
|
155
|
+
quotes=None, # List of quotes to rotate (uses defaults if None, pass [] to disable)
|
|
156
|
+
color_cycle=True, # Enable color cycling animation
|
|
157
|
+
testimonial_text=None, # Legacy: single testimonial (use quotes instead)
|
|
158
|
+
brand_bg_cls='primary', # Legacy: fallback if gradient fails
|
|
159
|
+
left_cols=9, # Number of columns for left side (out of 12)
|
|
160
|
+
cls='',
|
|
161
|
+
**kwargs
|
|
162
|
+
):
|
|
163
|
+
"""
|
|
164
|
+
A configurable Split Login Screen with dynamic branding.
|
|
165
|
+
|
|
166
|
+
Features:
|
|
167
|
+
- Hero-style gradient background (same as landing page)
|
|
168
|
+
- Brand name + logo at top-left corner
|
|
169
|
+
- Rotating inspirational quotes in center (pure CSS, hidden on mobile)
|
|
170
|
+
- Optional color cycling through BeerCSS theme colors (minimal JS)
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
title: Sign-in form title
|
|
174
|
+
subtitle: Sign-in form subtitle
|
|
175
|
+
providers: List of OAuth provider dicts [{label, icon, href, cls}, ...]
|
|
176
|
+
left_slot: Custom content for left panel (overrides default branding)
|
|
177
|
+
logo_src: URL/path to logo image
|
|
178
|
+
brand_name: Brand name displayed at top-left corner
|
|
179
|
+
quotes: List of quote strings to rotate. Defaults to inspirational quotes.
|
|
180
|
+
Pass empty list [] to disable quotes entirely.
|
|
181
|
+
color_cycle: Enable gradient color cycling (default True)
|
|
182
|
+
left_cols: Grid columns for left panel (out of 12). Default 9 = 75%
|
|
183
|
+
|
|
184
|
+
Example:
|
|
185
|
+
LoginScreen(
|
|
186
|
+
brand_name="MyApp",
|
|
187
|
+
logo_src="/static/logo.svg",
|
|
188
|
+
quotes=[
|
|
189
|
+
"Your custom quote here — Author",
|
|
190
|
+
"Another inspiring message — Source",
|
|
191
|
+
],
|
|
192
|
+
)
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
# 1. Defaults
|
|
196
|
+
if providers is None:
|
|
197
|
+
providers = [
|
|
198
|
+
{'label': 'Continue with Google', 'icon': 'https://authjs.dev/img/providers/google.svg', 'href': '/auth/google', 'cls': 'border responsive surface'},
|
|
199
|
+
{'label': 'Continue with GitHub', 'icon': 'https://authjs.dev/img/providers/github.svg', 'icon_cls': 'invert', 'href': '/auth/github', 'cls': 'fill responsive inverse-surface'}
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
# Use default quotes if None, allow empty list to disable
|
|
203
|
+
if quotes is None:
|
|
204
|
+
quotes = _DEFAULT_LOGIN_QUOTES
|
|
205
|
+
|
|
206
|
+
# 2. Build Left Column - Branded layout
|
|
207
|
+
if left_slot:
|
|
208
|
+
left_content = left_slot
|
|
209
|
+
else:
|
|
210
|
+
# Top-left: Logo + Brand name (anchored at top-left via CSS)
|
|
211
|
+
top_section = []
|
|
212
|
+
if logo_src:
|
|
213
|
+
top_section.append(Img(src=logo_src, cls="responsive"))
|
|
214
|
+
if brand_name:
|
|
215
|
+
top_section.append(H3(brand_name, cls="bold no-margin"))
|
|
216
|
+
elif not logo_src:
|
|
217
|
+
top_section.append(H3("Welcome", cls="bold no-margin"))
|
|
218
|
+
|
|
219
|
+
top_branding = Div(*top_section, cls="login-branding")
|
|
220
|
+
|
|
221
|
+
# Center section: Rotating quotes (larger, centered)
|
|
222
|
+
center_quotes = Div(cls="login-quotes-wrapper")
|
|
223
|
+
if quotes:
|
|
224
|
+
quote_elements = [
|
|
225
|
+
P(f'"{q}"', cls="login-quote")
|
|
226
|
+
for q in quotes[:10] # Max 10 for CSS animation
|
|
227
|
+
]
|
|
228
|
+
center_quotes = Div(
|
|
229
|
+
Div(*quote_elements, cls="login-quotes"),
|
|
230
|
+
cls="login-quotes-wrapper"
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# Legacy support
|
|
234
|
+
if testimonial_text and not quotes:
|
|
235
|
+
center_quotes = Div(
|
|
236
|
+
Blockquote(P(f'"{testimonial_text}"', cls="italic center-align large-text")),
|
|
237
|
+
cls="login-quotes-wrapper"
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
left_content = Div(
|
|
241
|
+
top_branding,
|
|
242
|
+
center_quotes,
|
|
243
|
+
cls="login-brand-content"
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# 3. Build Right Column Buttons
|
|
247
|
+
button_list = []
|
|
248
|
+
for p in providers:
|
|
249
|
+
icon = Img(src=p['icon'], cls=f"circle tiny spacing-right {p.get('icon_cls', '')}") if p.get('icon') else ""
|
|
250
|
+
button_list.append(
|
|
251
|
+
Div(
|
|
252
|
+
A(
|
|
253
|
+
Button(icon, Span(p['label']), cls=p.get('cls')),
|
|
254
|
+
href=p.get('href', '#')
|
|
255
|
+
),
|
|
256
|
+
cls="s12"
|
|
257
|
+
)
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
auth_buttons = Div(*button_list, cls="grid small-space")
|
|
261
|
+
|
|
262
|
+
right_content = Div(
|
|
263
|
+
H4(title, cls="center-align bold margin-bottom"),
|
|
264
|
+
P(subtitle, cls="center-align medium-text margin-bottom no-wrap"),
|
|
265
|
+
auth_buttons,
|
|
266
|
+
cls="medium-width"
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# 4. Build page
|
|
270
|
+
right_cols = 12 - left_cols
|
|
271
|
+
left_panel_cls = f"s12 m12 l{left_cols} login-brand-panel"
|
|
272
|
+
|
|
273
|
+
# Include CSS, and optionally JS for color cycling
|
|
274
|
+
head_elements = [Style(_LOGIN_SCREEN_CSS)]
|
|
275
|
+
if color_cycle:
|
|
276
|
+
head_elements.append(Script(_LOGIN_COLOR_CYCLE_JS))
|
|
277
|
+
|
|
278
|
+
return Div(
|
|
279
|
+
*head_elements,
|
|
280
|
+
# Left (Brand) - gradient background with branding
|
|
281
|
+
Div(left_content, cls=left_panel_cls),
|
|
282
|
+
# Right (Auth) - clean form area
|
|
283
|
+
Div(
|
|
284
|
+
DivCentered(right_content),
|
|
285
|
+
cls=f"s12 m12 l{right_cols} padding middle-align center-align"
|
|
286
|
+
),
|
|
287
|
+
cls=f"grid no-space {cls}".strip(),
|
|
288
|
+
style="min-height: 100vh;",
|
|
289
|
+
**kwargs
|
|
290
|
+
)
|
|
291
|
+
|