fh-matui 0.9__py3-none-any.whl → 0.9.2__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.2"
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/web_pages.py CHANGED
@@ -9,24 +9,18 @@ __all__ = ['SECTION_STYLE', 'SECTION_MARGIN', 'STANDARD_FOOTER_COLUMNS', 'Featur
9
9
  # %% ../nbs/04_web_pages.ipynb 3
10
10
  import importlib
11
11
  import markdown
12
-
13
-
14
-
15
12
  from .components import *
16
13
  from .core import *
17
14
  from fasthtml.common import *
18
15
  from .app_pages import *
19
16
  from .foundations import *
20
-
21
17
  from fastcore.utils import partial
22
18
  from fasthtml.common import *
23
19
  from fasthtml.jupyter import FastHTML, fast_app, JupyUvi, HTMX
24
20
  from fastlite import *
25
21
  import fasthtml.components as fc
26
22
  from fasthtml.common import A, Button as FhButton, I, Span
27
- import socket
28
- import time
29
- import subprocess
23
+
30
24
 
31
25
  # %% ../nbs/04_web_pages.ipynb 10
32
26
  def FeatureShowcase(
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.4
2
+ Name: fh-matui
3
+ Version: 0.9.2
4
+ Summary: material-ui for fasthtml
5
+ Home-page: https://github.com/abhisheksreesaila/fh-matui
6
+ Author: abhishek sreesaila
7
+ Author-email: abhishek.sreesaila@gmail.com
8
+ License: Apache Software License 2.0
9
+ Keywords: nbdev jupyter notebook python
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Natural Language :: English
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: License :: OSI Approved :: Apache Software License
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: python-fasthtml
22
+ Requires-Dist: fastcore
23
+ Requires-Dist: markdown
24
+ Provides-Extra: dev
25
+ Dynamic: author
26
+ Dynamic: author-email
27
+ Dynamic: classifier
28
+ Dynamic: description
29
+ Dynamic: description-content-type
30
+ Dynamic: home-page
31
+ Dynamic: keywords
32
+ Dynamic: license
33
+ Dynamic: license-file
34
+ Dynamic: provides-extra
35
+ Dynamic: requires-dist
36
+ Dynamic: requires-python
37
+ Dynamic: summary
38
+
39
+
40
+ ## What is fh-matui?
41
+
42
+ **fh-matui** is a Python library that brings Google's Material Design to [FastHTML](https://fastht.ml/) applications. It provides a comprehensive set of pre-built UI components that integrate seamlessly with FastHTML's hypermedia-driven architecture.
43
+
44
+ Built on top of [BeerCSS](https://www.beercss.com/) (a lightweight Material Design 3 CSS framework), fh-matui enables you to create modern, responsive web interfaces entirely in Python — no JavaScript required.
45
+
46
+ ## ✨ Key Features
47
+
48
+ | Feature | Description |
49
+ |---------|-------------|
50
+ | 🎨 **Material Design 3** | Modern, beautiful components following Google's latest design language |
51
+ | ⚡ **Zero JavaScript** | Build interactive UIs entirely in Python with FastHTML |
52
+ | 📱 **Responsive** | Mobile-first design with automatic breakpoint handling |
53
+ | 🌙 **Dark Mode** | Built-in light/dark theme support with 20+ color schemes |
54
+ | 🧩 **Composable** | Chainable styling APIs inspired by MonsterUI |
55
+ | 📊 **Data Tables** | Full-featured tables with pagination, search, sorting, and CRUD |
56
+ | 🔧 **nbdev-powered** | Literate programming with documentation built from notebooks |
57
+
58
+ ## 🏗️ Architecture
59
+
60
+ ```
61
+ ┌─────────────────────────────────────────────────────────────┐
62
+ │ fh-matui │
63
+ ├─────────────────────────────────────────────────────────────┤
64
+ │ Foundations │ Core styling utilities, helpers, enums │
65
+ │ Core │ Theme system, MatTheme color presets │
66
+ │ Components │ Buttons, Cards, Modals, Forms, Tables │
67
+ │ App Pages │ Full-page layouts, navigation patterns │
68
+ │ Data Tables │ DataTable, DataTableResource for CRUD │
69
+ │ Web Pages │ Landing pages, marketing components │
70
+ ├─────────────────────────────────────────────────────────────┤
71
+ │ BeerCSS │ Material Design 3 CSS framework │
72
+ │ FastHTML │ Python hypermedia web framework │
73
+ └─────────────────────────────────────────────────────────────┘
74
+ ```
75
+
76
+ ## 🎨 Available Themes
77
+
78
+ fh-matui includes 15+ pre-configured Material Design 3 color themes:
79
+
80
+ | Theme | Preview | Theme | Preview |
81
+ |-------|---------|-------|---------|
82
+ | `MatTheme.red` | 🔴 | `MatTheme.pink` | 🩷 |
83
+ | `MatTheme.purple` | 🟣 | `MatTheme.deepPurple` | 💜 |
84
+ | `MatTheme.indigo` | 🔵 | `MatTheme.blue` | 💙 |
85
+ | `MatTheme.lightBlue` | 🩵 | `MatTheme.cyan` | 🌊 |
86
+ | `MatTheme.teal` | 🩶 | `MatTheme.green` | 💚 |
87
+ | `MatTheme.lightGreen` | 🍀 | `MatTheme.lime` | 💛 |
88
+ | `MatTheme.yellow` | 🌟 | `MatTheme.amber` | 🧡 |
89
+ | `MatTheme.orange` | 🟠 | `MatTheme.deepOrange` | 🔶 |
90
+
91
+ **Usage:**
92
+ ```python
93
+ # Choose your theme
94
+ app, rt = fast_app(hdrs=[MatTheme.deepPurple.headers()])
95
+ ```
96
+
97
+ ## 🚀 Quick Start
98
+
99
+ Here's a minimal example to get you started:
100
+
101
+ ```python
102
+ from fasthtml.common import *
103
+ from fh_matui.core import MatTheme
104
+ from fh_matui.components import Button, Card, FormField
105
+
106
+ # Create a themed FastHTML app
107
+ app, rt = fast_app(hdrs=[MatTheme.indigo.headers()])
108
+
109
+ @rt('/')
110
+ def home():
111
+ return Div(
112
+ Card(
113
+ H3("Welcome to fh-matui!"),
114
+ P("Build beautiful Material Design apps with Python."),
115
+ FormField("email", label="Email", type="email"),
116
+ Button("Get Started", cls="primary"),
117
+ ),
118
+ cls="padding"
119
+ )
120
+
121
+ serve()
122
+ ```
123
+
124
+ ## 📦 Installation
125
+
126
+ ```bash
127
+ pip install fh-matui
128
+ ```
129
+
130
+ ### Dependencies
131
+
132
+ fh-matui automatically includes:
133
+ - **python-fasthtml** - The core FastHTML framework
134
+ - **BeerCSS** - Loaded via CDN for Material Design 3 styling
135
+
136
+ ### What This Code Does
137
+
138
+ 1. **`MatTheme.indigo.headers()`** - Loads BeerCSS with the indigo color scheme
139
+ 2. **[`Card`](https://abhisheksreesaila.github.io/fh-matui/components.html#card)** - Creates a Material Design card component with elevation
140
+ 3. **[`FormField`](https://abhisheksreesaila.github.io/fh-matui/components.html#formfield)** - Generates a styled input with floating label
141
+ 4. **`Button`** - Renders a Material Design button with ripple effects
142
+
143
+ ## 📚 Module Reference
144
+
145
+ | Module | Description | Key Components |
146
+ |--------|-------------|----------------|
147
+ | [Foundations](foundations.html) | Base utilities and helper functions | `BeerHeaders`, `display`, styling helpers |
148
+ | [Core](core.html) | Theme system and styling | `MatTheme`, color presets, theme configuration |
149
+ | [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) |
150
+ | [App Pages](app_pages.html) | Application layouts | Navigation, sidebars, full-page layouts |
151
+ | [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 |
152
+ | [Web Pages](web_pages.html) | Marketing/landing pages | Hero sections, feature grids, testimonials |
153
+
154
+ ## 🛠️ Development
155
+
156
+ ### Install in Development Mode
157
+
158
+ ```bash
159
+ # Clone the repository
160
+ git clone https://github.com/user/fh-matui.git
161
+ cd fh-matui
162
+
163
+ # Install in editable mode
164
+ pip install -e .
165
+
166
+ # Make changes under nbs/ directory, then compile
167
+ nbdev_prepare
168
+ ```
169
+
170
+ ## 🤝 Why fh-matui?
171
+
172
+ | Challenge | fh-matui Solution |
173
+ |-----------|-------------------|
174
+ | **CSS complexity** | Pre-built Material Design 3 components via BeerCSS |
175
+ | **JavaScript fatigue** | FastHTML handles interactivity declaratively |
176
+ | **Component consistency** | Unified API across all components |
177
+ | **Dark mode support** | Built-in with automatic system preference detection |
178
+ | **Responsive design** | Mobile-first grid system and responsive utilities |
179
+ | **Form handling** | [`FormField`](https://abhisheksreesaila.github.io/fh-matui/components.html#formfield), [`FormGrid`](https://abhisheksreesaila.github.io/fh-matui/components.html#formgrid), [`FormModal`](https://abhisheksreesaila.github.io/fh-matui/components.html#formmodal) for rapid form building |
180
+ | **Data management** | [`DataTable`](https://abhisheksreesaila.github.io/fh-matui/table.html#datatable) and [`DataTableResource`](https://abhisheksreesaila.github.io/fh-matui/table.html#datatableresource) for CRUD operations |
181
+
182
+ ## 📄 License
183
+
184
+ This project is licensed under the Apache 2.0 License - see the [LICENSE](https://github.com/user/fh-matui/blob/main/LICENSE) file for details.
185
+
186
+ ---
187
+
188
+ **Built with ❤️ using FastHTML and nbdev**
@@ -0,0 +1,14 @@
1
+ fh_matui/__init__.py,sha256=I3ASgj0LYAmGGQhqxkAYEEiiLOpQ1UAZGOd0bJAXSRw,23
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=KjdTHzWRXpVWBEIGskW1HfhjPpzRYzi6UA_yRjZyMWM,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=9YkzgTcBuIG3SKVzAVyDRqmttINAu5bySOkCpPg-e18,32077
9
+ fh_matui-0.9.2.dist-info/licenses/LICENSE,sha256=xV8xoN4VOL0uw9X8RSs2IMuD_Ss_a9yAbtGNeBWZwnw,11337
10
+ fh_matui-0.9.2.dist-info/METADATA,sha256=kcJvlvnrzx8bqaKD1yjuvU8OjNc9nF_zWYuW3LZXNjE,8592
11
+ fh_matui-0.9.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ fh_matui-0.9.2.dist-info/entry_points.txt,sha256=zn4CR4gNTiAAxbFsCxHAf2tQhtW29_YOffjbUTgeoWI,38
13
+ fh_matui-0.9.2.dist-info/top_level.txt,sha256=l80d5eoA2ZjqtPYwAorLMS5PiHxUxz3zKzxMJ41Xoso,9
14
+ fh_matui-0.9.2.dist-info/RECORD,,
@@ -1,101 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: fh-matui
3
- Version: 0.9
4
- Summary: material-ui for fasthtml
5
- Home-page: https://github.com/abhisheksreesaila/fh-matui
6
- Author: abhishek sreesaila
7
- Author-email: abhishek.sreesaila@gmail.com
8
- License: Apache Software License 2.0
9
- Keywords: nbdev jupyter notebook python
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Intended Audience :: Developers
12
- Classifier: Natural Language :: English
13
- Classifier: Programming Language :: Python :: 3.9
14
- Classifier: Programming Language :: Python :: 3.10
15
- Classifier: Programming Language :: Python :: 3.11
16
- Classifier: Programming Language :: Python :: 3.12
17
- Classifier: License :: OSI Approved :: Apache Software License
18
- Requires-Python: >=3.9
19
- Description-Content-Type: text/markdown
20
- License-File: LICENSE
21
- Provides-Extra: dev
22
- Dynamic: author
23
- Dynamic: author-email
24
- Dynamic: classifier
25
- Dynamic: description
26
- Dynamic: description-content-type
27
- Dynamic: home-page
28
- Dynamic: keywords
29
- Dynamic: license
30
- Dynamic: license-file
31
- Dynamic: provides-extra
32
- Dynamic: requires-python
33
- Dynamic: summary
34
-
35
- # fh-matui
36
-
37
-
38
- <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
39
-
40
- This file will become your README and also the index of your
41
- documentation.
42
-
43
- ## Developer Guide
44
-
45
- If you are new to using `nbdev` here are some useful pointers to get you
46
- started.
47
-
48
- ### Install fh_matui in Development mode
49
-
50
- ``` sh
51
- # make sure fh_matui package is installed in development mode
52
- $ pip install -e .
53
-
54
- # make changes under nbs/ directory
55
- # ...
56
-
57
- # compile to have changes apply to fh_matui
58
- $ nbdev_prepare
59
- ```
60
-
61
- ## Usage
62
-
63
- ### Installation
64
-
65
- Install latest from the GitHub
66
- [repository](https://github.com/abhishek%20sreesaila/fh-matui):
67
-
68
- ``` sh
69
- $ pip install git+https://github.com/abhishek sreesaila/fh-matui.git
70
- ```
71
-
72
- or from [conda](https://anaconda.org/abhishek%20sreesaila/fh-matui)
73
-
74
- ``` sh
75
- $ conda install -c abhishek sreesaila fh_matui
76
- ```
77
-
78
- or from [pypi](https://pypi.org/project/fh-matui/)
79
-
80
- ``` sh
81
- $ pip install fh_matui
82
- ```
83
-
84
- ### Documentation
85
-
86
- Documentation can be found hosted on this GitHub
87
- [repository](https://github.com/abhishek%20sreesaila/fh-matui)’s
88
- [pages](https://abhishek%20sreesaila.github.io/fh-matui/). Additionally
89
- you can find package manager specific guidelines on
90
- [conda](https://anaconda.org/abhishek%20sreesaila/fh-matui) and
91
- [pypi](https://pypi.org/project/fh-matui/) respectively.
92
-
93
- ## How to use
94
-
95
- Fill me in please! Don’t forget code examples:
96
-
97
- ``` python
98
- 1+1
99
- ```
100
-
101
- 2
@@ -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.dist-info/licenses/LICENSE,sha256=xV8xoN4VOL0uw9X8RSs2IMuD_Ss_a9yAbtGNeBWZwnw,11337
10
- fh_matui-0.9.dist-info/METADATA,sha256=x84AWDfYkDB_rOjLgbJtkKdb4NFif1E5lKOih5I0eN8,2528
11
- fh_matui-0.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
- fh_matui-0.9.dist-info/entry_points.txt,sha256=zn4CR4gNTiAAxbFsCxHAf2tQhtW29_YOffjbUTgeoWI,38
13
- fh_matui-0.9.dist-info/top_level.txt,sha256=l80d5eoA2ZjqtPYwAorLMS5PiHxUxz3zKzxMJ41Xoso,9
14
- fh_matui-0.9.dist-info/RECORD,,