fh-matui 0.9.1__py3-none-any.whl → 0.9.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.
fh_matui/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.9"
1
+ __version__ = "0.9.3"
fh_matui/_modidx.py CHANGED
@@ -128,35 +128,35 @@ d = { 'settings': { 'branch': 'master',
128
128
  'fh_matui.core._ThemeNamespace.violet': ('core.html#_themenamespace.violet', 'fh_matui/core.py'),
129
129
  'fh_matui.core._ThemeNamespace.yellow': ('core.html#_themenamespace.yellow', 'fh_matui/core.py'),
130
130
  'fh_matui.core._ThemeNamespace.zinc': ('core.html#_themenamespace.zinc', 'fh_matui/core.py')},
131
- 'fh_matui.datatable': { 'fh_matui.datatable.DataTable': ('table.html#datatable', 'fh_matui/datatable.py'),
132
- 'fh_matui.datatable.DataTableResource': ('table.html#datatableresource', 'fh_matui/datatable.py'),
133
- 'fh_matui.datatable.DataTableResource.__init__': ( 'table.html#datatableresource.__init__',
131
+ 'fh_matui.datatable': { 'fh_matui.datatable.DataTable': ('datatable.html#datatable', 'fh_matui/datatable.py'),
132
+ 'fh_matui.datatable.DataTableResource': ('datatable.html#datatableresource', 'fh_matui/datatable.py'),
133
+ 'fh_matui.datatable.DataTableResource.__init__': ( 'datatable.html#datatableresource.__init__',
134
134
  'fh_matui/datatable.py'),
135
- 'fh_matui.datatable.DataTableResource._error_toast': ( 'table.html#datatableresource._error_toast',
135
+ 'fh_matui.datatable.DataTableResource._error_toast': ( 'datatable.html#datatableresource._error_toast',
136
136
  'fh_matui/datatable.py'),
137
- 'fh_matui.datatable.DataTableResource._filter_by_search': ( 'table.html#datatableresource._filter_by_search',
137
+ 'fh_matui.datatable.DataTableResource._filter_by_search': ( 'datatable.html#datatableresource._filter_by_search',
138
138
  'fh_matui/datatable.py'),
139
- 'fh_matui.datatable.DataTableResource._get_filtered_data': ( 'table.html#datatableresource._get_filtered_data',
139
+ 'fh_matui.datatable.DataTableResource._get_filtered_data': ( 'datatable.html#datatableresource._get_filtered_data',
140
140
  'fh_matui/datatable.py'),
141
- 'fh_matui.datatable.DataTableResource._handle_action': ( 'table.html#datatableresource._handle_action',
141
+ 'fh_matui.datatable.DataTableResource._handle_action': ( 'datatable.html#datatableresource._handle_action',
142
142
  'fh_matui/datatable.py'),
143
- 'fh_matui.datatable.DataTableResource._handle_save': ( 'table.html#datatableresource._handle_save',
143
+ 'fh_matui.datatable.DataTableResource._handle_save': ( 'datatable.html#datatableresource._handle_save',
144
144
  'fh_matui/datatable.py'),
145
- 'fh_matui.datatable.DataTableResource._handle_table': ( 'table.html#datatableresource._handle_table',
145
+ 'fh_matui.datatable.DataTableResource._handle_table': ( 'datatable.html#datatableresource._handle_table',
146
146
  'fh_matui/datatable.py'),
147
- 'fh_matui.datatable.DataTableResource._paginate': ( 'table.html#datatableresource._paginate',
147
+ 'fh_matui.datatable.DataTableResource._paginate': ( 'datatable.html#datatableresource._paginate',
148
148
  'fh_matui/datatable.py'),
149
- 'fh_matui.datatable.DataTableResource._register_routes': ( 'table.html#datatableresource._register_routes',
149
+ 'fh_matui.datatable.DataTableResource._register_routes': ( 'datatable.html#datatableresource._register_routes',
150
150
  'fh_matui/datatable.py'),
151
- 'fh_matui.datatable.DataTableResource._success_toast': ( 'table.html#datatableresource._success_toast',
151
+ 'fh_matui.datatable.DataTableResource._success_toast': ( 'datatable.html#datatableresource._success_toast',
152
152
  'fh_matui/datatable.py'),
153
- 'fh_matui.datatable.DataTableResource._wrap_modal': ( 'table.html#datatableresource._wrap_modal',
153
+ 'fh_matui.datatable.DataTableResource._wrap_modal': ( 'datatable.html#datatableresource._wrap_modal',
154
154
  'fh_matui/datatable.py'),
155
- 'fh_matui.datatable._action_menu': ('table.html#_action_menu', 'fh_matui/datatable.py'),
156
- 'fh_matui.datatable._page_size_select': ('table.html#_page_size_select', 'fh_matui/datatable.py'),
157
- 'fh_matui.datatable._safe_int': ('table.html#_safe_int', 'fh_matui/datatable.py'),
158
- 'fh_matui.datatable._to_dict': ('table.html#_to_dict', 'fh_matui/datatable.py'),
159
- 'fh_matui.datatable.table_state_from_request': ( 'table.html#table_state_from_request',
155
+ 'fh_matui.datatable._action_menu': ('datatable.html#_action_menu', 'fh_matui/datatable.py'),
156
+ 'fh_matui.datatable._page_size_select': ('datatable.html#_page_size_select', 'fh_matui/datatable.py'),
157
+ 'fh_matui.datatable._safe_int': ('datatable.html#_safe_int', 'fh_matui/datatable.py'),
158
+ 'fh_matui.datatable._to_dict': ('datatable.html#_to_dict', 'fh_matui/datatable.py'),
159
+ 'fh_matui.datatable.table_state_from_request': ( 'datatable.html#table_state_from_request',
160
160
  'fh_matui/datatable.py')},
161
161
  'fh_matui.foundations': { 'fh_matui.foundations.VEnum': ('foundations.html#venum', 'fh_matui/foundations.py'),
162
162
  'fh_matui.foundations.VEnum.__add__': ('foundations.html#venum.__add__', 'fh_matui/foundations.py'),
@@ -171,6 +171,7 @@ d = { 'settings': { 'branch': 'master',
171
171
  'fh_matui.web_pages.FAQSection': ('web_pages.html#faqsection', 'fh_matui/web_pages.py'),
172
172
  'fh_matui.web_pages.FeatureShowcase': ('web_pages.html#featureshowcase', 'fh_matui/web_pages.py'),
173
173
  'fh_matui.web_pages.FeaturesGrid': ('web_pages.html#featuresgrid', 'fh_matui/web_pages.py'),
174
+ 'fh_matui.web_pages.HeroSection': ('web_pages.html#herosection', 'fh_matui/web_pages.py'),
174
175
  'fh_matui.web_pages.LandingNavBar': ('web_pages.html#landingnavbar', 'fh_matui/web_pages.py'),
175
176
  'fh_matui.web_pages.LandingPageSimple': ('web_pages.html#landingpagesimple', 'fh_matui/web_pages.py'),
176
177
  'fh_matui.web_pages.MarkdownSection': ('web_pages.html#markdownsection', 'fh_matui/web_pages.py'),
fh_matui/components.py CHANGED
@@ -60,7 +60,7 @@ for name, css in BUTTON_SPECIALS.items():
60
60
 
61
61
  ButtonT = _ButtonChain()
62
62
 
63
- # %% ../nbs/02_components.ipynb 11
63
+ # %% ../nbs/02_components.ipynb 10
64
64
  #| code-fold: true
65
65
  class _AnchorChain(BeerCssChain):
66
66
  """Chainable anchor style helper"""
@@ -84,7 +84,7 @@ for name, css in ANCHOR_SPECIALS.items():
84
84
 
85
85
  AT = _AnchorChain()
86
86
 
87
- # %% ../nbs/02_components.ipynb 14
87
+ # %% ../nbs/02_components.ipynb 13
88
88
  class SpaceT(VEnum):
89
89
  """Space types using BeerCSS spacing classes"""
90
90
  no_space = 'no-space'
@@ -224,7 +224,7 @@ def Grid(*cells, space=SpaceT.medium_space,
224
224
  grid_cls = [t for t in grid_cls if t]
225
225
  return Div(*wrapped_cells, cls=stringify(dedupe_preserve_order(grid_cls)), **kwargs)
226
226
 
227
- # %% ../nbs/02_components.ipynb 17
227
+ # %% ../nbs/02_components.ipynb 16
228
228
  def DivLAligned(*c, cls='', **kwargs):
229
229
  """MonsterUI-compatible left-aligned row using BeerCSS tokens."""
230
230
  cls_tokens = normalize_tokens(cls)
@@ -235,7 +235,7 @@ def DivLAligned(*c, cls='', **kwargs):
235
235
 
236
236
 
237
237
 
238
- # %% ../nbs/02_components.ipynb 19
238
+ # %% ../nbs/02_components.ipynb 18
239
239
  def DivVStacked(*c, responsive=True, padding=True, cls='', **kwargs):
240
240
  """Responsive vertical stack with padding and mobile compatibility."""
241
241
  cls_tokens = normalize_tokens(cls)
@@ -253,7 +253,7 @@ def DivVStacked(*c, responsive=True, padding=True, cls='', **kwargs):
253
253
  return Div(*c, cls=stringify(dedupe_preserve_order(tokens)), **kwargs)
254
254
 
255
255
 
256
- # %% ../nbs/02_components.ipynb 21
256
+ # %% ../nbs/02_components.ipynb 20
257
257
  def DivHStacked(*c, responsive=True, padding=True, cls='', **kwargs):
258
258
  """Responsive horizontal stack with padding and mobile compatibility."""
259
259
  cls_tokens = normalize_tokens(cls)
@@ -271,7 +271,7 @@ def DivHStacked(*c, responsive=True, padding=True, cls='', **kwargs):
271
271
  return Div(*c, cls=stringify(dedupe_preserve_order(tokens)), **kwargs)
272
272
 
273
273
 
274
- # %% ../nbs/02_components.ipynb 23
274
+ # %% ../nbs/02_components.ipynb 22
275
275
  def DivRAligned(*c, cls='', **kwargs):
276
276
  """MonsterUI-compatible right-aligned row using BeerCSS tokens."""
277
277
  cls_tokens = normalize_tokens(cls)
@@ -280,7 +280,7 @@ def DivRAligned(*c, cls='', **kwargs):
280
280
  tokens = [t for t in tokens if t]
281
281
  return DivHStacked(*c, cls=stringify(dedupe_preserve_order(tokens)), **kwargs)
282
282
 
283
- # %% ../nbs/02_components.ipynb 25
283
+ # %% ../nbs/02_components.ipynb 24
284
284
  def DivCentered(*c, cls='', **kwargs):
285
285
  """Center-aligned container using BeerCSS tokens."""
286
286
  cls_tokens = normalize_tokens(cls)
@@ -289,7 +289,7 @@ def DivCentered(*c, cls='', **kwargs):
289
289
  tokens = [t for t in tokens if t]
290
290
  return Div(*c, cls=stringify(dedupe_preserve_order(tokens)), **kwargs)
291
291
 
292
- # %% ../nbs/02_components.ipynb 27
292
+ # %% ../nbs/02_components.ipynb 26
293
293
  def DivFullySpaced(*c, cls='', **kwargs):
294
294
  """Row with children stretched to far ends using BeerCSS `max` spacers."""
295
295
  cls_tokens = normalize_tokens(cls)
@@ -310,7 +310,7 @@ def DivFullySpaced(*c, cls='', **kwargs):
310
310
  base = spaced_children
311
311
  return Div(*base, cls=stringify(dedupe_preserve_order(tokens)), **kwargs)
312
312
 
313
- # %% ../nbs/02_components.ipynb 30
313
+ # %% ../nbs/02_components.ipynb 29
314
314
  #| code-fold: true
315
315
  def Icon(icon: str, size: str = None, fill: bool = False, cls = (), **kwargs):
316
316
  """Material Design icon with optional size and fill"""
@@ -321,7 +321,7 @@ def Icon(icon: str, size: str = None, fill: bool = False, cls = (), **kwargs):
321
321
  cls_str = ' '.join(icon_cls) if icon_cls else None
322
322
  return I(icon, cls=cls_str, **kwargs) if cls_str else I(icon, **kwargs)
323
323
 
324
- # %% ../nbs/02_components.ipynb 33
324
+ # %% ../nbs/02_components.ipynb 32
325
325
  #| code-fold: true
326
326
  def NavBar(*children, brand=None, sticky=False, cls='', **kwargs):
327
327
  """Horizontal navigation bar with optional brand and sticky positioning"""
@@ -330,7 +330,7 @@ def NavBar(*children, brand=None, sticky=False, cls='', **kwargs):
330
330
  return Nav(brand, Div(cls='max'), *children, cls=f"row middle-align padding {nav_cls}", **kwargs)
331
331
  return Nav(*children, cls=f"padding {nav_cls}", **kwargs)
332
332
 
333
- # %% ../nbs/02_components.ipynb 36
333
+ # %% ../nbs/02_components.ipynb 35
334
334
  def Modal(*c, id=None, footer=None, active=False, overlay=True, cls=(), **kwargs):
335
335
  """BeerCSS modal dialog with optional overlay and footer."""
336
336
  modal_cls = normalize_tokens(cls)
@@ -398,7 +398,7 @@ def ModalFooter(*c, cls=(), **kwargs):
398
398
  footer_cls.extend(['right-align', 'no-space'])
399
399
  return Nav(*c, cls=' '.join(footer_cls), **kwargs)
400
400
 
401
- # %% ../nbs/02_components.ipynb 39
401
+ # %% ../nbs/02_components.ipynb 38
402
402
  #| code-fold: true
403
403
  def Field(*c, label: bool = False, prefix: bool = False, suffix: bool = False, cls = '', **kwargs):
404
404
  """BeerCSS field wrapper for inputs with border/label/prefix/suffix styling."""
@@ -423,7 +423,7 @@ def LabelInput(label: str, id: str = None, placeholder: str = None, input_type:
423
423
  if suffix_icon: children.append(I(suffix_icon))
424
424
  return Field(*children, label=True, prefix=bool(prefix_icon), suffix=bool(suffix_icon), cls=cls)
425
425
 
426
- # %% ../nbs/02_components.ipynb 42
426
+ # %% ../nbs/02_components.ipynb 41
427
427
  #| code-fold: true
428
428
  def LabelInput(label: str, id: str = None, placeholder: str = None, input_type: str = 'text',
429
429
  prefix_icon: str = None, suffix_icon: str = None, value: str = None, cls = '', **kwargs):
@@ -445,7 +445,7 @@ def FormLabel(*c, cls=(), **kwargs):
445
445
  if cls_str: return Label(*c, cls=cls_str, **kwargs)
446
446
  return Label(*c, **kwargs)
447
447
 
448
- # %% ../nbs/02_components.ipynb 45
448
+ # %% ../nbs/02_components.ipynb 44
449
449
  #| code-fold: true
450
450
  def CheckboxX(*c, cls=(), **kwargs):
451
451
  """BeerCSS checkbox with label support."""
@@ -455,7 +455,7 @@ def CheckboxX(*c, cls=(), **kwargs):
455
455
  cls_str = stringify(checkbox_cls)
456
456
  return Label(Input(type='checkbox', **kwargs), Span(label_text) if label_text else Span(), cls=cls_str)
457
457
 
458
- # %% ../nbs/02_components.ipynb 48
458
+ # %% ../nbs/02_components.ipynb 47
459
459
  #| code-fold: true
460
460
  def Radio(*c, cls=(), **kwargs):
461
461
  """BeerCSS radio button with label."""
@@ -465,7 +465,7 @@ def Radio(*c, cls=(), **kwargs):
465
465
  cls_str = stringify(radio_cls)
466
466
  return Label(Input(type='radio', **kwargs), Span(label_text) if label_text else Span(), cls=cls_str)
467
467
 
468
- # %% ../nbs/02_components.ipynb 51
468
+ # %% ../nbs/02_components.ipynb 50
469
469
  #| code-fold: true
470
470
  def Switch(*c, cls=(), **kwargs):
471
471
  """BeerCSS toggle switch for on/off states.
@@ -492,7 +492,7 @@ def Switch(*c, cls=(), **kwargs):
492
492
  cls='middle-align'
493
493
  )
494
494
 
495
- # %% ../nbs/02_components.ipynb 54
495
+ # %% ../nbs/02_components.ipynb 53
496
496
  #| code-fold: true
497
497
  def TextArea(*c, cls=(), **kwargs):
498
498
  """BeerCSS textarea with field wrapper for consistent styling."""
@@ -500,7 +500,7 @@ def TextArea(*c, cls=(), **kwargs):
500
500
  textarea = Textarea(content, **kwargs) if content else Textarea(**kwargs)
501
501
  return Field(textarea, cls=cls)
502
502
 
503
- # %% ../nbs/02_components.ipynb 57
503
+ # %% ../nbs/02_components.ipynb 56
504
504
  #| code-fold: true
505
505
  def Range(*c, min=None, max=None, step=None, cls=(), **kwargs):
506
506
  """BeerCSS range slider with two-tone fill effect."""
@@ -529,7 +529,7 @@ def Range(*c, min=None, max=None, step=None, cls=(), **kwargs):
529
529
  style = f"--_start: 0%; --_end: {percentage:.1f}%;"
530
530
  return Label(Input(**input_attrs), Span(), cls=cls_str, style=style)
531
531
 
532
- # %% ../nbs/02_components.ipynb 60
532
+ # %% ../nbs/02_components.ipynb 59
533
533
  #| code-fold: true
534
534
  def Select(*items, value='', placeholder='Select...', prefix_icon=None, name='', cls=(), **kwargs):
535
535
  """BeerCSS menu-based select dropdown with rich styling."""
@@ -554,7 +554,7 @@ def Select(*items, value='', placeholder='Select...', prefix_icon=None, name='',
554
554
  cls_str = stringify(field_cls)
555
555
  return Div(*children, cls=cls_str)
556
556
 
557
- # %% ../nbs/02_components.ipynb 69
557
+ # %% ../nbs/02_components.ipynb 68
558
558
  #| code-fold: true
559
559
  def FormGrid(*c, cols: int = 1):
560
560
  """Responsive grid layout for form fields that stacks on mobile."""
@@ -563,7 +563,7 @@ def FormGrid(*c, cols: int = 1):
563
563
  wrapped = [Div(child, cls=col_cls) for child in c]
564
564
  return Div(*wrapped, cls="grid")
565
565
 
566
- # %% ../nbs/02_components.ipynb 72
566
+ # %% ../nbs/02_components.ipynb 71
567
567
  #| code-fold: true
568
568
  def Progress(*c, value='', max='100', cls=(), **kwargs):
569
569
  """Linear progress bar with value/max support."""
@@ -575,7 +575,7 @@ def Progress(*c, value='', max='100', cls=(), **kwargs):
575
575
  if cls_str: return fc.Progress(*c, cls=cls_str, **progress_attrs)
576
576
  return fc.Progress(*c, **progress_attrs)
577
577
 
578
- # %% ../nbs/02_components.ipynb 75
578
+ # %% ../nbs/02_components.ipynb 74
579
579
  #| code-fold: true
580
580
  def LoadingIndicator(size='medium', cls='', **kwargs):
581
581
  """BeerCSS circular spinner for async operations."""
@@ -583,7 +583,7 @@ def LoadingIndicator(size='medium', cls='', **kwargs):
583
583
  progress_cls = f"circle {size_cls} {cls}".strip()
584
584
  return fc.Progress(cls=progress_cls, **kwargs)
585
585
 
586
- # %% ../nbs/02_components.ipynb 78
586
+ # %% ../nbs/02_components.ipynb 77
587
587
  #| code-fold: true
588
588
  def Table(*c, cls = 'border', **kwargs):
589
589
  """BeerCSS table with optional border/stripes classes."""
@@ -651,14 +651,14 @@ def TableFromDicts(header_data, body_data, footer_data = None, header_cell_rende
651
651
  Tfoot(Tr(*[footer_cell_render(k, footer_data.get(k, '')) for k in header_data])) if footer_data else None,
652
652
  cls=cls, **kwargs)
653
653
 
654
- # %% ../nbs/02_components.ipynb 81
654
+ # %% ../nbs/02_components.ipynb 80
655
655
  #| code-fold: true
656
656
  def TableControls(*controls, cls='', **kwargs):
657
657
  """Toolbar container for table filters, search, and actions."""
658
658
  controls_cls = f"padding middle-align space {cls}".strip()
659
659
  return Div(*controls, cls=controls_cls, **kwargs)
660
660
 
661
- # %% ../nbs/02_components.ipynb 84
661
+ # %% ../nbs/02_components.ipynb 83
662
662
  #| code-fold: true
663
663
  def Pagination(current_page: int, total_pages: int, hx_get: str, hx_target: str = '#table-container',
664
664
  show_first_last: bool = True, cls='', **kwargs):
@@ -693,7 +693,7 @@ def Pagination(current_page: int, total_pages: int, hx_get: str, hx_target: str
693
693
  nav_cls = f"center-align middle-align {cls}".strip()
694
694
  return Nav(*buttons, cls=nav_cls, **kwargs)
695
695
 
696
- # %% ../nbs/02_components.ipynb 87
696
+ # %% ../nbs/02_components.ipynb 86
697
697
  #| code-fold: true
698
698
  def Card(*c, header = None, footer = None, body_cls = 'padding', header_cls = (), footer_cls = (), cls = (), **kwargs):
699
699
  """BeerCSS card with optional header/footer sections."""
@@ -707,7 +707,7 @@ def Card(*c, header = None, footer = None, body_cls = 'padding', header_cls = ()
707
707
  if footer is not None: sections.append(Nav(footer, cls=footer_cls) if footer_cls else Nav(footer))
708
708
  return Article(*sections, cls=cls, **kwargs)
709
709
 
710
- # %% ../nbs/02_components.ipynb 90
710
+ # %% ../nbs/02_components.ipynb 89
711
711
  #| code-fold: true
712
712
  def Toolbar(*items, cls='', elevate='large', fill=True, **kwargs):
713
713
  """BeerCSS toolbar for action bars with elevation options."""
@@ -717,7 +717,7 @@ def Toolbar(*items, cls='', elevate='large', fill=True, **kwargs):
717
717
  if cls: classes.append(cls)
718
718
  return Nav(*items, cls=' '.join(classes), **kwargs)
719
719
 
720
- # %% ../nbs/02_components.ipynb 93
720
+ # %% ../nbs/02_components.ipynb 92
721
721
  #| code-fold: true
722
722
  def Toast(*c, cls='', position='top', variant='', action=None, dur=5.0, active=False, **kwargs):
723
723
  """BeerCSS snackbar/toast notification with position and variant options."""
@@ -741,7 +741,7 @@ def Snackbar(*c, **kwargs):
741
741
  """Alias for Toast component."""
742
742
  return Toast(*c, **kwargs)
743
743
 
744
- # %% ../nbs/02_components.ipynb 95
744
+ # %% ../nbs/02_components.ipynb 94
745
745
  #| code-fold: true
746
746
  class ContainerT(VEnum):
747
747
  """Container size options (BeerCSS). Most alias to 'responsive'; use 'expand' for full-width."""
@@ -752,7 +752,7 @@ class ContainerT(VEnum):
752
752
  xl = 'responsive'
753
753
  expand = 'responsive max'
754
754
 
755
- # %% ../nbs/02_components.ipynb 97
755
+ # %% ../nbs/02_components.ipynb 96
756
756
  #| code-fold: true
757
757
  def _get_form_config(col: dict) -> dict:
758
758
  """Extract form config from column, with sensible defaults."""
@@ -828,7 +828,7 @@ def FormField(
828
828
  **attrs
829
829
  )
830
830
 
831
- # %% ../nbs/02_components.ipynb 99
831
+ # %% ../nbs/02_components.ipynb 98
832
832
  #| code-fold: true
833
833
  from typing import Callable, Any
834
834
 
@@ -947,7 +947,7 @@ def FormModal(
947
947
  cls="large-width"
948
948
  )
949
949
 
950
- # %% ../nbs/02_components.ipynb 101
950
+ # %% ../nbs/02_components.ipynb 100
951
951
  #| code-fold: true
952
952
  def NavContainer(*li, title=None, brand=None, position='left', close_button=True, cls='active', id=None, **kwargs):
953
953
  """Slide-out navigation drawer with header and close button."""
@@ -1004,7 +1004,7 @@ def BottomNav(*c, cls='bottom', size='s', **kwargs):
1004
1004
  final_cls = f"{cls} {size_cls}".strip()
1005
1005
  return Nav(*c, cls=final_cls, **kwargs)
1006
1006
 
1007
- # %% ../nbs/02_components.ipynb 104
1007
+ # %% ../nbs/02_components.ipynb 103
1008
1008
  #| code-fold: true
1009
1009
  def NavSideBarHeader(*c, cls='', **kwargs):
1010
1010
  """Sidebar header section for menu buttons and branding."""
@@ -1024,7 +1024,7 @@ def NavSideBarContainer(*children, position='left', size='m', cls='', active=Fal
1024
1024
  nav_cls = f"{base_cls} {cls}".strip()
1025
1025
  return Nav(*children, cls=nav_cls, **kwargs)
1026
1026
 
1027
- # %% ../nbs/02_components.ipynb 106
1027
+ # %% ../nbs/02_components.ipynb 105
1028
1028
  #| code-fold: true
1029
1029
  def Layout(*content, sidebar=None, sidebar_links=None, nav_bar=None, container_size=ContainerT.expand,
1030
1030
  main_bg='surface', sidebar_id='app-sidebar', cls='', **kwargs):
@@ -1069,7 +1069,7 @@ def Layout(*content, sidebar=None, sidebar_links=None, nav_bar=None, container_s
1069
1069
  final_cls = f"surface-container {cls}".strip() if cls else "surface-container"
1070
1070
  return Div(*layout_children, cls=final_cls, **kwargs)
1071
1071
 
1072
- # %% ../nbs/02_components.ipynb 110
1072
+ # %% ../nbs/02_components.ipynb 109
1073
1073
  #| code-fold: true
1074
1074
  class TextT(VEnum):
1075
1075
  """Text styles using BeerCSS typography classes."""
@@ -1101,7 +1101,7 @@ class TextPresets(VEnum):
1101
1101
  primary_link = 'link primary-text'
1102
1102
  muted_link = 'link secondary-text'
1103
1103
 
1104
- # %% ../nbs/02_components.ipynb 111
1104
+ # %% ../nbs/02_components.ipynb 110
1105
1105
  #| code-fold: true
1106
1106
  def CodeSpan(*c, cls=(), **kwargs):
1107
1107
  """Inline code snippet."""
@@ -1157,7 +1157,7 @@ def Sup(*c, cls=(), **kwargs):
1157
1157
  cls_str = stringify(cls) if cls else None
1158
1158
  return fc.Sup(*c, cls=cls_str, **kwargs) if cls_str else fc.Sup(*c, **kwargs)
1159
1159
 
1160
- # %% ../nbs/02_components.ipynb 113
1160
+ # %% ../nbs/02_components.ipynb 112
1161
1161
  #| code-fold: true
1162
1162
  def FAQItem(question: str, answer: str, question_cls: str = '', answer_cls: str = ''):
1163
1163
  """Collapsible FAQ item using details/summary.
@@ -1175,7 +1175,7 @@ def FAQItem(question: str, answer: str, question_cls: str = '', answer_cls: str
1175
1175
  Summary(Article(Nav(Div(question, cls=f"max bold {question_cls}".strip()), I("expand_more")), cls="round surface-variant border no-elevate")),
1176
1176
  Article(P(answer, cls=f"secondary-text {answer_cls}".strip()), cls="round border padding"))
1177
1177
 
1178
- # %% ../nbs/02_components.ipynb 117
1178
+ # %% ../nbs/02_components.ipynb 116
1179
1179
  #| code-fold: true
1180
1180
  def CookiesBanner(message='We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies.',
1181
1181
  accept_text='Accept', decline_text='Decline', settings_text=None, policy_link='/cookies', policy_text='Learn more',
fh_matui/datatable.py CHANGED
@@ -1,11 +1,11 @@
1
1
  """Data table with pagination, search, sorting, and inline actions"""
2
2
 
3
- # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/05_table.ipynb.
3
+ # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/05_datatable.ipynb.
4
4
 
5
5
  # %% auto 0
6
6
  __all__ = ['PAGE_SIZES', 'table_state_from_request', 'DataTable', 'DataTableResource']
7
7
 
8
- # %% ../nbs/05_table.ipynb 2
8
+ # %% ../nbs/05_datatable.ipynb 2
9
9
  from fastcore.utils import *
10
10
  from fasthtml.common import *
11
11
  from fasthtml.jupyter import *
@@ -17,7 +17,7 @@ from .core import *
17
17
  from nbdev.showdoc import show_doc
18
18
  from .components import *
19
19
 
20
- # %% ../nbs/05_table.ipynb 6
20
+ # %% ../nbs/05_datatable.ipynb 6
21
21
  #| code-fold: true
22
22
  from math import ceil
23
23
  from urllib.parse import urlencode
@@ -288,7 +288,7 @@ def DataTable(
288
288
 
289
289
  return Div(card, Div(id=feedback_id), id=container_id)
290
290
 
291
- # %% ../nbs/05_table.ipynb 8
291
+ # %% ../nbs/05_datatable.ipynb 8
292
292
  from typing import Callable, Optional, Any, Union
293
293
  from dataclasses import asdict, is_dataclass
294
294
  from datetime import datetime
fh_matui/web_pages.py CHANGED
@@ -3,30 +3,97 @@
3
3
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/04_web_pages.ipynb.
4
4
 
5
5
  # %% auto 0
6
- __all__ = ['SECTION_STYLE', 'SECTION_MARGIN', 'STANDARD_FOOTER_COLUMNS', 'FeatureShowcase', 'FeaturesGrid', 'PricingSection',
7
- 'FAQSection', 'PageFooter', 'LandingNavBar', 'LandingPageSimple', 'MarkdownSection', 'ContentPage']
6
+ __all__ = ['SECTION_STYLE', 'SECTION_MARGIN', 'STANDARD_FOOTER_COLUMNS', 'HeroSection', 'FeatureShowcase', 'FeaturesGrid',
7
+ 'PricingSection', 'FAQSection', 'PageFooter', 'LandingNavBar', 'LandingPageSimple', 'MarkdownSection',
8
+ 'ContentPage']
8
9
 
9
10
  # %% ../nbs/04_web_pages.ipynb 3
10
11
  import importlib
11
12
  import markdown
12
-
13
-
14
-
15
13
  from .components import *
16
14
  from .core import *
17
15
  from fasthtml.common import *
18
16
  from .app_pages import *
19
17
  from .foundations import *
20
-
21
18
  from fastcore.utils import partial
22
19
  from fasthtml.common import *
23
20
  from fasthtml.jupyter import FastHTML, fast_app, JupyUvi, HTMX
24
21
  from fastlite import *
25
22
  import fasthtml.components as fc
26
23
  from fasthtml.common import A, Button as FhButton, I, Span
27
- import socket
28
- import time
29
- import subprocess
24
+
25
+
26
+ # %% ../nbs/04_web_pages.ipynb 6
27
+ def HeroSection(
28
+ title: str, # Main hero title
29
+ subtitle: str, # Hero subtitle/description
30
+ primary_cta_text: str, # Primary CTA button text
31
+ primary_cta_href: str, # Primary CTA button href
32
+ secondary_cta_text: str = None, # Secondary CTA button text (optional)
33
+ secondary_cta_href: str = None, # Secondary CTA button href (optional)
34
+ background: str = "primary-container", # BeerCSS background class (without bg- prefix)
35
+ cls: str = "", # Additional classes
36
+ extra_css: str | None = None, # Optional custom CSS (minimal; opt-in)
37
+ extra_js: str | None = None, # Optional custom JS (minimal; opt-in)
38
+ ):
39
+ """Hero section with title, subtitle, and CTA buttons.
40
+
41
+ BeerCSS-first styling. Takes up 75vh by default with gradient overlay.
42
+ Designed for full-width layout - background extends edge-to-edge naturally.
43
+ Content is centered using responsive class internally.
44
+ """
45
+ # Hero styling: 75vh height + gradient overlay
46
+ # No width hacks needed - parent layout uses "max" for full-width
47
+ hero_css = """
48
+ .hero-section {
49
+ min-height: 75vh;
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: center;
53
+ position: relative;
54
+ background: linear-gradient(135deg,
55
+ var(--primary-container) 0%,
56
+ var(--surface-container) 50%,
57
+ var(--secondary-container) 100%);
58
+ }
59
+ .hero-section::before {
60
+ content: '';
61
+ position: absolute;
62
+ inset: 0;
63
+ background: radial-gradient(circle at 20% 80%, var(--primary) 0%, transparent 50%),
64
+ radial-gradient(circle at 80% 20%, var(--secondary) 0%, transparent 50%);
65
+ opacity: 0.1;
66
+ pointer-events: none;
67
+ }
68
+ .hero-content {
69
+ position: relative;
70
+ z-index: 1;
71
+ }
72
+ """
73
+
74
+ hooks = [Style(hero_css)]
75
+ if extra_css:
76
+ hooks.append(Style(extra_css))
77
+ if extra_js:
78
+ hooks.append(Script(extra_js))
79
+
80
+ ctas = [Button(primary_cta_text, href=primary_cta_href, variant="raised")]
81
+ if secondary_cta_text and secondary_cta_href:
82
+ ctas.append(Button(secondary_cta_text, href=secondary_cta_href, variant="outlined"))
83
+
84
+ stack = DivVStacked(
85
+ H1(title, cls="no-margin"),
86
+ P(subtitle, cls="secondary-text large-text"),
87
+ Div(*ctas, cls="row middle-align center-align small-space"),
88
+ cls="center-align large-padding hero-content",
89
+ )
90
+ # Content centered with responsive class
91
+ content = Div(stack, cls="responsive")
92
+ return Section(
93
+ *hooks,
94
+ content,
95
+ cls=f"hero-section {cls}".strip(),
96
+ )
30
97
 
31
98
  # %% ../nbs/04_web_pages.ipynb 10
32
99
  def FeatureShowcase(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fh-matui
3
- Version: 0.9.1
3
+ Version: 0.9.3
4
4
  Summary: material-ui for fasthtml
5
5
  Home-page: https://github.com/abhisheksreesaila/fh-matui
6
6
  Author: abhishek sreesaila
@@ -18,6 +18,9 @@ Classifier: License :: OSI Approved :: Apache Software License
18
18
  Requires-Python: >=3.9
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE
21
+ Requires-Dist: python-fasthtml
22
+ Requires-Dist: fastcore
23
+ Requires-Dist: markdown
21
24
  Provides-Extra: dev
22
25
  Dynamic: author
23
26
  Dynamic: author-email
@@ -29,6 +32,7 @@ Dynamic: keywords
29
32
  Dynamic: license
30
33
  Dynamic: license-file
31
34
  Dynamic: provides-extra
35
+ Dynamic: requires-dist
32
36
  Dynamic: requires-python
33
37
  Dynamic: summary
34
38
 
@@ -140,12 +144,12 @@ fh-matui automatically includes:
140
144
 
141
145
  | Module | Description | Key Components |
142
146
  |--------|-------------|----------------|
143
- | [Foundations](foundations.html) | Base utilities and helper functions | `BeerHeaders`, `display`, styling helpers |
144
- | [Core](core.html) | Theme system and styling | `MatTheme`, color presets, theme configuration |
145
- | [Components](components.html) | UI component library | `Button`, [`Card`](https://abhisheksreesaila.github.io/fh-matui/components.html#card), [`FormField`](https://abhisheksreesaila.github.io/fh-matui/components.html#formfield), [`FormModal`](https://abhisheksreesaila.github.io/fh-matui/components.html#formmodal), [`Grid`](https://abhisheksreesaila.github.io/fh-matui/components.html#grid) |
146
- | [App Pages](app_pages.html) | Application layouts | Navigation, sidebars, full-page layouts |
147
- | [Data Tables](05_table.html) | Data management components | [`DataTable`](https://abhisheksreesaila.github.io/fh-matui/table.html#datatable), [`DataTableResource`](https://abhisheksreesaila.github.io/fh-matui/table.html#datatableresource), CRUD operations |
148
- | [Web Pages](web_pages.html) | Marketing/landing pages | Hero sections, feature grids, testimonials |
147
+ | [Foundations](https://abhisheksreesaila.github.io/fh-matui/foundations.html) | Base utilities and helper functions | `BeerHeaders`, `display`, styling helpers |
148
+ | [Core](https://abhisheksreesaila.github.io/fh-matui/core.html) | Theme system and styling | `MatTheme`, color presets, theme configuration |
149
+ | [Components](https://abhisheksreesaila.github.io/fh-matui/components.html) | UI component library | `Button`, `Card`, `FormField`, `FormModal`, `Grid` |
150
+ | [App Pages](https://abhisheksreesaila.github.io/fh-matui/app_pages.html) | Application layouts | Navigation, sidebars, full-page layouts |
151
+ | [Data Tables](https://abhisheksreesaila.github.io/fh-matui/datatable.html) | Data management components | `DataTable`, `DataTableResource`, CRUD operations |
152
+ | [Web Pages](https://abhisheksreesaila.github.io/fh-matui/web_pages.html) | Marketing/landing pages | Hero sections, feature grids, testimonials |
149
153
 
150
154
  ## 🛠️ Development
151
155
 
@@ -0,0 +1,14 @@
1
+ fh_matui/__init__.py,sha256=5uBZ3sUaocnyIWuJeW9M94Z77vA1kKmwKxiblrnbKlc,23
2
+ fh_matui/_modidx.py,sha256=hLZ_V7aRsAvavJ82m02XyvImfzYB5_DnOce8eKRD3xU,22865
3
+ fh_matui/app_pages.py,sha256=Sn9-tgBpaPNbR-0nZtPLoSCmAWLOGB4UQ88IkFvzBRY,10361
4
+ fh_matui/components.py,sha256=KjdTHzWRXpVWBEIGskW1HfhjPpzRYzi6UA_yRjZyMWM,48254
5
+ fh_matui/core.py,sha256=xtVBN8CtC50ZJ4Iu7o-mUhaA87tWdnz8gBfKRk63Zhs,10680
6
+ fh_matui/datatable.py,sha256=MAEibyjRwYlBLMD9dIIocufuWn84jTvrgRt1XKFAN9U,25506
7
+ fh_matui/foundations.py,sha256=b7PnObJpKN8ZAU9NzCm9xpfnHzFjjAROU7E2YvA_tj4,1820
8
+ fh_matui/web_pages.py,sha256=4mF-jpfVcZTVepfQ-aMGgIUp-nBp0YCkvcdsWhUYeaA,34879
9
+ fh_matui-0.9.3.dist-info/licenses/LICENSE,sha256=xV8xoN4VOL0uw9X8RSs2IMuD_Ss_a9yAbtGNeBWZwnw,11337
10
+ fh_matui-0.9.3.dist-info/METADATA,sha256=KX2VQz5wOPRHaSwtc86l3-p3TTjn-08pjuS7kAHbta8,8431
11
+ fh_matui-0.9.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ fh_matui-0.9.3.dist-info/entry_points.txt,sha256=zn4CR4gNTiAAxbFsCxHAf2tQhtW29_YOffjbUTgeoWI,38
13
+ fh_matui-0.9.3.dist-info/top_level.txt,sha256=l80d5eoA2ZjqtPYwAorLMS5PiHxUxz3zKzxMJ41Xoso,9
14
+ fh_matui-0.9.3.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- fh_matui/__init__.py,sha256=Y6W8oeFa2EC4luE43Qn41YddoEfesw76EJ4Lj0NkhIQ,21
2
- fh_matui/_modidx.py,sha256=GqigyZE6TkLMfflOcgGzo1CjBiSxIY5ez_DyO6qApjQ,22665
3
- fh_matui/app_pages.py,sha256=Sn9-tgBpaPNbR-0nZtPLoSCmAWLOGB4UQ88IkFvzBRY,10361
4
- fh_matui/components.py,sha256=S5rbnPdkGH2rhOpRR007uU7Sof7PAmPIKRDII3fBqb8,48254
5
- fh_matui/core.py,sha256=xtVBN8CtC50ZJ4Iu7o-mUhaA87tWdnz8gBfKRk63Zhs,10680
6
- fh_matui/datatable.py,sha256=G7Gmkj5nNWbcWqZvJtWGUSKQSs8AQAcs57qEpMt1ijo,25490
7
- fh_matui/foundations.py,sha256=b7PnObJpKN8ZAU9NzCm9xpfnHzFjjAROU7E2YvA_tj4,1820
8
- fh_matui/web_pages.py,sha256=PQs_1elTdC1lkx1MNTW4yD_zaAXLtxzKX8JFuIP4Iw0,32130
9
- fh_matui-0.9.1.dist-info/licenses/LICENSE,sha256=xV8xoN4VOL0uw9X8RSs2IMuD_Ss_a9yAbtGNeBWZwnw,11337
10
- fh_matui-0.9.1.dist-info/METADATA,sha256=G-u13Lvhv0mrVWgpee4tEKqWDwml1I4A4CsAlI5nPVc,8486
11
- fh_matui-0.9.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
- fh_matui-0.9.1.dist-info/entry_points.txt,sha256=zn4CR4gNTiAAxbFsCxHAf2tQhtW29_YOffjbUTgeoWI,38
13
- fh_matui-0.9.1.dist-info/top_level.txt,sha256=l80d5eoA2ZjqtPYwAorLMS5PiHxUxz3zKzxMJ41Xoso,9
14
- fh_matui-0.9.1.dist-info/RECORD,,