AItool commited on
Commit
d467ea7
·
verified ·
1 Parent(s): c645376

Upload 81 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +2 -0
  2. MonsterUI/.cursorrules +1 -0
  3. MonsterUI/.gitattributes +1 -0
  4. MonsterUI/.gitconfig +11 -0
  5. MonsterUI/.gitignore +167 -0
  6. MonsterUI/CHANGELOG.bak +222 -0
  7. MonsterUI/CHANGELOG.md +229 -0
  8. MonsterUI/CONTRIBUTING.md +27 -0
  9. MonsterUI/LICENSE +201 -0
  10. MonsterUI/MANIFEST.in +5 -0
  11. MonsterUI/README.md +99 -0
  12. MonsterUI/__pycache__/testnavbar.cpython-312.pyc +0 -0
  13. MonsterUI/docs/.plash +1 -0
  14. MonsterUI/docs/MonsterUI.jpg +3 -0
  15. MonsterUI/docs/api_reference/api_reference.py +1211 -0
  16. MonsterUI/docs/api_reference/logo.svg +32 -0
  17. MonsterUI/docs/apilist.txt +520 -0
  18. MonsterUI/docs/cf_addns.py +18 -0
  19. MonsterUI/docs/createllms.sh +48 -0
  20. MonsterUI/docs/custom_theme.css +56 -0
  21. MonsterUI/docs/data_/mail.json +206 -0
  22. MonsterUI/docs/data_/status_list.json +1 -0
  23. MonsterUI/docs/data_/statuses.json +22 -0
  24. MonsterUI/docs/examples/auth.py +40 -0
  25. MonsterUI/docs/examples/cards.py +141 -0
  26. MonsterUI/docs/examples/dashboard.py +106 -0
  27. MonsterUI/docs/examples/data/mail.json +206 -0
  28. MonsterUI/docs/examples/data/status_list.json +1 -0
  29. MonsterUI/docs/examples/data/statuses.json +22 -0
  30. MonsterUI/docs/examples/forms.py +150 -0
  31. MonsterUI/docs/examples/mail.py +111 -0
  32. MonsterUI/docs/examples/music.py +138 -0
  33. MonsterUI/docs/examples/playground.py +69 -0
  34. MonsterUI/docs/examples/scrollspy.py +125 -0
  35. MonsterUI/docs/examples/tasks.py +118 -0
  36. MonsterUI/docs/examples/ticket.py +95 -0
  37. MonsterUI/docs/favicon.ico +3 -0
  38. MonsterUI/docs/getting_started/GettingStarted.md +98 -0
  39. MonsterUI/docs/getting_started/StylingRulesOfThumb.py +110 -0
  40. MonsterUI/docs/getting_started/app_product_gallery.py +96 -0
  41. MonsterUI/docs/guides/Layout.ipynb +591 -0
  42. MonsterUI/docs/guides/Spacing.ipynb +482 -0
  43. MonsterUI/docs/htmxindicator.py +25 -0
  44. MonsterUI/docs/llms-ctx-full.txt +0 -0
  45. MonsterUI/docs/llms-ctx.txt +1603 -0
  46. MonsterUI/docs/llms.txt +44 -0
  47. MonsterUI/docs/main.py +266 -0
  48. MonsterUI/docs/requirements.txt +13 -0
  49. MonsterUI/docs/updatellms.sh +5 -0
  50. MonsterUI/docs/utils.py +60 -0
.gitattributes CHANGED
@@ -35,3 +35,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  MonsterUI/content/MonsterUI/docs/favicon.ico filter=lfs diff=lfs merge=lfs -text
37
  MonsterUI/content/MonsterUI/docs/MonsterUI.jpg filter=lfs diff=lfs merge=lfs -text
 
 
 
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  MonsterUI/content/MonsterUI/docs/favicon.ico filter=lfs diff=lfs merge=lfs -text
37
  MonsterUI/content/MonsterUI/docs/MonsterUI.jpg filter=lfs diff=lfs merge=lfs -text
38
+ MonsterUI/docs/favicon.ico filter=lfs diff=lfs merge=lfs -text
39
+ MonsterUI/docs/MonsterUI.jpg filter=lfs diff=lfs merge=lfs -text
MonsterUI/.cursorrules ADDED
@@ -0,0 +1 @@
 
 
1
+ I am trying to make the python code as consistent with tailwind as possible. For example `large` should be abbreviated `lg` like in tailwind.
MonsterUI/.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ *.ipynb merge=nbdev-merge
MonsterUI/.gitconfig ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Generated by nbdev_install_hooks
2
+ #
3
+ # If you need to disable this instrumentation do:
4
+ # git config --local --unset include.path
5
+ #
6
+ # To restore:
7
+ # git config --local include.path ../.gitconfig
8
+ #
9
+ [merge "nbdev-merge"]
10
+ name = resolve conflicts with nbdev_fix
11
+ driver = nbdev_merge %O %A %B %P
MonsterUI/.gitignore ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ tags
2
+ .sesskey
3
+ docs/static
4
+ # Byte-compiled / optimized / DLL files
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+ _docs/*
9
+ _proc/*
10
+ # C extensions
11
+ *.so
12
+
13
+ # Distribution / packaging
14
+ .Python
15
+ build/
16
+ develop-eggs/
17
+ dist/
18
+ downloads/
19
+ eggs/
20
+ .eggs/
21
+ lib/
22
+ lib64/
23
+ parts/
24
+ sdist/
25
+ var/
26
+ wheels/
27
+ share/python-wheels/
28
+ *.egg-info/
29
+ .installed.cfg
30
+ *.egg
31
+ MANIFEST
32
+
33
+ # PyInstaller
34
+ # Usually these files are written by a python script from a template
35
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
36
+ *.manifest
37
+ *.spec
38
+
39
+ # Installer logs
40
+ pip-log.txt
41
+ pip-delete-this-directory.txt
42
+
43
+ # Unit test / coverage reports
44
+ htmlcov/
45
+ .tox/
46
+ .nox/
47
+ .coverage
48
+ .coverage.*
49
+ .cache
50
+ nosetests.xml
51
+ coverage.xml
52
+ *.cover
53
+ *.py,cover
54
+ .hypothesis/
55
+ .pytest_cache/
56
+ cover/
57
+
58
+ # Translations
59
+ *.mo
60
+ *.pot
61
+
62
+ # Django stuff:
63
+ *.log
64
+ local_settings.py
65
+ db.sqlite3
66
+ db.sqlite3-journal
67
+
68
+ # Flask stuff:
69
+ instance/
70
+ .webassets-cache
71
+
72
+ # Scrapy stuff:
73
+ .scrapy
74
+
75
+ # Sphinx documentation
76
+ docs/_build/
77
+
78
+ # PyBuilder
79
+ .pybuilder/
80
+ target/
81
+
82
+ # Jupyter Notebook
83
+ .ipynb_checkpoints
84
+
85
+ # IPython
86
+ profile_default/
87
+ ipython_config.py
88
+
89
+ # pyenv
90
+ # For a library or package, you might want to ignore these files since the code is
91
+ # intended to run in multiple environments; otherwise, check them in:
92
+ # .python-version
93
+
94
+ # pipenv
95
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
96
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
97
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
98
+ # install all needed dependencies.
99
+ #Pipfile.lock
100
+
101
+ # poetry
102
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
103
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
104
+ # commonly ignored for libraries.
105
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
106
+ #poetry.lock
107
+
108
+ # pdm
109
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
110
+ #pdm.lock
111
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
112
+ # in version control.
113
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
114
+ .pdm.toml
115
+ .pdm-python
116
+ .pdm-build/
117
+
118
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
119
+ __pypackages__/
120
+
121
+ # Celery stuff
122
+ celerybeat-schedule
123
+ celerybeat.pid
124
+
125
+ # SageMath parsed files
126
+ *.sage.py
127
+
128
+ # Environments
129
+ .env
130
+ .venv
131
+ env/
132
+ venv/
133
+ ENV/
134
+ env.bak/
135
+ venv.bak/
136
+ uv.lock
137
+
138
+ # Spyder project settings
139
+ .spyderproject
140
+ .spyproject
141
+
142
+ # Rope project settings
143
+ .ropeproject
144
+
145
+ # mkdocs documentation
146
+ /site
147
+
148
+ # mypy
149
+ .mypy_cache/
150
+ .dmypy.json
151
+ dmypy.json
152
+
153
+ # Pyre type checker
154
+ .pyre/
155
+
156
+ # pytype static type analyzer
157
+ .pytype/
158
+
159
+ # Cython debug symbols
160
+ cython_debug/
161
+
162
+ # PyCharm
163
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
164
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
165
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
166
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
167
+ .idea/
MonsterUI/CHANGELOG.bak ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Release notes
2
+
3
+ <!-- do not remove -->
4
+
5
+ ## 1.0.28
6
+
7
+ ### New Features
8
+
9
+ - allow optional renderer ([#134](https://github.com/AnswerDotAI/MonsterUI/pull/134))
10
+
11
+ ### Bugs Squashed
12
+
13
+ - `render_md` doesn't render images with data uris when `img_dir` is set ([#132](https://github.com/AnswerDotAI/MonsterUI/issues/132))
14
+
15
+
16
+ ## 1.0.26
17
+
18
+ ### Bugs Squashed
19
+
20
+ - fix `render_md` non http/s urls ([#133](https://github.com/AnswerDotAI/MonsterUI/pull/133)), thanks to [@comhar](https://github.com/comhar)
21
+
22
+
23
+ ## 1.0.25
24
+
25
+ ### Bugs Squashed
26
+
27
+ - remove modal on close ([#130](https://github.com/AnswerDotAI/MonsterUI/pull/130)), thanks to [@comhar](https://github.com/comhar)
28
+ - Buttons not working in Modal added to the DOM by HTMX. ([#126](https://github.com/AnswerDotAI/MonsterUI/issues/126))
29
+
30
+
31
+ ## 1.0.24
32
+
33
+ ### New Features
34
+
35
+ - use uikit to initialise and open modals inserted with htmx ([#127](https://github.com/AnswerDotAI/MonsterUI/pull/127)), thanks to [@comhar](https://github.com/comhar)
36
+
37
+
38
+ ## 1.0.23
39
+
40
+ ### Bugs Squashed
41
+
42
+ - fragment md parsing does not work ([#124](https://github.com/AnswerDotAI/MonsterUI/issues/124))
43
+ - llms.txt showing "internal server" errors ([#122](https://github.com/AnswerDotAI/MonsterUI/issues/122))
44
+
45
+
46
+ ## 1.0.22
47
+
48
+ - Create custom themes
49
+
50
+ ### Bugs Squashed
51
+
52
+ - Unicode strings with encoding declaration are not supported ([#123](https://github.com/AnswerDotAI/MonsterUI/issues/123))
53
+ - Update DropDownNavContainer class to remove unnecessary width class ([#114](https://github.com/AnswerDotAI/MonsterUI/pull/114)), thanks to [@ndendic](https://github.com/ndendic)
54
+ - fix font weight ordering ([#113](https://github.com/AnswerDotAI/MonsterUI/pull/113)), thanks to [@comhar](https://github.com/comhar)
55
+ - FieldSet inputs in Form are misaligned when monsterui is active ([#87](https://github.com/AnswerDotAI/MonsterUI/issues/87))
56
+
57
+
58
+ ## 1.0.21
59
+
60
+ ### New Features
61
+
62
+ - The new `ApexChart` component can create line charts, pie charts and [more](https://monsterui.answer.ai/api_ref/docs_charts). ([#110](https://github.com/AnswerDotAI/MonsterUI/pull/110)), thanks to [@ndendic](https://github.com/ndendic)
63
+ - Toasts now disappear automatically after 5 seconds. You can adjust the duration by using the `dur` field (e.g. `Toast('My Toast', dur=10.0)`). ([#109](https://github.com/AnswerDotAI/MonsterUI/pull/109)), thanks to [@comhar](https://github.com/comhar)
64
+
65
+ ### Breaking Change
66
+
67
+ - Katex is no longer included in the default headers. To include it set `katex=True` when calling `.headers`. (i.e. `Theme.slate.headers(katex=True)`). ([#105](https://github.com/AnswerDotAI/MonsterUI/pull/105)), thanks to [@comhar](https://github.com/comhar)
68
+
69
+
70
+ ## 1.0.20
71
+
72
+ ### New Features
73
+
74
+ - Add `icon` header param to optionally not bring in icons js lib ([#99](https://github.com/AnswerDotAI/MonsterUI/issues/99))
75
+
76
+ ### Bugs Squashed
77
+
78
+ - added fh. to unqid ([#98](https://github.com/AnswerDotAI/MonsterUI/pull/98)), thanks to [@MorsCerta-crypto](https://github.com/MorsCerta-crypto)
79
+
80
+
81
+ ## 1.0.19
82
+
83
+ ### New Features
84
+
85
+ - Add accordion component ([#94](https://github.com/AnswerDotAI/MonsterUI/pull/94)), thanks to [@MichlF](https://github.com/MichlF)
86
+ - Fix theme logic ([#93](https://github.com/AnswerDotAI/MonsterUI/pull/93)), thanks to [@curtis-allan](https://github.com/curtis-allan)
87
+
88
+
89
+ ## 1.0.18
90
+
91
+ - Hotfix accidental deletion of label select :(
92
+
93
+
94
+ ## 1.0.16
95
+
96
+ ### Bugs Squashed
97
+
98
+ - Select not properly checking presence of hx-trigger
99
+
100
+ ## 1.0.14
101
+
102
+ ### New Features
103
+
104
+ - Move CDN's to jsdelivr ([#88](https://github.com/AnswerDotAI/MonsterUI/pull/88)), thanks to [@curtis-allan](https://github.com/curtis-allan)
105
+
106
+ ### Bugs Squashed
107
+
108
+ - Select htmx compatibility bug
109
+ - SVG Path Name Collision Issue in MonsterUI ([#85](https://github.com/AnswerDotAI/MonsterUI/issues/85))
110
+
111
+
112
+ ## 1.0.13
113
+
114
+ ### Bugs Squashed
115
+
116
+ - LabelCheckboxX ignores id set manually ([#80](https://github.com/AnswerDotAI/MonsterUI/issues/80))
117
+ - Select sending multiple values to HTMX
118
+
119
+
120
+ ## 1.0.10
121
+
122
+ ### New Features
123
+
124
+ - Cusom Themes support in ThemePicker ([#71](https://github.com/AnswerDotAI/MonsterUI/pull/71)), thanks to [@ndendic](https://github.com/ndendic)
125
+
126
+
127
+ ## 1.0.8
128
+
129
+ - Add lightbox and Insertable select
130
+
131
+ ## 1.0.7
132
+
133
+ ### New Features
134
+
135
+ - Add select kwargs to Select and LabelSelect ([#70](https://github.com/AnswerDotAI/MonsterUI/issues/70))
136
+
137
+ ### Bugs Squashed
138
+
139
+ - Update component classes to align with Franken UI v2.0 ([#67](https://github.com/AnswerDotAI/MonsterUI/pull/67)), thanks to [@Zaseem-BIsquared](https://github.com/Zaseem-BIsquared)
140
+ - Updated ContainerT, CardT, and TableT class names to match the documented patterns from Franken UI v2.0 docs
141
+
142
+ ## 1.0.6
143
+
144
+
145
+ ### Bugs Squashed
146
+
147
+ - Update component classes to align with Franken UI v2.0 ([#67](https://github.com/AnswerDotAI/MonsterUI/pull/67)), thanks to [@Zaseem-BIsquared](https://github.com/Zaseem-BIsquared)
148
+
149
+
150
+ ## 1.0.5
151
+
152
+ - Add Center component
153
+
154
+ ## 1.0.4
155
+
156
+ ### New Features
157
+
158
+ - Bug fix to correct theming conflict in theme initialization
159
+
160
+
161
+ ## 1.0.2
162
+
163
+ - Bug fix to add dark mode theme selector to TW config, thanks to [@curtis-allan](https://github.com/curtis-allan)
164
+
165
+ ## 1.0.1
166
+
167
+ - Theme bug fix not allowing theme changes to stick, thanks to [@zaseem-bisquared](https://github.com/Zaseem-BIsquared)
168
+ - Documentation bug fix on tutorial app, thanks to [@decherd](https://github.com/decherd)
169
+
170
+
171
+ ## 1.0.0
172
+
173
+ ### New Features
174
+
175
+ - Migrated to use FrankenUI version 2.0 version
176
+
177
+ - Brand new simplified NavBar api, including enhanced sticky and scrollspy options, thanks to [@ohmeow](https://github.com/ohmeow) and [@curtis-allan](https://github.com/curtis-allan)
178
+
179
+ - Latex rendering enabled via katex ([#58](https://github.com/AnswerDotAI/MonsterUI/pull/58)), thanks to [@algal](https://github.com/algal)
180
+
181
+ - Add API References and Guides to llms.txt ([#54](https://github.com/AnswerDotAI/MonsterUI/issues/54))
182
+
183
+ - New Range component, which includes min/max range
184
+
185
+ - New center component thanks to inspiration from Carson of HTMX ([#52](https://github.com/AnswerDotAI/MonsterUI/issues/52))
186
+
187
+ - Better Theme Picker ([#51](https://github.com/AnswerDotAI/MonsterUI/issues/51))
188
+
189
+ - Upload Zone and Upload Button Components added ([#50](https://github.com/AnswerDotAI/MonsterUI/issues/50))
190
+
191
+ ### Bugs Squashed
192
+
193
+ - fix: correct PaddingT class naming for padding variants ([#55](https://github.com/AnswerDotAI/MonsterUI/pull/55)), thanks to [@Zaseem-BIsquared](https://github.com/Zaseem-BIsquared)
194
+
195
+
196
+ ## 0.0.34
197
+
198
+
199
+ ### Bugs Squashed
200
+
201
+ - Table markdown rendering bug fix ([#46](https://github.com/AnswerDotAI/MonsterUI/issues/46))
202
+
203
+
204
+ ## 0.0.33
205
+
206
+ ### New Features
207
+
208
+ - Add subtitle function for common semantic styling option ([#44](https://github.com/AnswerDotAI/MonsterUI/pull/44))
209
+
210
+ - Add semantic text styling to docs examples ([#42](https://github.com/AnswerDotAI/MonsterUI/pull/42))
211
+
212
+ - Created higher level Navbars function for auto-responsive collapse to mobile and easier interface ([#33](https://github.com/AnswerDotAI/MonsterUI/issues/33)), thanks to @curtis-allan
213
+
214
+ - Added Scrollspy to Nav and NavBar and example that demonstrates it ([#31](https://github.com/AnswerDotAI/MonsterUI/issues/31)), thanks to @99ch
215
+
216
+ - Added Highlight JS integration to headers ([#28](https://github.com/AnswerDotAI/MonsterUI/issues/28)), thanks to @99ch
217
+
218
+ ### Bugs Squashed
219
+
220
+ - Improve defaults for Navbar when components are passed so it doesn't override styling specified toby user ([#43](https://github.com/AnswerDotAI/MonsterUI/pull/43))
221
+
222
+
MonsterUI/CHANGELOG.md ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Release notes
2
+
3
+ <!-- do not remove -->
4
+
5
+ ## 1.0.29
6
+
7
+ ### Bugs Squashed
8
+
9
+ - `apply_classes` wraps some elements in html/body/head tags ([#135](https://github.com/AnswerDotAI/MonsterUI/issues/135))
10
+
11
+
12
+ ## 1.0.28
13
+
14
+ ### New Features
15
+
16
+ - allow optional renderer ([#134](https://github.com/AnswerDotAI/MonsterUI/pull/134))
17
+
18
+ ### Bugs Squashed
19
+
20
+ - `render_md` doesn't render images with data uris when `img_dir` is set ([#132](https://github.com/AnswerDotAI/MonsterUI/issues/132))
21
+
22
+
23
+ ## 1.0.26
24
+
25
+ ### Bugs Squashed
26
+
27
+ - fix `render_md` non http/s urls ([#133](https://github.com/AnswerDotAI/MonsterUI/pull/133)), thanks to [@comhar](https://github.com/comhar)
28
+
29
+
30
+ ## 1.0.25
31
+
32
+ ### Bugs Squashed
33
+
34
+ - remove modal on close ([#130](https://github.com/AnswerDotAI/MonsterUI/pull/130)), thanks to [@comhar](https://github.com/comhar)
35
+ - Buttons not working in Modal added to the DOM by HTMX. ([#126](https://github.com/AnswerDotAI/MonsterUI/issues/126))
36
+
37
+
38
+ ## 1.0.24
39
+
40
+ ### New Features
41
+
42
+ - use uikit to initialise and open modals inserted with htmx ([#127](https://github.com/AnswerDotAI/MonsterUI/pull/127)), thanks to [@comhar](https://github.com/comhar)
43
+
44
+
45
+ ## 1.0.23
46
+
47
+ ### Bugs Squashed
48
+
49
+ - fragment md parsing does not work ([#124](https://github.com/AnswerDotAI/MonsterUI/issues/124))
50
+ - llms.txt showing "internal server" errors ([#122](https://github.com/AnswerDotAI/MonsterUI/issues/122))
51
+
52
+
53
+ ## 1.0.22
54
+
55
+ - Create custom themes
56
+
57
+ ### Bugs Squashed
58
+
59
+ - Unicode strings with encoding declaration are not supported ([#123](https://github.com/AnswerDotAI/MonsterUI/issues/123))
60
+ - Update DropDownNavContainer class to remove unnecessary width class ([#114](https://github.com/AnswerDotAI/MonsterUI/pull/114)), thanks to [@ndendic](https://github.com/ndendic)
61
+ - fix font weight ordering ([#113](https://github.com/AnswerDotAI/MonsterUI/pull/113)), thanks to [@comhar](https://github.com/comhar)
62
+ - FieldSet inputs in Form are misaligned when monsterui is active ([#87](https://github.com/AnswerDotAI/MonsterUI/issues/87))
63
+
64
+
65
+ ## 1.0.21
66
+
67
+ ### New Features
68
+
69
+ - The new `ApexChart` component can create line charts, pie charts and [more](https://monsterui.answer.ai/api_ref/docs_charts). ([#110](https://github.com/AnswerDotAI/MonsterUI/pull/110)), thanks to [@ndendic](https://github.com/ndendic)
70
+ - Toasts now disappear automatically after 5 seconds. You can adjust the duration by using the `dur` field (e.g. `Toast('My Toast', dur=10.0)`). ([#109](https://github.com/AnswerDotAI/MonsterUI/pull/109)), thanks to [@comhar](https://github.com/comhar)
71
+
72
+ ### Breaking Change
73
+
74
+ - Katex is no longer included in the default headers. To include it set `katex=True` when calling `.headers`. (i.e. `Theme.slate.headers(katex=True)`). ([#105](https://github.com/AnswerDotAI/MonsterUI/pull/105)), thanks to [@comhar](https://github.com/comhar)
75
+
76
+
77
+ ## 1.0.20
78
+
79
+ ### New Features
80
+
81
+ - Add `icon` header param to optionally not bring in icons js lib ([#99](https://github.com/AnswerDotAI/MonsterUI/issues/99))
82
+
83
+ ### Bugs Squashed
84
+
85
+ - added fh. to unqid ([#98](https://github.com/AnswerDotAI/MonsterUI/pull/98)), thanks to [@MorsCerta-crypto](https://github.com/MorsCerta-crypto)
86
+
87
+
88
+ ## 1.0.19
89
+
90
+ ### New Features
91
+
92
+ - Add accordion component ([#94](https://github.com/AnswerDotAI/MonsterUI/pull/94)), thanks to [@MichlF](https://github.com/MichlF)
93
+ - Fix theme logic ([#93](https://github.com/AnswerDotAI/MonsterUI/pull/93)), thanks to [@curtis-allan](https://github.com/curtis-allan)
94
+
95
+
96
+ ## 1.0.18
97
+
98
+ - Hotfix accidental deletion of label select :(
99
+
100
+
101
+ ## 1.0.16
102
+
103
+ ### Bugs Squashed
104
+
105
+ - Select not properly checking presence of hx-trigger
106
+
107
+ ## 1.0.14
108
+
109
+ ### New Features
110
+
111
+ - Move CDN's to jsdelivr ([#88](https://github.com/AnswerDotAI/MonsterUI/pull/88)), thanks to [@curtis-allan](https://github.com/curtis-allan)
112
+
113
+ ### Bugs Squashed
114
+
115
+ - Select htmx compatibility bug
116
+ - SVG Path Name Collision Issue in MonsterUI ([#85](https://github.com/AnswerDotAI/MonsterUI/issues/85))
117
+
118
+
119
+ ## 1.0.13
120
+
121
+ ### Bugs Squashed
122
+
123
+ - LabelCheckboxX ignores id set manually ([#80](https://github.com/AnswerDotAI/MonsterUI/issues/80))
124
+ - Select sending multiple values to HTMX
125
+
126
+
127
+ ## 1.0.10
128
+
129
+ ### New Features
130
+
131
+ - Cusom Themes support in ThemePicker ([#71](https://github.com/AnswerDotAI/MonsterUI/pull/71)), thanks to [@ndendic](https://github.com/ndendic)
132
+
133
+
134
+ ## 1.0.8
135
+
136
+ - Add lightbox and Insertable select
137
+
138
+ ## 1.0.7
139
+
140
+ ### New Features
141
+
142
+ - Add select kwargs to Select and LabelSelect ([#70](https://github.com/AnswerDotAI/MonsterUI/issues/70))
143
+
144
+ ### Bugs Squashed
145
+
146
+ - Update component classes to align with Franken UI v2.0 ([#67](https://github.com/AnswerDotAI/MonsterUI/pull/67)), thanks to [@Zaseem-BIsquared](https://github.com/Zaseem-BIsquared)
147
+ - Updated ContainerT, CardT, and TableT class names to match the documented patterns from Franken UI v2.0 docs
148
+
149
+ ## 1.0.6
150
+
151
+
152
+ ### Bugs Squashed
153
+
154
+ - Update component classes to align with Franken UI v2.0 ([#67](https://github.com/AnswerDotAI/MonsterUI/pull/67)), thanks to [@Zaseem-BIsquared](https://github.com/Zaseem-BIsquared)
155
+
156
+
157
+ ## 1.0.5
158
+
159
+ - Add Center component
160
+
161
+ ## 1.0.4
162
+
163
+ ### New Features
164
+
165
+ - Bug fix to correct theming conflict in theme initialization
166
+
167
+
168
+ ## 1.0.2
169
+
170
+ - Bug fix to add dark mode theme selector to TW config, thanks to [@curtis-allan](https://github.com/curtis-allan)
171
+
172
+ ## 1.0.1
173
+
174
+ - Theme bug fix not allowing theme changes to stick, thanks to [@zaseem-bisquared](https://github.com/Zaseem-BIsquared)
175
+ - Documentation bug fix on tutorial app, thanks to [@decherd](https://github.com/decherd)
176
+
177
+
178
+ ## 1.0.0
179
+
180
+ ### New Features
181
+
182
+ - Migrated to use FrankenUI version 2.0 version
183
+
184
+ - Brand new simplified NavBar api, including enhanced sticky and scrollspy options, thanks to [@ohmeow](https://github.com/ohmeow) and [@curtis-allan](https://github.com/curtis-allan)
185
+
186
+ - Latex rendering enabled via katex ([#58](https://github.com/AnswerDotAI/MonsterUI/pull/58)), thanks to [@algal](https://github.com/algal)
187
+
188
+ - Add API References and Guides to llms.txt ([#54](https://github.com/AnswerDotAI/MonsterUI/issues/54))
189
+
190
+ - New Range component, which includes min/max range
191
+
192
+ - New center component thanks to inspiration from Carson of HTMX ([#52](https://github.com/AnswerDotAI/MonsterUI/issues/52))
193
+
194
+ - Better Theme Picker ([#51](https://github.com/AnswerDotAI/MonsterUI/issues/51))
195
+
196
+ - Upload Zone and Upload Button Components added ([#50](https://github.com/AnswerDotAI/MonsterUI/issues/50))
197
+
198
+ ### Bugs Squashed
199
+
200
+ - fix: correct PaddingT class naming for padding variants ([#55](https://github.com/AnswerDotAI/MonsterUI/pull/55)), thanks to [@Zaseem-BIsquared](https://github.com/Zaseem-BIsquared)
201
+
202
+
203
+ ## 0.0.34
204
+
205
+
206
+ ### Bugs Squashed
207
+
208
+ - Table markdown rendering bug fix ([#46](https://github.com/AnswerDotAI/MonsterUI/issues/46))
209
+
210
+
211
+ ## 0.0.33
212
+
213
+ ### New Features
214
+
215
+ - Add subtitle function for common semantic styling option ([#44](https://github.com/AnswerDotAI/MonsterUI/pull/44))
216
+
217
+ - Add semantic text styling to docs examples ([#42](https://github.com/AnswerDotAI/MonsterUI/pull/42))
218
+
219
+ - Created higher level Navbars function for auto-responsive collapse to mobile and easier interface ([#33](https://github.com/AnswerDotAI/MonsterUI/issues/33)), thanks to @curtis-allan
220
+
221
+ - Added Scrollspy to Nav and NavBar and example that demonstrates it ([#31](https://github.com/AnswerDotAI/MonsterUI/issues/31)), thanks to @99ch
222
+
223
+ - Added Highlight JS integration to headers ([#28](https://github.com/AnswerDotAI/MonsterUI/issues/28)), thanks to @99ch
224
+
225
+ ### Bugs Squashed
226
+
227
+ - Improve defaults for Navbar when components are passed so it doesn't override styling specified toby user ([#43](https://github.com/AnswerDotAI/MonsterUI/pull/43))
228
+
229
+
MonsterUI/CONTRIBUTING.md ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CONTRIBUTING
2
+
3
+ ## Library Contributions
4
+
5
+ > The code for all components in the library in the Jupyter notebooks (.ipynb files). Edit those, not the .py files.
6
+
7
+ This is an [nbdev](https://nbdev.fast.ai/) library. The notebooks are located in `nbs`.
8
+
9
+ ### Exporting the Modules
10
+
11
+ You can use `nbdev_export` to export the notebooks to the library directory, `monsterui`.
12
+
13
+ ### Cleaning NB metadad
14
+
15
+ You can use `nbdev_clean` to clean the nb metadata from the .py files.
16
+
17
+ ## Docs Contributions
18
+
19
+ The docs are run using [FastHTML](https://fastht.ml/) and can be run locally with:
20
+
21
+ ```bash
22
+ cd docs
23
+ pip install -r requirements.txt
24
+ python main.py
25
+ ```
26
+
27
+ This will start up the MonsterUI documentation site, which is a FastHTML app. Then you can see the site locally at http://localhost:5001/
MonsterUI/LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2022, fastai
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
MonsterUI/MANIFEST.in ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ include settings.ini
2
+ include LICENSE
3
+ include CONTRIBUTING.md
4
+ include README.md
5
+ recursive-exclude * __pycache__
MonsterUI/README.md ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MonsterUI
2
+
3
+ MonsterUI is a UI framework for FastHTML for building beautiful web interfaces with minimal code. It combines the simplicity of Python with the power of Tailwind. Perfect for data scientists, ML engineers, and developers who want to quickly turn their Python code into polished web apps without the complexity of traditional UI frameworks. Follows semantic HTML patterns when possible.
4
+
5
+ MonsterUI adds the following Tailwind-based libraries [Franken UI](https://franken-ui.dev/) and [DaisyUI](https://daisyui.com/) to FastHTML, as well as Python's [Mistletoe](https://github.com/miyuchina/mistletoe) for Markdown, [HighlightJS](https://highlightjs.org/) for code highlighting, and [Katex](https://katex.org/) for latex support.
6
+
7
+ # Getting Started
8
+
9
+
10
+ ## Installation
11
+
12
+ To install this library, uses
13
+
14
+ `pip install MonsterUI`
15
+
16
+ ## Getting Started
17
+
18
+ ### TLDR
19
+
20
+ Run `python file.py` on this to start:
21
+
22
+ ``` python
23
+ from fasthtml.common import *
24
+ from monsterui.all import *
25
+
26
+ # Choose a theme color (blue, green, red, etc)
27
+ hdrs = Theme.blue.headers()
28
+
29
+ # Create your app with the theme
30
+ app, rt = fast_app(hdrs=hdrs)
31
+
32
+ @rt
33
+ def index():
34
+ socials = (('github','https://github.com/AnswerDotAI/MonsterUI'),
35
+ ('twitter','https://twitter.com/isaac_flath/'),
36
+ ('linkedin','https://www.linkedin.com/in/isaacflath/'))
37
+ return Titled("Your First App",
38
+ Card(
39
+ H1("Welcome!"),
40
+ P("Your first MonsterUI app", cls=TextPresets.muted_sm),
41
+ P("I'm excited to see what you build with MonsterUI!"),
42
+ footer=DivLAligned(*[UkIconLink(icon,href=url) for icon,url in socials])))
43
+
44
+ serve()
45
+ ```
46
+
47
+ ## LLM context files
48
+
49
+ Using LLMs for development is a best practice way to get started and
50
+ explore. While LLMs cannot code for you, they can be helpful assistants.
51
+ You must check, refactor, test, and vet any code any LLM generates for
52
+ you - but they are helpful productivity tools. Take a look inside the
53
+ `llms.txt` file to see links to particularly useful context files!
54
+
55
+ - [llms.txt](https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/llms.txt): Links to what is included
56
+ - [llms-ctx.txt](https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/llms-ctx.txt): MonsterUI Documentation Pages
57
+ - [API list](https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/apilist.txt): API list for MonsterUI (included in llms-ctx.txt)
58
+ - [llms-ctx-full.txt](https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/llms-ctx-full.txt): Full context that includes all api reference pages as markdown
59
+
60
+ In addition you can add `/md` (for markdown) to a url to get a markdown representation and `/rmd` for rendered markdown representation (nice for looking to see what would be put into context.
61
+
62
+ ### Step by Step
63
+
64
+ To get started, check out:
65
+
66
+ 1. Start by importing the modules as follows:
67
+
68
+ ``` python
69
+ from fasthtml.common import *
70
+ from monsterui.all import *
71
+ ```
72
+
73
+ 2. Instantiate the app with the MonsterUI headers
74
+
75
+ ``` python
76
+ app = FastHTML(hdrs=Theme.blue.headers())
77
+
78
+ # Alternatively, using the fast_app method
79
+ app, rt = fast_app(hdrs=Theme.slate.headers())
80
+ ```
81
+
82
+ > *The color option can be any of the theme options available out of the
83
+ > box*
84
+
85
+ > `katex` and `highlightjs` are not included by default. To include them set `katex=True` or `highlightjs=True` when calling `.headers`. (i.e. `Theme.slate.headers(katex=True)`)*
86
+
87
+ From here, you can explore the API Reference & examples to see how to
88
+ implement the components. You can also check out these demo videos to as
89
+ a quick start guide:
90
+
91
+ - MonsterUI [documentation page and Tutorial
92
+ app](https://monsterui.answer.ai/tutorial_app)
93
+ - Isaac & Hamel : [Building his website’s team
94
+ page](https://youtu.be/22Jn46-mmM0)
95
+ - Isaac & Audrey : [Building a blog](https://youtu.be/gVWAsywxLXE)
96
+ - Isaac : [Building a blog](https://youtu.be/22NJgfAqgko)
97
+
98
+ More resources and improvements to the documentation will be added here
99
+ soon!
MonsterUI/__pycache__/testnavbar.cpython-312.pyc ADDED
Binary file (989 Bytes). View file
 
MonsterUI/docs/.plash ADDED
@@ -0,0 +1 @@
 
 
1
+ export PLASH_APP_NAME=monsterui.answer.ai
MonsterUI/docs/MonsterUI.jpg ADDED

Git LFS Details

  • SHA256: 1a18a9096a684140dade9be4e90b1cac0d65f395f04c9dc504502ed7d19735ac
  • Pointer size: 131 Bytes
  • Size of remote file: 718 kB
MonsterUI/docs/api_reference/api_reference.py ADDED
@@ -0,0 +1,1211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Reference to all FrankenUI Components"""
2
+
3
+ from fasthtml.common import *
4
+ from monsterui.all import *
5
+ # from nbdev.showdoc import *
6
+ from utils import create_flippable_card, fn2code_string
7
+ from enum import EnumType
8
+ from collections.abc import Callable
9
+
10
+ '''
11
+ Any variable starting with docs_ is a function that generates a section of the API reference.
12
+
13
+ These are automatically added to the docs sidebar so you don't have to do anything other than add the function using create_doc_section.
14
+ '''
15
+ from inspect import signature, getdoc, getsourcefile, getsourcelines
16
+
17
+ # Utilities
18
+ def get_github_url(func):
19
+ "Create GitHub URL for function, assuming AnswerDotAI/MonsterUI repo"
20
+ file = getsourcefile(func).split('MonsterUI/')[-1]
21
+ line = getsourcelines(func)[-1]
22
+ file = file.replace('/opt/venv/lib/python3.12/site-packages/','')
23
+ return f"https://github.com/AnswerDotAI/MonsterUI/blob/main/{file}#L{line}"
24
+
25
+ def get_github_url(func):
26
+ "Create GitHub URL for function, assuming AnswerDotAI/MonsterUI repo"
27
+ try:
28
+ file = getsourcefile(func)
29
+ line = getsourcelines(func)[-1]
30
+
31
+ # Get path after monsterui/ (case insensitive)
32
+ file = file.lower()
33
+ if 'monsterui/' in file:
34
+ file = file.split('monsterui/')[-1]
35
+ elif 'site-packages/' in file:
36
+ file = file.split('site-packages/')[-1]
37
+
38
+ return f"https://github.com/AnswerDotAI/MonsterUI/blob/main/monsterui/{file}#L{line}"
39
+ except:
40
+ return None
41
+
42
+ from fastcore.docments import docments, docstring, get_name
43
+ def show_doc(func) -> str:
44
+ "Convert a Google-style docstring to markdown"
45
+ params = docments(func, args_kwargs=True)
46
+ funcname = get_name(func)
47
+ doc = docstring(func)
48
+ par, ret = None, None
49
+ if params:
50
+ par = Div(Strong('Params'),
51
+ Ul(*[Li(render_md(f"`{name}` {desc if desc else ''}",class_map_mods={'p':'leading-relaxed'}), cls='') for name, desc in params.items() if name != 'return'], cls='uk-list-disc space-y-2 mb-6 ml-6'))
52
+ if 'return' in params and params['return']: ret = render_md(f"**Returns:** {params['return']}")
53
+ return Div(
54
+ DivFullySpaced(
55
+ render_md(f"### {funcname}"),
56
+ A("Source", href=get_github_url(func), cls='text-primary hover:text-primary-focus underline')),
57
+ Pre(Code(f"{funcname}{signature(func)}",
58
+ cls='hljs language-python px-1 block overflow-x-auto'),
59
+ cls='bg-base-200 rounded-lg p-4 mb-6'),
60
+ Div(Blockquote(render_md(doc), cls='pl-4 border-l-4 border-primary mb-6'), par, ret, cls='ml-10'))
61
+
62
+ def enum_to_html_table(enum_class):
63
+ "Creates a compact multi-column table display for enum documentation"
64
+ items = list(enum_class.__members__.items())
65
+ n_cols = min(4, max(2, round((len(items) ** 0.5))))
66
+
67
+ # Create header/cell pairs with borders
68
+ def make_pair(opt, val, i):
69
+ border = 'border-l border-base-300 pl-4' if i > 0 else ''
70
+ return [Th('Option', cls=border), Th('Value')] if opt == 'header' else [Td(opt, cls=border), Td(val)]
71
+
72
+ # Build rows with padding for incomplete final row
73
+ rows = []
74
+ for i in range(0, len(items), n_cols):
75
+ cells = []
76
+ for j in range(n_cols):
77
+ name, val = items[i + j] if i + j < len(items) else ('', '')
78
+ cells.extend(make_pair(name, val.value if val else '', j))
79
+ rows.append(Tr(*cells))
80
+
81
+ return Div(
82
+ Hr(cls='uk-divider-icon my-2'),
83
+ DivFullySpaced(H3(enum_class.__name__, cls='my-2'), P(I(enum_class.__doc__), cls='text-sm')),
84
+ Table(
85
+ Thead(Tr(*make_pair('header', '', 0) * n_cols)),
86
+ Tbody(*rows),
87
+ cls=(TableT.hover, 'uk-table-small uk-table-justify uk-table-middle')))
88
+
89
+ def render_content(c):
90
+ "Renders content by type"
91
+ if isinstance(c, str): return render_md(c) # Strings are rendered as markdown
92
+ elif isinstance(c, EnumType): return enum_to_html_table(c) # Enums are rendered as tables
93
+ elif isinstance(c, FT): return c # FastHTML tags are rendered as themselves
94
+ elif isinstance(c, tuple): # Tuples are rendered as cards with source and output that can be flipped
95
+ extra_cls = c[2] if len(tuple(c)) == 3 else None
96
+ return create_flippable_card(c[0], c[1], extra_cls)
97
+ elif isinstance(c, Callable): # Callables are rendered as documentation via show_doc
98
+ return show_doc(c)
99
+ # _html = show_doc(c, renderer=BasicHtmlRenderer)._repr_html_()
100
+ # return NotStr(apply_classes(_html, class_map_mods={"table":'uk-table uk-table-hover uk-table-small'}))
101
+ else: return c
102
+
103
+ def create_doc_section(*content, title):
104
+ return lambda: Div(Container(*map(render_content, content)))
105
+
106
+ def string2code_string(code: str) -> tuple: return eval(code), code
107
+
108
+ # Sliders
109
+
110
+ def ex_sliders_1():
111
+ return Slider(*[Img(src=f'https://picsum.photos/200/200?random={i}') for i in range(10)])
112
+
113
+ def ex_sliders_2():
114
+ def _card(i): return Card(H3(f'Card {i}'), P(f'Card {i} content'))
115
+ return Slider(*[_card(i) for i in range(10)])
116
+
117
+ def ex_sliders_3():
118
+ def _card(i): return Card(H3(f'Card {i}'), P(f'Card {i} content'))
119
+ return Slider(*[_card(i) for i in range(10)], items_cls='gap-10', uk_slider='autoplay: true; autoplay-interval: 1000')
120
+
121
+ docs_sliders = create_doc_section(
122
+ H1("Carousel Sliders API Reference"),
123
+ "Here is a simple example of a slider:",
124
+ fn2code_string(ex_sliders_1),
125
+ "Here is a slider with cards:",
126
+ fn2code_string(ex_sliders_2),
127
+ "Here is a slider with cards and autoplay:",
128
+ fn2code_string(ex_sliders_3),
129
+ "Typically you want to use the `Slider` component, but if you need more control you can use the `SliderContainer`, `SliderItems`, and `SliderNav` components.",
130
+ Slider,
131
+ SliderContainer,
132
+ SliderItems,
133
+ SliderNav,
134
+ title="Sliders")
135
+
136
+ # Accordions
137
+
138
+ def ex_accordion_1():
139
+ return Div(
140
+ H2("Accordion Header"),
141
+ Accordion(
142
+ AccordionItem(
143
+ "Section 1",
144
+ P("Content for the first section."),
145
+ P("More content here."),
146
+ ),
147
+ AccordionItem(
148
+ "Section 2",
149
+ P("Content for the second section."),
150
+ Label("A label inside!"),
151
+ li_kwargs={"id": "section-2"},
152
+ ),
153
+ AccordionItem(
154
+ "Section 3 - The last one!", P("Content for the third section.")
155
+ ),
156
+ multiple=False,
157
+ animation=True,
158
+ ),
159
+ ),
160
+
161
+ def ex_accordion_2():
162
+ return Div(
163
+ H2("Accordion Header"),
164
+ Accordion(
165
+ AccordionItem(
166
+ "Section 1",
167
+ P("Content for the first section."),
168
+ P("More content here."),
169
+ open=True,
170
+ ),
171
+ AccordionItem(
172
+ "Section 2",
173
+ P("Content for the second section."),
174
+ Label("A label inside!"),
175
+ li_kwargs={"id": "section-2"},
176
+ ),
177
+ AccordionItem(
178
+ "Section 3 - The last one!", P("Content for the third section.")
179
+ ),
180
+ multiple=True,
181
+ animation=True,
182
+ ),
183
+ ),
184
+
185
+ def ex_accordion_3():
186
+ return Div(
187
+ H2("Accordion Header"),
188
+ Accordion(
189
+ AccordionItem(
190
+ "Section 1",
191
+ P("Content for the first section."),
192
+ P("More content here."),
193
+ ),
194
+ AccordionItem(
195
+ "Section 2",
196
+ P("Content for the second section."),
197
+ Label("A label inside!"),
198
+ li_kwargs={"id": "section-2"},
199
+ ),
200
+ AccordionItem(
201
+ "Section 3 - The last one!", P("Content for the third section.")
202
+ ),
203
+ multiple=False,
204
+ animation=False,
205
+ ),
206
+ ),
207
+
208
+ docs_accordion_link = create_doc_section(
209
+ H1("Accordion API Reference"),
210
+ Div(id='accordion'), # for linking to in release post
211
+ H3("Example Accordions"),
212
+ P("A simple accordion with fluid collapsing and expanding animation where only a single Section can be exanded at any time."),
213
+ fn2code_string(ex_accordion_1),
214
+ P("An accordion with fluid collapsing and expanding animation where one section is already expanded at startup and multiple section can be expanded at any time."),
215
+ fn2code_string(ex_accordion_2),
216
+ P("An accordion with no collapsing and expanding animation where only a single Section can be exanded at any time."),
217
+ fn2code_string(ex_accordion_3),
218
+ H3("API Reference"),
219
+ Accordion,
220
+ AccordionItem,
221
+ title="Accordion")
222
+
223
+ # Buttons
224
+
225
+ def ex_buttons():
226
+ return Grid(
227
+ Button("Default"),
228
+ Button("Primary", cls=ButtonT.primary),
229
+ Button("Secondary", cls=ButtonT.secondary),
230
+ Button("Danger", cls=ButtonT.destructive),
231
+ Button("Text", cls=ButtonT.text),
232
+ Button("Link", cls=ButtonT.link),
233
+ Button("Ghost", cls=ButtonT.ghost),
234
+ )
235
+
236
+ def ex_links():
237
+ return Div(cls='space-x-4')(
238
+ A('Default Link'),
239
+ A('Muted Link', cls=AT.muted),
240
+ A('Text Link', cls=AT.text),
241
+ A('Reset Link', cls=AT.reset),
242
+ A('Primary Link', cls=AT.primary),
243
+ A('Classic Link', cls=AT.classic),)
244
+
245
+ docs_button_link = create_doc_section(
246
+ H1("Buttons & Links API Reference"),
247
+ Div(id='button'), # for linking to in release post
248
+ fn2code_string(ex_buttons),
249
+ fn2code_string(ex_links),
250
+ Button,
251
+ ButtonT,
252
+ AT,
253
+ title="Buttons & Links")
254
+
255
+ # Theme
256
+
257
+ def ex_theme_switcher():
258
+ return ThemePicker()
259
+
260
+ docs_theme_headers = create_doc_section(
261
+ H1("Theme and Headers API Reference"),
262
+ """
263
+ To get headers with a default theme use `hdrs=Theme.<color>.headers()`. For example for the blue theme you would use `hdrs=Theme.blue.headers()`. The theme integrated together different frameworks and allows tailwind, FrankenUI, HighlighJS, and DaisyUI components to work well together.
264
+
265
+ Tailwind, FrankenUI and DaisyUI are imported by default. You must use DaisyUI headers to use anything in the `daisy` module, and FrankenUI headers to use anything in the `franken` module.
266
+
267
+ HighlightJS is not added by default, but you can add it by setting `highlightjs=True` in the headers function. The `render_md` function will use HighlightJS for code blocks.
268
+
269
+ Theme options are:""",
270
+ Card(Grid(map(P,Theme)),cls='mb-8'),
271
+ H3("Theme Picker", id='theme'),
272
+ fn2code_string(ex_theme_switcher),
273
+ ThemePicker,
274
+ H3("Custom Themes"),
275
+ render_md("""
276
+ 1. You can use [this theme](https://github.com/AnswerDotAI/MonsterUI/blob/main/docs/custom_theme.css) as a starting point.
277
+ 2. Add the theme to your headers as a link like this `Link(rel="stylesheet", href="/custom_theme.css", type="text/css")`
278
+ 3. Then add the theme to the `ThemePicker` component. For example `ThemePicker(custom_themes=[('Grass', '#10b981')])`
279
+ """),
280
+ "Themes are controlled with `bg-background text-foreground` classes on the `Body` tag. `fast_app` and `FastHTML` will do this for you automatically so you typically do not have to do anything",
281
+ fast_app,
282
+ FastHTML,
283
+
284
+ Blockquote(P("Users have said ", A("this site", href="https://ui.jln.dev/"), " is helpful in creating your own themes.")),
285
+
286
+ title="Headers")
287
+
288
+ # Typography
289
+
290
+ def ex_headings():
291
+ return Div(
292
+ Titled("Titled"),
293
+ H1("Level 1 Heading (H1)"),
294
+ H2("Level 2 Heading (H2)"),
295
+ H3("Level 3 Heading (H3)"),
296
+ H4("Level 4 Heading (H4)"),
297
+ H5("Level 5 Heading (H5)"),
298
+ H6("Level 6 Heading (H6)"),
299
+ )
300
+
301
+
302
+ def ex_semantic_elements():
303
+ return Div(
304
+ H2("Semantic HTML Elements Demo"),
305
+ # Text formatting examples
306
+ P("Here's an example of ", Em("emphasized (Em)"), " and ", Strong("strong (Strong)"), " text."),
307
+ P("Some ", I("italic text (I)"), " and ", Small("smaller text (Small)"), " in a paragraph."),
308
+ P("You can ", Mark("highlight (Mark)"), " text, show ", Del("deleted (Del)"), " and ",
309
+ Ins("inserted (Ins)"), " content."),
310
+ P("Chemical formulas use ", Sub("subscripts (Sub)"), " and ", Sup("superscripts (Sup)"),
311
+ " like H", Sub("2"), "O."),
312
+ # Quote examples
313
+ Blockquote(
314
+ P("The only way to do great work is to love what you do."),
315
+ Cite("Steve Jobs (Cite)")),
316
+ P("As Shakespeare wrote, ", Q("All the world's a stage (Q)"), "."),
317
+ # Time and Address
318
+ P("Posted on ", Time("2024-01-29", datetime="2024-01-29")),
319
+ Address(
320
+ "Mozilla Foundation (Address)",
321
+ Br(),
322
+ "331 E Evelyn Ave (Address)",
323
+ Br(),
324
+ "Mountain View, CA 94041 (Address)",
325
+ Br(),
326
+ "USA (Address)"),
327
+ # Technical and definition examples
328
+ P(
329
+ Dfn("HTML (Dfn)"), " (",
330
+ Abbr("HyperText Markup Language (Abbr)", title="HyperText Markup Language"),
331
+ ") is the standard markup language for documents designed to be displayed in a web browser."),
332
+ P("Press ", Kbd("Ctrl (Kbd)"), " + ", Kbd("C (Kbd)"), " to copy."),
333
+ P("The command returned: ", Samp("Hello, World! (Samp)")),
334
+ P("Let ", Var("x (Var)"), " be the variable in the equation."),
335
+ # Figure with caption
336
+ Figure(
337
+ PicSumImg(),
338
+ Caption("Figure 1: An example image with caption (Caption)")),
339
+ # Interactive elements
340
+ Details(
341
+ Summary("Click to show more information (Summary)"),
342
+ P("This is the detailed content that is initially hidden (P)")),
343
+ # Data representation
344
+ P(
345
+ Data("123 (Data)", value="123"), " is a number, and here's a Meter showing progress: ",
346
+ Meter(value=0.6, min=0, max=1)),
347
+ P(
348
+ "Temperature: ",
349
+ Meter(value=-1, min=-10, max=40, low=0, high=30, optimum=21),
350
+ " (with low/high/optimum values)"),
351
+ P(
352
+ Data("€42.00", value="42"),
353
+ " - price example with semantic value"),
354
+ # Output example
355
+ P("Form calculation result: ", Output("The sum is 42 (Output)", form="calc-form", for_="num1 num2")),
356
+ # Meta information example
357
+ Section(
358
+ H3("Blog Post Title (H3)"),
359
+ Small("By John Doe • 5 min read (Small)"),
360
+ P("Article content here...")),
361
+ # Text decoration examples
362
+ P("This text has ",U("proper name annotation (U)"), " and this is ",S("outdated information (S)"), " that's been superseded."),
363
+ cls='space-y-4'
364
+ )
365
+
366
+
367
+ def ex_textpresets():
368
+ return Grid(*[Div(P(f"This is {preset.name} text", cls=preset.value)) for preset in TextPresets])
369
+
370
+ def ex_textt():
371
+ return Grid(*[Div(P(f"This is {s.name} text", cls=s.value)) for s in TextT])
372
+
373
+ def ex_other():
374
+ return Div(
375
+ CodeSpan("This is a CodeSpan element"),
376
+ Blockquote("This is a blockquote element"),
377
+ CodeBlock("#This is a CodeBlock element\n\ndef add(a,b): return a+b"))
378
+
379
+ docs_typography = create_doc_section(
380
+ H1("Typography API Reference"),
381
+ P("Ready to go semantic options that cover most of what you need based on the HTML spec"),
382
+ fn2code_string(ex_headings),
383
+ fn2code_string(ex_semantic_elements),
384
+ fn2code_string(ex_other),
385
+ P("Styling text is possibly the most common style thing to do, so we have a couple of helpers for discoverability inside python. `TextPresets` is intended to be combinations are are widely applicable and used often, where `TextT` is intended to be more flexible options for you to combine together yourself."),
386
+ H5("TextPresets.*"),
387
+ fn2code_string(ex_textpresets),
388
+ H5("TextT.*"),
389
+ fn2code_string(ex_textt),
390
+ H3("API Reference"),
391
+ TextPresets,
392
+ TextT,
393
+ H1, H2, H3, H4, H5, H6,
394
+ CodeSpan, Blockquote, CodeBlock,
395
+ Em, Strong, I, Small, Mark, Sub, Sup, Del, Ins,
396
+ Dfn, Abbr, Q, Kbd, Samp, Var,
397
+ Figure, Caption,
398
+ Details, Summary,
399
+ Meter, Data, Output,
400
+ Address, Time,
401
+ title="Text Style")
402
+
403
+
404
+ # Notifications
405
+ def ex_alerts1(): return Alert("This is a plain alert")
406
+
407
+ def ex_alerts2(): return Alert("Your purchase has been confirmed!", cls=AlertT.success)
408
+
409
+ def ex_alerts3():
410
+ return Alert(
411
+ DivLAligned(UkIcon('triangle-alert'),
412
+ P("Please enter a valid email.")),
413
+ cls=AlertT.error)
414
+
415
+ def ex_toasts1():
416
+ return Toast("First Example Toast", cls=(ToastHT.start, ToastVT.bottom), dur=300)
417
+
418
+ def ex_toasts2():
419
+ return Toast("Second Example Toast", alert_cls=AlertT.info, dur=300)
420
+
421
+ docs_notifications = create_doc_section(
422
+ H1("Alerts & Toasts API Reference"),
423
+ H3("Alerts"),
424
+ P("The simplest alert is a div wrapped with a span:"),
425
+ fn2code_string(ex_alerts1),
426
+ P("Alert colors are defined by the alert styles:"),
427
+ fn2code_string(ex_alerts2),
428
+ P("It often looks nice to use icons in alerts: "),
429
+ fn2code_string(ex_alerts3),
430
+ Alert, AlertT,
431
+ DividerLine(),
432
+ H3("Toasts"),
433
+ P("To define a toast with a particular location, add horizontal or vertical toast type classes:"),
434
+ fn2code_string(ex_toasts1),
435
+ P("To define toast colors, set the class of the alert wrapped by the toast:"),
436
+ fn2code_string(ex_toasts2),
437
+ P("Toasts will disappear automatically after 5 seconds. To change the duration of the toast set the `dur` param like this `Toast('Content', dur=10)`."),
438
+ P("Here's a demo ", A("app", href="https://gallery.fastht.ml/split/dynamic_user_interface_(htmx)/toast", target="_blank", rel="noopener noreferrer", cls='underline'), " showing how to trigger a toast.", cls='mt-4'),
439
+ Toast, ToastHT, ToastVT,
440
+ title="Alerts & Toasts")
441
+
442
+ # Containers
443
+
444
+ def ex_articles():
445
+ return Article(
446
+ ArticleTitle("Sample Article Title"),
447
+ Subtitle("By: John Doe"),
448
+ P('lorem ipsum dolor sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'))
449
+
450
+ def ex_containers():
451
+ return Container(
452
+ "This is a sample container with custom styling.",
453
+ cls=ContainerT.xs,
454
+ style="background-color: #FFA500; color: #000000")
455
+
456
+
457
+ docs_containers = create_doc_section(
458
+ H1("Articles, Containers & Sections API Reference"),
459
+ ArticleMeta,
460
+ ArticleTitle,
461
+ Article,
462
+ fn2code_string(ex_articles),
463
+ Container,
464
+ ContainerT,
465
+ fn2code_string(ex_containers),
466
+ Section,
467
+ SectionT,
468
+ title="Articles, Containers & Sections"
469
+ )
470
+
471
+ # Cards
472
+
473
+ def ex_card():
474
+ return Card(
475
+ Form(LabelInput("Input"),
476
+ LabelRange("Range")),
477
+ header=Div(
478
+ CardTitle("Header"),
479
+ P("A card with header and footer",cls=TextPresets.muted_sm)),
480
+ footer=DivLAligned(Button("Footer Submit Button")))
481
+
482
+
483
+
484
+ def Tags(cats): return Div(cls='space-x-2')(map(Label, cats))
485
+
486
+ def ex_card2_wide():
487
+ def Tags(cats): return DivLAligned(map(Label, cats))
488
+
489
+ return Card(
490
+ DivLAligned(
491
+ A(Img(src="https://picsum.photos/200/200?random=12", style="width:200px"),href="#"),
492
+ Div(cls='space-y-3 uk-width-expand')(
493
+ H4("Creating Custom FastHTML Tags for Markdown Rendering"),
494
+ P("A step by step tutorial to rendering markdown in FastHTML using zero-md inside of DaisyUI chat bubbles"),
495
+ DivFullySpaced(map(Small, ["Isaac Flath", "20-October-2024"]), cls=TextT.muted),
496
+ DivFullySpaced(
497
+ Tags(["FastHTML", "HTMX", "Web Apps"]),
498
+ Button("Read", cls=(ButtonT.primary,'h-6'))))),
499
+ cls=CardT.hover)
500
+
501
+ def ex_card2_tall():
502
+ def Tags(cats): return DivLAligned(map(Label, cats))
503
+
504
+ return Card(
505
+ Div(
506
+ A(Img(src="https://picsum.photos/400/200?random=14"), href="#"),
507
+ Div(cls='space-y-3 uk-width-expand')(
508
+ H4("Creating Custom FastHTML Tags for Markdown Rendering"),
509
+ P("A step by step tutorial to rendering markdown in FastHTML using zero-md inside of DaisyUI chat bubbles"),
510
+ DivFullySpaced(map(Small, ["Isaac Flath", "20-October-2024"]), cls=TextT.muted),
511
+ DivFullySpaced(
512
+ Tags(["FastHTML", "HTMX", "Web Apps"]),
513
+ Button("Read", cls=(ButtonT.primary,'h-6'))))),
514
+ cls=CardT.hover)
515
+
516
+ def ex_card3():
517
+ def team_member(name, role, location="Remote"):
518
+ return Card(
519
+ DivLAligned(
520
+ DiceBearAvatar(name, h=24, w=24),
521
+ Div(H3(name), P(role))),
522
+ footer=DivFullySpaced(
523
+ DivHStacked(UkIcon("map-pin", height=16), P(location)),
524
+ DivHStacked(*(UkIconLink(icon, height=16) for icon in ("mail", "linkedin", "github")))))
525
+ team = [
526
+ team_member("Sarah Chen", "Engineering Lead", "San Francisco"),
527
+ team_member("James Wilson", "Senior Developer", "New York"),
528
+ team_member("Maria Garcia", "UX Designer", "London"),
529
+ team_member("Alex Kumar", "Product Manager", "Singapore"),
530
+ team_member("Emma Brown", "DevOps Engineer", "Toronto"),
531
+ team_member("Marcus Johnson", "Frontend Developer", "Berlin")
532
+ ]
533
+ return Grid(*team, cols_sm=1, cols_md=1, cols_lg=2, cols_xl=3)
534
+
535
+ docs_cards = create_doc_section(
536
+ H1("Cards API Reference"),
537
+ H3("Example Usage"),
538
+ fn2code_string(ex_card),
539
+ (*fn2code_string(ex_card2_wide),'sm:block'),
540
+ (*fn2code_string(ex_card2_tall),'sm:hidden'),
541
+ fn2code_string(ex_card3),
542
+ H3("API Reference"),
543
+ Card,
544
+ CardTitle,
545
+ CardT,
546
+ P("The remainder of these are only needed if you're doing something really special. They are used in the `Card` function to generate the boilerplate for you.", cls='my-6'),
547
+ CardContainer,
548
+ CardHeader,
549
+ CardBody,
550
+ CardFooter,
551
+ title="Cards"
552
+ )
553
+
554
+ # Lists
555
+
556
+ def ex_lists():
557
+ list_options = [(style,str(cls)) for style,cls in ListT.__members__.items()]
558
+ lists = [Div(H4(f"{style} List:"), Ul(Li("Item 1"), Li("Item 2"), cls=cls)) for style, cls in list_options]
559
+ return Grid(*lists)
560
+
561
+ docs_lists = create_doc_section(
562
+ H1("Lists API Reference"),
563
+ fn2code_string(ex_lists),
564
+ ListT,
565
+ title="Lists")
566
+
567
+ # Forms
568
+
569
+ def ex_formlabel():
570
+ return FormLabel("Form Label")
571
+
572
+ def ex_input():
573
+ return Div(
574
+ Input(placeholder="Enter text"),
575
+ LabelInput(label="Input", id='myid'))
576
+
577
+ def ex_checkbox():
578
+ return Div(
579
+ CheckboxX(),
580
+ LabelCheckboxX(label="Checkbox", id='checkbox1'))
581
+
582
+ def ex_range():
583
+ return Div(
584
+ Range(),
585
+ Range(label='kg', value="25,75", min=20, max=75),
586
+ LabelRange('Basic Range', value='50', min=0, max=100, step=1),
587
+ LabelRange('Range with Label', value='75', min=0, max=100, step=5, label_range=True),
588
+ LabelRange('Multiple Values', value='25,75', min=0, max=100, step=5, label_range=True),
589
+ LabelRange('Custom Range', value='500', min=0, max=1000, step=100, label_range=True)
590
+ )
591
+
592
+ def ex_switch():
593
+ return Div(
594
+ Switch(id="switch"),
595
+ LabelSwitch(label="Switch", id='switch'))
596
+
597
+ def ex_textarea():
598
+ return Div(
599
+ TextArea(placeholder="Enter multiple lines of text"),
600
+ LabelTextArea(label="TextArea", id='myid'))
601
+
602
+ def ex_radio():
603
+ return Div(
604
+ Radio(name="radio-group", id="radio1"),
605
+ LabelRadio(label="Radio", id='radio1',cls='flex items-center space-x-4'))
606
+
607
+ def ex_insertable_select1():
608
+ fruit_opts = ['apple', 'orange', 'banana', 'mango']
609
+
610
+ return Grid(
611
+ Select(Option('Apple', value='apple'),
612
+ Option('Orange', value='orange'),
613
+ Option('Banana', value='banana'),
614
+ Option('Mango', value='mango'),
615
+ id="fruit", icon=True, insertable=True, placeholder="Choose a fruit..."),
616
+
617
+ Select(Optgroup(label="Fruit")(
618
+ *map(lambda l: Option(l.capitalize(), value=l), sorted(fruit_opts))),
619
+ id="fruit", icon=True, insertable=True, placeholder="Choose a fruit...",
620
+ cls_custom="button: uk-input-fake justify-between w-full; dropdown: w-full"))
621
+
622
+ def ex_select():
623
+ return Div(
624
+ Select(map(Option, ["Option 1", "Option 2", "Option 3"])),
625
+ LabelSelect(map(Option, ["Option 1", "Option 2", "Option 3"]), label="Select", id='myid'))
626
+
627
+ def ex_progress():
628
+ return Progress(value=20, max=100)
629
+
630
+ def ex_form():
631
+ relationship = ["Parent",'Sibling', "Friend", "Spouse", "Significant Other", "Relative", "Child", "Other"]
632
+ return Div(cls='space-y-4')(
633
+ DivCentered(
634
+ H3("Emergency Contact Form"),
635
+ P("Please fill out the form completely", cls=TextPresets.muted_sm)),
636
+ Form(cls='space-y-4')(
637
+ Grid(LabelInput("First Name",id='fn'), LabelInput("Last Name",id='ln')),
638
+ Grid(LabelInput("Email", id='em'), LabelInput("Phone", id='ph')),
639
+ H3("Relationship to patient"),
640
+ Grid(*[LabelCheckboxX(o) for o in relationship], cols=4, cls='space-y-3'),
641
+ LabelInput("Address", id='ad'),
642
+ LabelInput("Address Line 2", id='ad2'),
643
+ Grid(LabelInput("City", id='ct'), LabelInput("State", id='st')),
644
+ LabelInput("Zip", id='zp'),
645
+ DivCentered(Button("Submit Form", cls=ButtonT.primary))))
646
+
647
+ def ex_upload():
648
+ return Div(Upload("Upload Button!", id='upload1'),
649
+ UploadZone(DivCentered(Span("Upload Zone"), UkIcon("upload")), id='upload2'),
650
+ cls='space-y-4')
651
+
652
+ docs_forms = create_doc_section(
653
+ H1("Forms and User Inputs API Reference"),
654
+ H3("Example Form"),
655
+ P(f"This form was live coded in a 5 minute video ",
656
+ A("here",href="https://www.loom.com/share/0916e8a95d524c43a4d100ee85157624?start_and_pause=1",
657
+ cls=AT.muted), cls=TextPresets.muted_sm),
658
+ fn2code_string(ex_form),
659
+ fn2code_string(ex_upload),
660
+ FormLabel,
661
+ fn2code_string(ex_formlabel),
662
+ Input,
663
+ fn2code_string(ex_input),
664
+ LabelInput,
665
+ LabelCheckboxX,
666
+ LabelSwitch,
667
+ LabelRange,
668
+ LabelTextArea,
669
+ LabelRadio,
670
+ LabelSelect,
671
+ Progress,
672
+ fn2code_string(ex_progress),
673
+ Radio,
674
+ fn2code_string(ex_radio),
675
+ CheckboxX,
676
+ fn2code_string(ex_checkbox),
677
+ Range,
678
+ fn2code_string(ex_range),
679
+ Switch,
680
+ fn2code_string(ex_switch),
681
+ TextArea,
682
+ fn2code_string(ex_textarea),
683
+ Select,
684
+ fn2code_string(ex_select),
685
+ H3("Example: Insertable Select"),
686
+ Caption("In a production app, the user-inserted option would be saved server-side (db, session etc.)"),
687
+ fn2code_string(ex_insertable_select1),
688
+ Legend,
689
+ Fieldset,
690
+ title="Forms")
691
+
692
+
693
+ # Lightbox
694
+
695
+ def ex_lightbox1():
696
+ return LightboxContainer(
697
+ LightboxItem(Button("Open"), href='https://picsum.photos/id/100/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='This is my super cool caption'),
698
+ )
699
+ def ex_lightbox2():
700
+ return LightboxContainer(
701
+ LightboxItem(Button("Open"), href='https://picsum.photos/id/100/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='Image 1'),
702
+ LightboxItem(href='https://picsum.photos/id/101/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='Image 2'),
703
+ LightboxItem(href='https://picsum.photos/id/102/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='Image 3'),
704
+ )
705
+
706
+ def ex_lightbox3():
707
+ return LightboxContainer(
708
+ LightboxItem(Button("mp4"), href='https://yootheme.com/site/images/media/yootheme-pro.mp4'),
709
+ LightboxItem(Button("Youtube"), href='https://www.youtube.com/watch?v=c2pz2mlSfXA'),
710
+ LightboxItem(Button("Vimeo"), href='https://vimeo.com/1084537'),
711
+ LightboxItem(Button("Iframe"), data_type='iframe', href='https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d4740.819266853735!2d9.99008871708242!3d53.550454675412404!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x3f9d24afe84a0263!2sRathaus!5e0!3m2!1sde!2sde!4v1499675200938'))
712
+
713
+ docs_lightbox = create_doc_section(
714
+ H1("Lightbox API Reference"),
715
+ fn2code_string(ex_lightbox1),
716
+ fn2code_string(ex_lightbox2),
717
+ fn2code_string(ex_lightbox3),
718
+ LightboxContainer,
719
+ LightboxItem,
720
+ title="Lightbox")
721
+
722
+ # Modals
723
+
724
+ def ex_modal():
725
+ return Div(
726
+ Button("Open Modal",data_uk_toggle="target: #my-modal" ),
727
+ Modal(ModalTitle("Simple Test Modal"),
728
+ P("With some somewhat brief content to show that it works!", cls=TextPresets.muted_sm),
729
+ footer=ModalCloseButton("Close", cls=ButtonT.primary),id='my-modal'))
730
+
731
+ docs_modals = create_doc_section(
732
+ H1("Modals API Reference"),
733
+ H3("Example Modal"),
734
+ fn2code_string(ex_modal),
735
+ Modal,
736
+ P("If you want to trigger a htmx event on close (like calling a route) you can use `hx_trigger='hidden'` to catch the close event."),
737
+ ModalCloseButton,
738
+ P("The remainder of the Modal functions below are used internally by the `Modal` function for you. You shouldn't need to use them unless you're doing something really special."),
739
+ ModalTitle,
740
+ ModalFooter,
741
+ ModalBody,
742
+ ModalHeader,
743
+ ModalDialog,
744
+ ModalContainer,
745
+ title="Modals")
746
+
747
+ # Layout
748
+
749
+ def ex_grid():
750
+ return Grid(
751
+ Div(
752
+ P("Column 1 Item 1"),
753
+ P("Column 1 Item 2"),
754
+ P("Column 1 Item 3")),
755
+ Div(
756
+ P("Column 2 Item 1"),
757
+ P("Column 2 Item 2"),
758
+ P("Column 2 Item 3")),
759
+ Div(
760
+ P("Column 3 Item 1"),
761
+ P("Column 3 Item 2"),
762
+ P("Column 3 Item 3")))
763
+
764
+ def ex_product_grid():
765
+ products = [
766
+ {"name": "Laptop", "price": "$999", "img": "https://picsum.photos/200/100?random=1"},
767
+ {"name": "Smartphone", "price": "$599", "img": "https://picsum.photos/200/100?random=2"},
768
+ {"name": "Headphones", "price": "$199", "img": "https://picsum.photos/200/100?random=3"},
769
+ {"name": "Smartwatch", "price": "$299", "img": "https://picsum.photos/200/100?random=4"},
770
+ {"name": "Tablet", "price": "$449", "img": "https://picsum.photos/200/100?random=5"},
771
+ {"name": "Camera", "price": "$799", "img": "https://picsum.photos/200/100?random=6"},
772
+ ]
773
+
774
+ product_cards = [
775
+ Card(
776
+ Img(src=p["img"], alt=p["name"], style="width:100%; height:100px; object-fit:cover;"),
777
+ H4(p["name"], cls="mt-2"),
778
+ P(p["price"], cls=TextPresets.bold_sm),
779
+ Button("Add to Cart", cls=(ButtonT.primary, "mt-2"))
780
+ ) for p in products
781
+ ]
782
+
783
+ return Grid(*product_cards, cols_lg=3)
784
+
785
+ def ex_fully_spaced_div():
786
+ return DivFullySpaced(
787
+ Button("Left", cls=ButtonT.primary),
788
+ Button("Center", cls=ButtonT.secondary),
789
+ Button("Right", cls=ButtonT.destructive)
790
+ )
791
+
792
+ def ex_centered_div():
793
+ return DivCentered(
794
+ H3("Centered Title"),
795
+ P("This content is centered both horizontally and vertically.")
796
+ )
797
+
798
+ def ex_l_aligned_div():
799
+ return DivLAligned(
800
+ Img(src="https://picsum.photos/100/100?random=1", style="max-width: 100px;"),
801
+ H4("Left Aligned Title"),
802
+ P("Some text that's left-aligned with the title and image.")
803
+ )
804
+
805
+ def ex_r_aligned_div():
806
+ return DivRAligned(
807
+ Button("Action", cls=ButtonT.primary),
808
+ P("Right-aligned text"),
809
+ Img(src="https://picsum.photos/100/100?random=3", style="max-width: 100px;")
810
+ )
811
+
812
+ def ex_v_stacked_div():
813
+ return DivVStacked(
814
+ H2("Vertical Stack"),
815
+ P("First paragraph in the stack"),
816
+ P("Second paragraph in the stack"),
817
+ Button("Action Button", cls=ButtonT.secondary)
818
+ )
819
+
820
+ def ex_h_stacked_div():
821
+ return DivHStacked(
822
+ Div(H4("Column 1"), P("Content for column 1")),
823
+ Div(H4("Column 2"), P("Content for column 2")),
824
+ Div(H4("Column 3"), P("Content for column 3"))
825
+ )
826
+
827
+ docs_layout = create_doc_section(
828
+ H1("Layout (Flex and Grid) API Reference"),
829
+ P("This page covers `Grid`s, which are often used for general structure, `Flex` which is often used for layout of components that are not grid based, padding and positioning that can help you make your layout look good, and dividers that can help break up the page", cls=TextPresets.muted_sm),
830
+ H2("Grid"),
831
+ fn2code_string(ex_grid),
832
+ Grid,
833
+ H4("Practical Grid Example"),
834
+ fn2code_string(ex_product_grid),
835
+ H2("Flex"),
836
+ P("Play ",
837
+ A("Flex Box Froggy", href="https://flexboxfroggy.com/", cls=AT.muted),
838
+ " to get an understanding of flex box.",
839
+ cls=TextPresets.muted_sm),
840
+ DivFullySpaced,
841
+ fn2code_string(ex_fully_spaced_div),
842
+ DivCentered,
843
+ fn2code_string(ex_centered_div),
844
+ DivLAligned,
845
+ fn2code_string(ex_l_aligned_div),
846
+ DivRAligned,
847
+ fn2code_string(ex_r_aligned_div),
848
+ DivVStacked,
849
+ fn2code_string(ex_v_stacked_div),
850
+ DivHStacked,
851
+ fn2code_string(ex_h_stacked_div),
852
+ FlexT,
853
+ title="Layout")
854
+
855
+ # Dividers
856
+
857
+ def ex_dividers():
858
+ return Div(
859
+ P("Small Divider"),
860
+ Divider(cls=DividerT.sm),
861
+ DivCentered(
862
+ P("Vertical Divider"),
863
+ Divider(cls=DividerT.vertical)),
864
+ DivCentered("Icon Divider"),
865
+ Divider(cls=DividerT.icon))
866
+
867
+ def ex_dividersplit():
868
+ return DividerSplit(P("Or continue with", cls=TextPresets.muted_sm))
869
+
870
+ def ex_dividerline():
871
+ return DividerLine()
872
+
873
+ docs_dividers = create_doc_section(
874
+ H1("Dividers API Reference"),
875
+ Divider,
876
+ DividerT,
877
+ fn2code_string(ex_dividers),
878
+ DividerSplit,
879
+ fn2code_string(ex_dividersplit),
880
+ DividerLine,
881
+ fn2code_string(ex_dividerline),
882
+ title="Dividers")
883
+
884
+ # Navigation
885
+
886
+ def ex_nav1():
887
+ mbrs1 = [Li(A('Option 1'), cls='uk-active'), Li(A('Option 2')), Li(A('Option 3'))]
888
+ return NavContainer(*mbrs1)
889
+
890
+ def ex_nav2():
891
+ mbrs1 = [Li(A('Option 1'), cls='uk-active'), Li(A('Option 2')), Li(A('Option 3'))]
892
+ mbrs2 = [Li(A('Child 1')), Li(A('Child 2')),Li(A('Child 3'))]
893
+
894
+ return NavContainer(
895
+ NavHeaderLi("NavHeaderLi"),
896
+ *mbrs1,
897
+ Li(A(href='')(Div("Subtitle Ex",NavSubtitle("NavSubtitle text to be shown")))),
898
+ NavDividerLi(),
899
+ NavParentLi(
900
+ A('Parent Name'),
901
+ NavContainer(*mbrs2,parent=False),
902
+ ),
903
+ )
904
+
905
+ def ex_navbar1():
906
+ return NavBar(A("Page1",href='/rt1'),
907
+ A("Page2",href='/rt2'),
908
+ A("Page3",href='/rt3'),
909
+ brand=H3('My Blog'))
910
+
911
+ def ex_navbar2():
912
+ return NavBar(
913
+ A(Input(placeholder='search')),
914
+ A(UkIcon("rocket")),
915
+ A('Page1',href='/rt1'),
916
+ A("Page2", href='/rt3'),
917
+ brand=DivLAligned(Img(src='/api_reference/logo.svg'),UkIcon('rocket',height=30,width=30)))
918
+
919
+ def ex_navdrop():
920
+ return Div(
921
+ Button("Open DropDown"),
922
+ DropDownNavContainer(Li(A("Item 1",href=''),Li(A("Item 2",href='')))))
923
+
924
+ def ex_tabs1():
925
+ return Container(
926
+ TabContainer(
927
+ Li(A("Active",href='#', cls='uk-active')),
928
+ Li(A("Item",href='#')),
929
+ Li(A("Item",href='#')),
930
+ Li(A("Disabled",href='#', cls='uk-disabled')),
931
+ uk_switcher='connect: #component-nav; animation: uk-animation-fade',
932
+ alt=True),
933
+ Ul(id="component-nav", cls="uk-switcher")(
934
+ Li(H1("Tab 1")),
935
+ Li(H1("Tab 2")),
936
+ Li(H1("Tab 3"))))
937
+
938
+ def ex_tabs2():
939
+ return Container(
940
+ TabContainer(
941
+ Li(A("Active",href='javascript:void(0);', cls='uk-active')),
942
+ Li(A("Item",href='javascript:void(0);')),
943
+ Li(A("Item",href='javascript:void(0);')),
944
+ Li(A("Disabled", cls='uk-disabled'))))
945
+
946
+ docs_navigation = create_doc_section(
947
+ H1("Navigation (Nav, NavBar, Tabs, etc.) API Reference"),
948
+ H1("Nav, NavBar, DowDownNav, and Tab examples"),
949
+ Divider(),
950
+ H2("Nav"),
951
+ fn2code_string(ex_nav1),
952
+ fn2code_string(ex_nav2),
953
+ H2("Navbars", id='navbars'),
954
+ "Fully responsive simple navbar using the high level API. This will collapse to a hamburger menu on mobile devices. See the Scrollspy example for a more complex navbar example.",
955
+ fn2code_string(ex_navbar1),
956
+ fn2code_string(ex_navbar2),
957
+ H2("Drop Down Navs"),
958
+ fn2code_string(ex_navdrop),
959
+ H2("Tabs"),
960
+ fn2code_string(ex_tabs2),
961
+ P("A tabs can use any method of navigation (htmx, or href). However, often these are use in conjunction with switchers do to this client side", cls=TextPresets.muted_sm),
962
+ fn2code_string(ex_tabs1),
963
+ H1("API Docs"),
964
+ NavBar,
965
+ TabContainer,
966
+ NavContainer,
967
+ NavT,
968
+ NavCloseLi,
969
+ NavSubtitle,
970
+ NavHeaderLi,
971
+ NavDividerLi,
972
+ NavParentLi,
973
+ DropDownNavContainer,
974
+ title="Navigation")
975
+
976
+ # Steps
977
+
978
+
979
+ def ex_steps2():
980
+ return Steps(
981
+ LiStep("Account Created", cls=StepT.primary),
982
+ LiStep("Profile Setup", cls=StepT.neutral),
983
+ LiStep("Verification", cls=StepT.neutral),
984
+ cls="w-full")
985
+ def ex_steps3():
986
+ return Steps(
987
+ LiStep("Project Planning", cls=StepT.success, data_content="📝"),
988
+ LiStep("Design Phase", cls=StepT.success, data_content="💡"),
989
+ LiStep("Development", cls=StepT.primary, data_content="🛠️"),
990
+ LiStep("Testing", cls=StepT.neutral, data_content="🔎"),
991
+ LiStep("Deployment", cls=StepT.neutral, data_content="🚀"),
992
+ cls=(StepsT.vertical, "min-h-[400px]"))
993
+
994
+ docs_steps = create_doc_section(
995
+ H1("Steps API Reference"),
996
+ fn2code_string(ex_steps2),
997
+ fn2code_string(ex_steps3),
998
+ H1("API Docs"),
999
+ Steps,
1000
+ StepsT,
1001
+ LiStep,
1002
+ StepT,
1003
+ title="Steps")
1004
+ # Tables
1005
+
1006
+ def ex_tables0():
1007
+ return Table(
1008
+ Thead(Tr(Th('Name'), Th('Age'), Th('City'))),
1009
+ Tbody(Tr(Td('Alice'), Td('25'), Td('New York')),
1010
+ Tr(Td('Bob'), Td('30'), Td('San Francisco')),
1011
+ Tr(Td('Charlie'), Td('35'), Td('London'))),
1012
+ Tfoot(Tr(Td('Total'), Td('90'))))
1013
+
1014
+ def ex_tables1():
1015
+ header = ['Name', 'Age', 'City']
1016
+ body = [['Alice', '25', 'New York'],
1017
+ ['Bob', '30', 'San Francisco'],
1018
+ ['Charlie', '35', 'London']]
1019
+ footer = ['Total', '90']
1020
+ return TableFromLists(header, body, footer)
1021
+
1022
+ def ex_tables2():
1023
+ def body_render(k, v):
1024
+ match k.lower():
1025
+ case 'name': return Td(v, cls='font-bold')
1026
+ case 'age': return Td(f"{v} years")
1027
+ case _: return Td(v)
1028
+
1029
+ header_data = ['Name', 'Age', 'City']
1030
+ body_data =[{'Name': 'Alice', 'Age': 30, 'City': 'New York'},
1031
+ {'Name': 'Bob', 'Age': 25, 'City': 'London'}]
1032
+
1033
+ return TableFromDicts(header_data, body_data,
1034
+ header_cell_render=lambda v: Th(v.upper()),
1035
+ body_cell_render=body_render)
1036
+
1037
+ docs_tables = create_doc_section(
1038
+ H1("Tables API Reference"),
1039
+ fn2code_string(ex_tables0),
1040
+ fn2code_string(ex_tables1),
1041
+ fn2code_string(ex_tables2),
1042
+ Table,
1043
+ TableFromLists,
1044
+ TableFromDicts,
1045
+ TableT,
1046
+ Tbody,
1047
+ Th,
1048
+ Td,
1049
+ title="Tables")
1050
+
1051
+ # Icons
1052
+
1053
+ def ex_dicebear():
1054
+ return DivLAligned(
1055
+ DiceBearAvatar('Isaac Flath',10,10),
1056
+ DiceBearAvatar('Aaliyah',10,10),
1057
+ DiceBearAvatar('Alyssa',10,10))
1058
+
1059
+ def ex_picsum():
1060
+ return Grid(PicSumImg(100,100), PicSumImg(100,100, blur=6),PicSumImg(100,100, grayscale=True))
1061
+
1062
+ def ex_icon():
1063
+ return Grid(
1064
+ UkIcon('chevrons-right', height=15, width=15),
1065
+ UkIcon('bug', height=15, width=15),
1066
+ UkIcon('phone-call', height=15, width=15),
1067
+ UkIcon('maximize-2', height=15, width=15),
1068
+ UkIcon('thumbs-up', height=15, width=15),)
1069
+
1070
+ def ex_iconlink():
1071
+ return DivLAligned(
1072
+ UkIconLink('chevrons-right'),
1073
+ UkIconLink('chevrons-right', button=True, cls=ButtonT.primary))
1074
+
1075
+ docs_icons_images = create_doc_section(
1076
+ H1("Icons & Images API Reference"),
1077
+ H1("Avatars"),
1078
+ fn2code_string(ex_dicebear),
1079
+ DiceBearAvatar,
1080
+ H1("PlaceHolder Images"),
1081
+ fn2code_string(ex_picsum),
1082
+ PicSumImg,
1083
+ H1("Icons"),
1084
+ P("Icons use Lucide icons - you can find a full list of icons in their docs.", cls=TextPresets.muted_sm),
1085
+ fn2code_string(ex_icon),
1086
+ UkIcon,
1087
+ fn2code_string(ex_iconlink),
1088
+ UkIconLink,
1089
+ title="Icons")
1090
+
1091
+ # Markdown
1092
+
1093
+ def ex_markdown():
1094
+ md = '''# Example Markdown
1095
+
1096
+ + With **bold** and *italics*
1097
+ + With a [link](https://github.com)
1098
+
1099
+ ### And a subheading
1100
+
1101
+ > This is a blockquote
1102
+
1103
+ This supports inline latex: $e^{\\pi i} + 1 = 0$ as well as block latex thanks to Katex.
1104
+
1105
+ $$
1106
+ \\frac{1}{2\\pi i} \\oint_C \\frac{f(z)}{z-z_0} dz
1107
+ $$
1108
+
1109
+ And even syntax highlighting thanks to Highlight.js! (Just make sure you set `highlightjs=True` in the headers function)
1110
+
1111
+ ```python
1112
+ def add(a, b):
1113
+ return a + b
1114
+ ```
1115
+ '''
1116
+ return render_md(md)
1117
+
1118
+ def ex_markdown2():
1119
+ md = '''With custom **bold** style\n\n > But no extra quote style because class_map overrides all default styled'''
1120
+ return render_md(md, class_map={'b': 'text-red-500'})
1121
+
1122
+ def ex_markdown3():
1123
+ md = '''With custom **bold** style\n\n > But default quote style because class_map_mods replaces sepecified styles and leaves the rest as default'''
1124
+ return render_md(md, class_map_mods={'b': 'text-red-500'})
1125
+
1126
+ def ex_applyclasses():
1127
+ return apply_classes('<h1>Hello, World!</h1><p>This is a paragraph</p>')
1128
+
1129
+ def ex_applyclasses2():
1130
+ from mistletoe import markdown, HTMLRenderer
1131
+ md = markdown('# Hi\n[a link](www.google.com)', renderer=HTMLRenderer)
1132
+ return Safe(apply_classes(md))
1133
+
1134
+ docs_markdown = create_doc_section(
1135
+ H1("Markdown + automated HTML styling API Reference"),
1136
+ fn2code_string(ex_markdown),
1137
+ render_md("You can overwrite the default styling for markdown rendering with your own css classes with `class_map"),
1138
+ fn2code_string(ex_markdown2),
1139
+ render_md("You can modify the default styling for markdown rendering with your own css classes with `class_map_mods"),
1140
+ fn2code_string(ex_markdown3),
1141
+ render_md("This uses the `apply_classes` function, which can be used to apply classes to html strings. This is useful for applying styles to any html you get from an external source."),
1142
+ fn2code_string(ex_applyclasses),
1143
+ render_md("One common external source is a markdown renderer. MonsterUI uses tailwind css for styling so you don't get any styling without specifying classes, `apply_classes` can do that for you."),
1144
+ fn2code_string(ex_applyclasses2),
1145
+ apply_classes,
1146
+ title="Markdown + HTML Frankification")
1147
+
1148
+
1149
+ docs_html = create_doc_section(
1150
+ H1("HTML Styling API Reference"),
1151
+ fn2code_string(ex_applyclasses),
1152
+ title="HTML Styling")
1153
+
1154
+ def ex_loading1():
1155
+ return Loading()
1156
+
1157
+ def ex_loading2():
1158
+ types = [LoadingT.spinner, LoadingT.dots, LoadingT.ring, LoadingT.ball, LoadingT.bars, LoadingT.infinity]
1159
+ sizes = [LoadingT.xs, LoadingT.sm, LoadingT.md, LoadingT.lg]
1160
+ rows = [Div(*[Loading((t,s)) for s in sizes], cls='flex gap-4') for t in types]
1161
+ return Div(*rows, cls='flex flex-col gap-4')
1162
+
1163
+ docs_loading = create_doc_section(
1164
+ H1("Loading Indicators API Reference"),
1165
+ fn2code_string(ex_loading1),
1166
+ fn2code_string(ex_loading2),
1167
+ Loading,
1168
+ LoadingT,
1169
+ title="Loading")
1170
+
1171
+
1172
+ # Charts
1173
+ def ex_line_chart():
1174
+ return ApexChart(
1175
+ opts={
1176
+ "chart": {"type":"line", "zoom":{"enabled": False}, "toolbar":{"show":False}},
1177
+ "series": [{"name":"Desktops", "data": [186, 305, 237, 73, 209, 214, 355]}],
1178
+ "xaxis": {"categories":["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"]}
1179
+ },
1180
+ cls='max-w-md max-h-md'
1181
+ )
1182
+
1183
+ def ex_pie_chart():
1184
+ return ApexChart(
1185
+ opts={
1186
+ "chart": {"type":"pie", "zoom":{"enabled": False}, "toolbar":{"show":False}},
1187
+ "series": [186, 305, 237, 73, 209, 214, 355],
1188
+ "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"]
1189
+ },
1190
+ cls='max-w-md max-h-md'
1191
+ )
1192
+
1193
+ docs_charts = create_doc_section(
1194
+ H1("Charts API Reference"),
1195
+ P(
1196
+ "MonsterUI supports ", A("ApexCharts", href="https://apexcharts.com/", cls='underline'),
1197
+ ", a javascript library for rendering different charts like line and pie charts. ",
1198
+ "See the full list of chart types ", A("here.", href="https://apexcharts.com/javascript-chart-demos/", cls='underline'),
1199
+ ),
1200
+ P("To render a chart you'll need to include the ApexChart js in your app headers like this"),
1201
+ CodeSpan("app, rt = fast_app(hdrs=Theme.blue.headers(apex_charts=True))"),
1202
+ P("Then create an " , CodeSpan("ApexChart"), " component as shown in the examples below."),
1203
+ P("Generally, you should be able to take any chart from the ApexChart docs, convert the chart's options var to a python dict and plug it straight into MonsterUI's ApexChart component."),
1204
+ H2("Example usage", cls="mt-4"),
1205
+ H4("Line chart", cls="mt-4"),
1206
+ fn2code_string(ex_line_chart),
1207
+ H4("Pie chart", cls="mt-4"),
1208
+ fn2code_string(ex_pie_chart),
1209
+ ApexChart,
1210
+ title="Charts"
1211
+ )
MonsterUI/docs/api_reference/logo.svg ADDED
MonsterUI/docs/apilist.txt ADDED
@@ -0,0 +1,520 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # monsterui Module Documentation
2
+
3
+ ## monsterui.core
4
+
5
+ - `class ThemeRadii(Enum)`
6
+ Members: none, sm, md, lg
7
+
8
+
9
+ - `class ThemeShadows`
10
+
11
+ - `class ThemeFont`
12
+
13
+ - `class Theme(Enum)`
14
+ Selector to choose theme and get all headers needed for app. Includes frankenui + tailwind + daisyui + highlight.js options
15
+ Members: slate, stone, gray, neutral, red, rose, orange, green, blue, yellow, violet, zinc
16
+
17
+ - `headers(self, mode, icons, daisy, highlightjs, katex, apex_charts, radii, shadows, font)`
18
+ Create frankenui and tailwind cdns
19
+
20
+ - `local_headers(self, mode, static_dir, icons, daisy, highlightjs, katex, apex_charts, radii, shadows, font)`
21
+ Create headers using local files downloaded from CDNs
22
+
23
+
24
+ ## monsterui.daisy
25
+
26
+ - `class AlertT(Enum)`
27
+ Alert styles from DaisyUI
28
+ Members: info, success, warning, error
29
+
30
+
31
+ - `def Alert(*c, **kwargs)`
32
+ Alert informs users about important events.
33
+
34
+ - `class StepsT(Enum)`
35
+ Options for Steps
36
+ Members: vertical, horizonal
37
+
38
+
39
+ - `class StepT(Enum)`
40
+ Step styles for LiStep
41
+ Members: primary, secondary, accent, info, success, warning, error, neutral
42
+
43
+
44
+ - `def Steps(*li, **kwargs)`
45
+ Creates a steps container
46
+
47
+ - `def LiStep(*c, **kwargs)`
48
+ Creates a step list item
49
+
50
+ - `class LoadingT(Enum)`
51
+ Members: spinner, dots, ring, ball, bars, infinity, xs, sm, md, lg
52
+
53
+
54
+ - `def Loading(cls, htmx_indicator, **kwargs)`
55
+ Creates a loading animation component
56
+
57
+ - `class ToastHT(Enum)`
58
+ Horizontal position for Toast
59
+ Members: start, center, end
60
+
61
+
62
+ - `class ToastVT(Enum)`
63
+ Vertical position for Toast
64
+ Members: top, middle, bottom
65
+
66
+
67
+ ## monsterui.foundations
68
+
69
+ > Data Structures and Utilties
70
+
71
+ - `def stringify(o)`
72
+ Converts input types into strings that can be passed to FT components
73
+
74
+ - `class VEnum(Enum)`
75
+ Members:
76
+
77
+ - `__str__(self)`
78
+ - `__add__(self, other)`
79
+ - `__radd__(self, other)`
80
+
81
+ ## monsterui.franken
82
+
83
+ - `class TextT(Enum)`
84
+ Text Styles from https://franken-ui.dev/docs/text
85
+ Members: paragraph, lead, meta, gray, italic, xs, sm, lg, xl, light, normal, medium, bold, extrabold, muted, primary, secondary, success, warning, error, info, left, right, center, justify, start, end, top, middle, bottom, truncate, break_, nowrap, underline, highlight
86
+
87
+
88
+ - `class TextPresets(Enum)`
89
+ Common Typography Presets
90
+ Members: muted_sm, muted_lg, bold_sm, bold_lg, md_weight_sm, md_weight_muted
91
+
92
+
93
+ - `def CodeSpan(*c, **kwargs)`
94
+ A CodeSpan with Styling
95
+
96
+ - `def CodeBlock(*c, **kwargs)`
97
+ CodeBlock with Styling
98
+
99
+ - `def H1(*c, **kwargs)`
100
+ H1 with styling and appropriate size
101
+
102
+ - `def H2(*c, **kwargs)`
103
+ H2 with styling and appropriate size
104
+
105
+ - `def H3(*c, **kwargs)`
106
+ H3 with styling and appropriate size
107
+
108
+ - `def H4(*c, **kwargs)`
109
+ H4 with styling and appropriate size
110
+
111
+ - `def H5(*c, **kwargs)`
112
+ H5 with styling and appropriate size
113
+
114
+ - `def H6(*c, **kwargs)`
115
+ H6 with styling and appropriate size
116
+
117
+ - `def Subtitle(*c, **kwargs)`
118
+ Styled muted_sm text designed to go under Headings and Titles
119
+
120
+ - `def Q(*c, **kwargs)`
121
+ Styled quotation mark
122
+
123
+ - `def Em(*c, **kwargs)`
124
+ Styled emphasis text
125
+
126
+ - `def Strong(*c, **kwargs)`
127
+ Styled strong text
128
+
129
+ - `def I(*c, **kwargs)`
130
+ Styled italic text
131
+
132
+ - `def Small(*c, **kwargs)`
133
+ Styled small text
134
+
135
+ - `def Mark(*c, **kwargs)`
136
+ Styled highlighted text
137
+
138
+ - `def Del(*c, **kwargs)`
139
+ Styled deleted text
140
+
141
+ - `def Ins(*c, **kwargs)`
142
+ Styled inserted text
143
+
144
+ - `def Sub(*c, **kwargs)`
145
+ Styled subscript text
146
+
147
+ - `def Sup(*c, **kwargs)`
148
+ Styled superscript text
149
+
150
+ - `def Blockquote(*c, **kwargs)`
151
+ Blockquote with Styling
152
+
153
+ - `def Caption(*c, **kwargs)`
154
+ Styled caption text
155
+
156
+ - `def Cite(*c, **kwargs)`
157
+ Styled citation text
158
+
159
+ - `def Time(*c, **kwargs)`
160
+ Styled time element
161
+
162
+ - `def Address(*c, **kwargs)`
163
+ Styled address element
164
+
165
+ - `def Abbr(*c, **kwargs)`
166
+ Styled abbreviation with dotted underline
167
+
168
+ - `def Dfn(*c, **kwargs)`
169
+ Styled definition term with italic and medium weight
170
+
171
+ - `def Kbd(*c, **kwargs)`
172
+ Styled keyboard input with subtle background
173
+
174
+ - `def Samp(*c, **kwargs)`
175
+ Styled sample output with subtle background
176
+
177
+ - `def Var(*c, **kwargs)`
178
+ Styled variable with italic monospace
179
+
180
+ - `def Figure(*c, **kwargs)`
181
+ Styled figure container with card-like appearance
182
+
183
+ - `def Details(*c, **kwargs)`
184
+ Styled details element
185
+
186
+ - `def Summary(*c, **kwargs)`
187
+ Styled summary element
188
+
189
+ - `def Data(*c, **kwargs)`
190
+ Styled data element
191
+
192
+ - `def Meter(*c, **kwargs)`
193
+ Styled meter element
194
+
195
+ - `def S(*c, **kwargs)`
196
+ Styled strikethrough text (different semantic meaning from Del)
197
+
198
+ - `def U(*c, **kwargs)`
199
+ Styled underline (for proper names in Chinese, proper spelling etc)
200
+
201
+ - `def Output(*c, **kwargs)`
202
+ Styled output element for form results
203
+
204
+ - `def PicSumImg(h, w, id, grayscale, blur, **kwargs)`
205
+ Creates a placeholder image using https://picsum.photos/
206
+
207
+ - `def AccordionItem(title, *c)`
208
+ Creates a single item for use within an Accordion component, handling title, content, and open state.
209
+
210
+ - `def Accordion(*c, **kwargs)`
211
+ Creates a styled Accordion container using accordion component.
212
+
213
+ - `class ButtonT(Enum)`
214
+ Options for styling Buttons
215
+ Members: default, ghost, primary, secondary, destructive, text, link, xs, sm, lg, xl, icon
216
+
217
+
218
+ - `def Button(*c, **kwargs)`
219
+ Button with Styling (defaults to `submit` for form submission)
220
+
221
+ - `class ContainerT(Enum)`
222
+ Max width container sizes from https://franken-ui.dev/docs/container
223
+ Members: xs, sm, lg, xl, expand
224
+
225
+
226
+ - `class BackgroundT(Enum)`
227
+ Members: muted, primary, secondary, default
228
+
229
+
230
+ - `def Container(*c, **kwargs)`
231
+ Div to be used as a container that often wraps large sections or a page of content
232
+
233
+ - `def Titled(title, *c, **kwargs)`
234
+ Creates a standard page structure for titled page. Main(Container(title, content))
235
+
236
+ - `class DividerT(Enum)`
237
+ Divider Styles from https://franken-ui.dev/docs/divider
238
+ Members: icon, sm, vertical
239
+
240
+
241
+ - `def Divider(*c, **kwargs)`
242
+ Divider with default styling and margin
243
+
244
+ - `def DividerSplit(*c)`
245
+ Creates a simple horizontal line divider with configurable thickness and vertical spacing
246
+
247
+ - `def Article(*c, **kwargs)`
248
+ A styled article container for blog posts or similar content
249
+
250
+ - `def ArticleTitle(*c, **kwargs)`
251
+ A title component for use within an Article
252
+
253
+ - `def ArticleMeta(*c, **kwargs)`
254
+ A metadata component for use within an Article showing things like date, author etc
255
+
256
+ - `class SectionT(Enum)`
257
+ Section styles from https://franken-ui.dev/docs/section
258
+ Members: default, muted, primary, secondary, xs, sm, lg, xl, remove_vertical
259
+
260
+
261
+ - `def Section(*c, **kwargs)`
262
+ Section with styling and margins
263
+
264
+ - `def Form(*c, **kwargs)`
265
+ A Form with default spacing between form elements
266
+
267
+ - `def Fieldset(*c, **kwargs)`
268
+ A Fieldset with default styling
269
+
270
+ - `def Legend(*c, **kwargs)`
271
+ A Legend with default styling
272
+
273
+ - `def Input(*c, **kwargs)`
274
+ An Input with default styling
275
+
276
+ - `def Radio(*c, **kwargs)`
277
+ A Radio with default styling
278
+
279
+ - `def CheckboxX(*c, **kwargs)`
280
+ A Checkbox with default styling
281
+
282
+ - `def Range(*c, **kwargs)`
283
+ A Range with default styling
284
+
285
+ - `def TextArea(*c, **kwargs)`
286
+ A Textarea with default styling
287
+
288
+ - `def Switch(*c, **kwargs)`
289
+ A Switch with default styling
290
+
291
+ - `def Upload(*c, **kwargs)`
292
+ A file upload component with default styling
293
+
294
+ - `def UploadZone(*c, **kwargs)`
295
+ A file drop zone component with default styling
296
+
297
+ - `def FormLabel(*c, **kwargs)`
298
+ A Label with default styling
299
+
300
+ - `class LabelT(Enum)`
301
+ Members: primary, secondary, destructive
302
+
303
+
304
+ - `def Label(*c, **kwargs)`
305
+ FrankenUI labels, which look like pills
306
+
307
+ - `def UkFormSection(title, description, *c)`
308
+ A form section with a title, description and optional button
309
+
310
+ - `def GenericLabelInput(label, lbl_cls, input_cls, container, cls, id, input_fn, **kwargs)`
311
+ `Div(Label,Input)` component with Uk styling injected appropriately. Generally you should higher level API, such as `LabelInput` which is created for you in this library
312
+
313
+ - `def LabelInput(label, lbl_cls, input_cls, cls, id, **kwargs)`
314
+ A `FormLabel` and `Input` pair that provides default spacing and links/names them based on id
315
+
316
+ - `def LabelRadio(label, lbl_cls, input_cls, container, cls, id, **kwargs)`
317
+ A FormLabel and Radio pair that provides default spacing and links/names them based on id
318
+
319
+ - `def LabelCheckboxX(label, lbl_cls, input_cls, container, cls, id, **kwargs)`
320
+ A FormLabel and CheckboxX pair that provides default spacing and links/names them based on id
321
+
322
+ - `def Options(*c)`
323
+ Helper function to wrap things into `Option`s for use in `Select`
324
+
325
+ - `def Select(*option, **kwargs)`
326
+ Creates a select dropdown with uk styling and option for adding a search box
327
+
328
+ - `def LabelSelect(*option, **kwargs)`
329
+ A FormLabel and Select pair that provides default spacing and links/names them based on id
330
+
331
+ - `@delegates(GenericLabelInput, but=['input_fn', 'cls']) def LabelRange(label, lbl_cls, input_cls, cls, id, value, min, max, step, label_range, **kwargs)`
332
+ A FormLabel and Range pair that provides default spacing and links/names them based on id
333
+
334
+ - `class AT(Enum)`
335
+ Link styles from https://franken-ui.dev/docs/link
336
+ Members: muted, text, reset, primary, classic
337
+
338
+
339
+ - `class ListT(Enum)`
340
+ List styles using Tailwind CSS
341
+ Members: disc, circle, square, decimal, hyphen, bullet, divider, striped
342
+
343
+
344
+ - `def ModalContainer(*c, **kwargs)`
345
+ Creates a modal container that components go in
346
+
347
+ - `def ModalDialog(*c, **kwargs)`
348
+ Creates a modal dialog
349
+
350
+ - `def ModalHeader(*c, **kwargs)`
351
+ Creates a modal header
352
+
353
+ - `def ModalBody(*c, **kwargs)`
354
+ Creates a modal body
355
+
356
+ - `def ModalFooter(*c, **kwargs)`
357
+ Creates a modal footer
358
+
359
+ - `def ModalTitle(*c, **kwargs)`
360
+ Creates a modal title
361
+
362
+ - `def ModalCloseButton(*c, **kwargs)`
363
+ Creates a button that closes a modal with js
364
+
365
+ - `def Modal(*c, **kwargs)`
366
+ Creates a modal with the appropriate classes to put the boilerplate in the appropriate places for you
367
+
368
+ - `def Placeholder(*c, **kwargs)`
369
+ Creates a placeholder
370
+
371
+ - `def Progress(*c, **kwargs)`
372
+ Creates a progress bar
373
+
374
+ - `def UkIcon(icon, height, width, stroke_width, cls, **kwargs)`
375
+ Creates an icon using lucide icons
376
+
377
+ - `def UkIconLink(icon, height, width, stroke_width, cls, button, **kwargs)`
378
+ Creates an icon link using lucide icons
379
+
380
+ - `def DiceBearAvatar(seed_name, h, w)`
381
+ Creates an Avatar using https://dicebear.com/
382
+
383
+ - `def Center(*c, **kwargs)`
384
+ Centers contents both vertically and horizontally by default
385
+
386
+ - `class FlexT(Enum)`
387
+ Flexbox modifiers using Tailwind CSS
388
+ Members: block, inline, left, center, right, between, around, stretch, top, middle, bottom, row, row_reverse, column, column_reverse, nowrap, wrap, wrap_reverse
389
+
390
+
391
+ - `def Grid(*div, **kwargs)`
392
+ Creates a responsive grid layout with smart defaults based on content
393
+
394
+ - `def DivFullySpaced(*c, **kwargs)`
395
+ Creates a flex div with it's components having as much space between them as possible
396
+
397
+ - `def DivCentered(*c, **kwargs)`
398
+ Creates a flex div with it's components centered in it
399
+
400
+ - `def DivLAligned(*c, **kwargs)`
401
+ Creates a flex div with it's components aligned to the left
402
+
403
+ - `def DivRAligned(*c, **kwargs)`
404
+ Creates a flex div with it's components aligned to the right
405
+
406
+ - `def DivVStacked(*c, **kwargs)`
407
+ Creates a flex div with it's components stacked vertically
408
+
409
+ - `def DivHStacked(*c, **kwargs)`
410
+ Creates a flex div with it's components stacked horizontally
411
+
412
+ - `class NavT(Enum)`
413
+ Members: default, primary, secondary
414
+
415
+
416
+ - `def NavContainer(*li, **kwargs)`
417
+ Creates a navigation container (useful for creating a sidebar navigation). A Nav is a list (NavBar is something different)
418
+
419
+ - `def NavParentLi(*nav_container, **kwargs)`
420
+ Creates a navigation list item with a parent nav for nesting
421
+
422
+ - `def NavDividerLi(*c, **kwargs)`
423
+ Creates a navigation list item with a divider
424
+
425
+ - `def NavHeaderLi(*c, **kwargs)`
426
+ Creates a navigation list item with a header
427
+
428
+ - `def NavSubtitle(*c, **kwargs)`
429
+ Creates a navigation subtitle
430
+
431
+ - `def NavCloseLi(*c, **kwargs)`
432
+ Creates a navigation list item with a close button
433
+
434
+ - `class ScrollspyT(Enum)`
435
+ Members: underline, bold
436
+
437
+
438
+ - `def NavBar(*c)`
439
+ Creates a responsive navigation bar with mobile menu support
440
+
441
+ - `def SliderContainer(*c, **kwargs)`
442
+ Creates a slider container
443
+
444
+ - `def SliderItems(*c, **kwargs)`
445
+ Creates a slider items container
446
+
447
+ - `def SliderNav(cls, prev_cls, next_cls, **kwargs)`
448
+ Navigation arrows for Slider component
449
+
450
+ - `def Slider(*c, **kwargs)`
451
+ Creates a slider with optional navigation arrows
452
+
453
+ - `def DropDownNavContainer(*li, **kwargs)`
454
+ A Nav that is part of a DropDown
455
+
456
+ - `def TabContainer(*li, **kwargs)`
457
+ A TabContainer where children will be different tabs
458
+
459
+ - `class CardT(Enum)`
460
+ Card styles from UIkit
461
+ Members: default, primary, secondary, destructive, hover
462
+
463
+
464
+ - `def CardTitle(*c, **kwargs)`
465
+ Creates a card title
466
+
467
+ - `def CardHeader(*c, **kwargs)`
468
+ Creates a card header
469
+
470
+ - `def CardBody(*c, **kwargs)`
471
+ Creates a card body
472
+
473
+ - `def CardFooter(*c, **kwargs)`
474
+ Creates a card footer
475
+
476
+ - `def CardContainer(*c, **kwargs)`
477
+ Creates a card container
478
+
479
+ - `def Card(*c, **kwargs)`
480
+ Creates a Card with a header, body, and footer
481
+
482
+ - `class TableT(Enum)`
483
+ Members: divider, striped, hover, sm, lg, justify, middle, responsive
484
+
485
+
486
+ - `def Table(*c, **kwargs)`
487
+ Creates a table
488
+
489
+ - `def TableFromLists(header_data, body_data, footer_data, header_cell_render, body_cell_render, footer_cell_render, cls, sortable, **kwargs)`
490
+ Creates a Table from a list of header data and a list of lists of body data
491
+
492
+ - `def TableFromDicts(header_data, body_data, footer_data, header_cell_render, body_cell_render, footer_cell_render, cls, sortable, **kwargs)`
493
+ Creates a Table from a list of header data and a list of dicts of body data
494
+
495
+ - `def apply_classes(html_str, class_map, class_map_mods)`
496
+ Apply classes to html string
497
+
498
+ - `class FrankenRenderer`
499
+ Custom renderer for Franken UI that handles image paths
500
+
501
+ - `def __init__(self, *args, **kwargs)`
502
+ - `def render_image(self, token)`
503
+ Modify image paths if they're relative and self.img_dir is specified
504
+
505
+
506
+ - `def render_md(md_content, class_map, class_map_mods, img_dir, renderer)`
507
+ Renders markdown using mistletoe and lxml with custom image handling
508
+
509
+ - `def ThemePicker(color, radii, shadows, font, mode, cls, custom_themes)`
510
+ Theme picker component with configurable sections
511
+
512
+ - `def LightboxContainer(*lightboxitem, **kwargs)`
513
+ Lightbox container that will hold `LightboxItems`
514
+
515
+ - `def LightboxItem(*c, **kwargs)`
516
+ Anchor tag with appropriate structure to go inside a `LightBoxContainer`
517
+
518
+ - `def ApexChart(**kws)`
519
+ Apex chart component
520
+
MonsterUI/docs/cf_addns.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # https://github.com/cloudflare/cloudflare-python/blob/main/api.md
3
+ from fastcore.script import *
4
+ from cloudflare import Cloudflare
5
+
6
+ @call_parse
7
+ def add_dns_record(
8
+ record_type: str, # Type of DNS record (CNAME or A)
9
+ target: str, # Target IP address or domain name
10
+ record: str, # Record name (without the zone)
11
+ zone: str, # Zone name
12
+ proxied: bool_arg=True # Use CF proxy?
13
+ ):
14
+ cf = Cloudflare()
15
+ zones = cf.zones.list(name=zone)
16
+ if not zones: raise ValueError(f"Zone '{zone}' not found")
17
+ zid = zones.result[0].id
18
+ cf.dns.records.create(zone_id=zid, type=record_type.upper(), name=f"{record}.{zone}", content=target, proxied=proxied)
MonsterUI/docs/createllms.sh ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+
3
+ from fastcore.utils import *
4
+ import httpx
5
+ import api_reference.api_reference as api_reference
6
+ def fname2title(ref_fn_name): return ref_fn_name[5:].replace('_',' | ').title()
7
+
8
+ def create_llms_txt():
9
+ # Get examples
10
+ base = "https://monsterui.answer.ai"
11
+ examples = [f for f in Path('examples').glob('*.py') if not f.name.startswith('__') and f.name.endswith('.py')]
12
+ example_links = []
13
+ for f in examples:
14
+ content = httpx.get(f"{base}/{f.stem}/md").text
15
+ first_line = content.split('\n')[0].strip('# ').strip('"')
16
+ example_links.append(f"[{f.stem.title()}]({base}/{f.name[:-3]}/md): {first_line}")
17
+
18
+ # Get reference files with their H1 headings
19
+ reference_fns = L([o for o in dir(api_reference) if o.startswith('docs_')])
20
+ api_links = []
21
+ for f in reference_fns:
22
+ content = httpx.get(f"{base}/api_ref/{f}/md").text
23
+ first_heading = content.split('\n')[0].strip('# ')
24
+ api_links.append(f"[{fname2title(f)}]({base}/api_ref/{f}/md): {first_heading}")
25
+
26
+ # Create content
27
+ content = [
28
+ "# MonsterUI Documentation",
29
+ '''
30
+ > MonsterUI is a python library which brings styling to python for FastHTML apps.
31
+
32
+ '''
33
+ "## API Reference",
34
+ '- [API List](https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/apilist.txt): Complete API Reference',
35
+ "",
36
+ "## Examples",
37
+ *[f'- {a}' for a in example_links],
38
+ "",
39
+ "## Optional",
40
+ *[f'- {a}' for a in api_links],
41
+ "- [Layout](https://monsterui.answer.ai/tutorial_layout/md): MonsterUI Page Layout Guide",
42
+ "- [Spacing](https://monsterui.answer.ai/tutorial_spacing/md): Padding & Margin & Spacing, Oh my! (MonsterUI Spacing Guide)",
43
+ ]
44
+
45
+ # Write to file
46
+ Path('llms.txt').write_text('\n'.join(content))
47
+
48
+ create_llms_txt()
MonsterUI/docs/custom_theme.css ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* custom_theme.css */
2
+
3
+ .uk-theme-grass {
4
+ --background: 78 47% 99%;
5
+ --foreground: 78 51% 0%;
6
+ --muted: 78 12% 85%;
7
+ --muted-foreground: 78 8% 38%;
8
+ --popover: 78 47% 99%;
9
+ --popover-foreground: 78 51% 0%;
10
+ --card: 78 47% 99%;
11
+ --card-foreground: 78 51% 0%;
12
+ --border: 78 2% 93%;
13
+ --input: 78 2% 93%;
14
+ --primary: 78 28% 60%;
15
+ --primary-foreground: 0 0% 0%;
16
+ --secondary: 78 8% 81%;
17
+ --secondary-foreground: 78 8% 21%;
18
+ --accent: 78 8% 81%;
19
+ --accent-foreground: 78 8% 21%;
20
+ --destructive: 17 86% 32%;
21
+ --destructive-foreground: 17 86% 92%;
22
+ --ring: 78 28% 60%;
23
+ --chart-1: 78 28% 60%;
24
+ --chart-2: 78 8% 81%;
25
+ --chart-3: 78 8% 81%;
26
+ --chart-4: 78 8% 84%;
27
+ --chart-5: 78 31% 60%;
28
+ --radius: 0.5rem;
29
+ }
30
+
31
+ .dark.uk-theme-grass {
32
+ --background: 78 48% 2%;
33
+ --foreground: 78 24% 99%;
34
+ --muted: 78 12% 15%;
35
+ --muted-foreground: 78 8% 62%;
36
+ --popover: 78 48% 2%;
37
+ --popover-foreground: 78 24% 99%;
38
+ --card: 78 48% 2%;
39
+ --card-foreground: 78 24% 99%;
40
+ --border: 78 2% 14%;
41
+ --input: 78 2% 14%;
42
+ --primary: 78 28% 60%;
43
+ --primary-foreground: 0 0% 0%;
44
+ --secondary: 78 8% 14%;
45
+ --secondary-foreground: 78 8% 74%;
46
+ --accent: 78 8% 14%;
47
+ --accent-foreground: 78 8% 74%;
48
+ --destructive: 17 86% 60%;
49
+ --destructive-foreground: 17 86% 0%;
50
+ --ring: 78 28% 60%;
51
+ --chart-1: 78 28% 60%;
52
+ --chart-2: 78 8% 14%;
53
+ --chart-3: 78 8% 14%;
54
+ --chart-4: 78 8% 17%;
55
+ --chart-5: 78 31% 60%;
56
+ }
MonsterUI/docs/data_/mail.json ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "id": "6c84fb90-12c4-11e1-840d-7b25c5ee775a",
4
+ "initial": "WS",
5
+ "name": "William Smith",
6
+ "email": "[email protected]",
7
+ "subject": "Meeting Tomorrow",
8
+ "text": "Hi, let's have a meeting tomorrow to discuss the project. I've been reviewing the project details and have some ideas I'd like to share. It's crucial that we align on our next steps to ensure the project's success.\n\nPlease come prepared with any questions or insights you may have. Looking forward to our meeting!\n\nBest regards, William",
9
+ "date": "2023-10-22T09:00:00",
10
+ "read": true,
11
+ "active": true,
12
+ "labels": ["meeting", "work", "important"]
13
+ },
14
+ {
15
+ "id": "110e8400-e29b-11d4-a716-446655440000",
16
+ "initial": "AS",
17
+ "name": "Alice Smith",
18
+ "email": "[email protected]",
19
+ "subject": "Re: Project Update",
20
+ "text": "Thank you for the project update. It looks great! I've gone through the report, and the progress is impressive. The team has done a fantastic job, and I appreciate the hard work everyone has put in.\n\nI have a few minor suggestions that I'll include in the attached document.\n\nLet's discuss these during our next meeting. Keep up the excellent work!\n\nBest regards, Alice",
21
+ "date": "2023-10-22T10:30:00",
22
+ "read": true,
23
+ "active": false,
24
+ "labels": ["work", "important"]
25
+ },
26
+ {
27
+ "id": "3e7c3f6d-bdf5-46ae-8d90-171300f27ae2",
28
+ "initial": "BJ",
29
+ "name": "Bob Johnson",
30
+ "email": "[email protected]",
31
+ "subject": "Weekend Plans",
32
+ "text": "Any plans for the weekend? I was thinking of going hiking in the nearby mountains. It's been a while since we had some outdoor fun.\n\nIf you're interested, let me know, and we can plan the details. It'll be a great way to unwind and enjoy nature.\n\nLooking forward to your response!\n\nBest, Bob",
33
+ "date": "2023-04-10T11:45:00",
34
+ "read": true,
35
+ "active": false,
36
+ "labels": ["personal"]
37
+ },
38
+ {
39
+ "id": "61c35085-72d7-42b4-8d62-738f700d4b92",
40
+ "initial": "ED",
41
+ "name": "Emily Davis",
42
+ "email": "[email protected]",
43
+ "subject": "Re: Question about Budget",
44
+ "text": "I have a question about the budget for the upcoming project. It seems like there's a discrepancy in the allocation of resources.\n\nI've reviewed the budget report and identified a few areas where we might be able to optimize our spending without compromising the project's quality.\n\nI've attached a detailed analysis for your reference. Let's discuss this further in our next meeting.\n\nThanks, Emily",
45
+ "date": "2023-03-25T13:15:00",
46
+ "read": false,
47
+ "active": false,
48
+ "labels": ["work", "budget"]
49
+ },
50
+ {
51
+ "id": "8f7b5db9-d935-4e42-8e05-1f1d0a3dfb97",
52
+ "initial": "MW",
53
+ "name": "Michael Wilson",
54
+ "email": "[email protected]",
55
+ "subject": "Important Announcement",
56
+ "text": "I have an important announcement to make during our team meeting. It pertains to a strategic shift in our approach to the upcoming product launch. We've received valuable feedback from our beta testers, and I believe it's time to make some adjustments to better meet our customers' needs.\n\nThis change is crucial to our success, and I look forward to discussing it with the team. Please be prepared to share your insights during the meeting.\n\nRegards, Michael",
57
+ "date": "2023-03-10T15:00:00",
58
+ "read": false,
59
+ "active": false,
60
+ "labels": ["meeting", "work", "important"]
61
+ },
62
+ {
63
+ "id": "1f0f2c02-e299-40de-9b1d-86ef9e42126b",
64
+ "initial": "SB",
65
+ "name": "Sarah Brown",
66
+ "email": "[email protected]",
67
+ "subject": "Re: Feedback on Proposal",
68
+ "text": "Thank you for your feedback on the proposal. It looks great! I'm pleased to hear that you found it promising. The team worked diligently to address all the key points you raised, and I believe we now have a strong foundation for the project.\n\nI've attached the revised proposal for your review.\n\nPlease let me know if you have any further comments or suggestions. Looking forward to your response.\n\nBest regards, Sarah",
69
+ "date": "2023-02-15T16:30:00",
70
+ "read": true,
71
+ "active": false,
72
+ "labels": ["work"]
73
+ },
74
+ {
75
+ "id": "17c0a96d-4415-42b1-8b4f-764efab57f66",
76
+ "initial": "DL",
77
+ "name": "David Lee",
78
+ "email": "[email protected]",
79
+ "subject": "New Project Idea",
80
+ "text": "I have an exciting new project idea to discuss with you. It involves expanding our services to target a niche market that has shown considerable growth in recent months.\n\nI've prepared a detailed proposal outlining the potential benefits and the strategy for execution.\n\nThis project has the potential to significantly impact our business positively. Let's set up a meeting to dive into the details and determine if it aligns with our current goals.\n\nBest regards, David",
81
+ "date": "2023-01-28T17:45:00",
82
+ "read": false,
83
+ "active": false,
84
+ "labels": ["meeting", "work", "important"]
85
+ },
86
+ {
87
+ "id": "2f0130cb-39fc-44c4-bb3c-0a4337edaaab",
88
+ "initial": "OW",
89
+ "name": "Olivia Wilson",
90
+ "email": "[email protected]",
91
+ "subject": "Vacation Plans",
92
+ "text": "Let's plan our vacation for next month. What do you think? I've been thinking of visiting a tropical paradise, and I've put together some destination options.\n\nI believe it's time for us to unwind and recharge. Please take a look at the options and let me know your preferences.\n\nWe can start making arrangements to ensure a smooth and enjoyable trip.\n\nExcited to hear your thoughts! Olivia",
93
+ "date": "2022-12-20T18:30:00",
94
+ "read": true,
95
+ "active": false,
96
+ "labels": ["personal"]
97
+ },
98
+ {
99
+ "id": "de305d54-75b4-431b-adb2-eb6b9e546014",
100
+ "initial": "JM",
101
+ "name": "James Martin",
102
+ "email": "[email protected]",
103
+ "subject": "Re: Conference Registration",
104
+ "text": "I've completed the registration for the conference next month. The event promises to be a great networking opportunity, and I'm looking forward to attending the various sessions and connecting with industry experts.\n\nI've also attached the conference schedule for your reference.\n\nIf there are any specific topics or sessions you'd like me to explore, please let me know. It's an exciting event, and I'll make the most of it.\n\nBest regards, James",
105
+ "date": "2022-11-30T19:15:00",
106
+ "read": true,
107
+ "active": false,
108
+ "labels": ["work", "conference"]
109
+ },
110
+ {
111
+ "id": "7dd90c63-00f6-40f3-bd87-5060a24e8ee7",
112
+ "initial": "SW",
113
+ "name": "Sophia White",
114
+ "email": "[email protected]",
115
+ "subject": "Team Dinner",
116
+ "text": "Let's have a team dinner next week to celebrate our success. We've achieved some significant milestones, and it's time to acknowledge our hard work and dedication.\n\nI've made reservations at a lovely restaurant, and I'm sure it'll be an enjoyable evening.\n\nPlease confirm your availability and any dietary preferences. Looking forward to a fun and memorable dinner with the team!\n\nBest, Sophia",
117
+ "date": "2022-11-05T20:30:00",
118
+ "read": false,
119
+ "active": false,
120
+ "labels": ["meeting", "work"]
121
+ },
122
+ {
123
+ "id": "99a88f78-3eb4-4d87-87b7-7b15a49a0a05",
124
+ "initial": "DJ",
125
+ "name": "Daniel Johnson",
126
+ "email": "[email protected]",
127
+ "subject": "Feedback Request",
128
+ "text": "I'd like your feedback on the latest project deliverables. We've made significant progress, and I value your input to ensure we're on the right track.\n\nI've attached the deliverables for your review, and I'm particularly interested in any areas where you think we can further enhance the quality or efficiency.\n\nYour feedback is invaluable, and I appreciate your time and expertise. Let's work together to make this project a success.\n\nRegards, Daniel",
129
+ "date": "2022-10-22T09:30:00",
130
+ "read": false,
131
+ "active": false,
132
+ "labels": ["work"]
133
+ },
134
+ {
135
+ "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
136
+ "initial": "AT",
137
+ "name": "Ava Taylor",
138
+ "email": "[email protected]",
139
+ "subject": "Re: Meeting Agenda",
140
+ "text": "Here's the agenda for our meeting next week. I've included all the topics we need to cover, as well as time allocations for each.\n\nIf you have any additional items to discuss or any specific points to address, please let me know, and we can integrate them into the agenda.\n\nIt's essential that our meeting is productive and addresses all relevant matters.\n\nLooking forward to our meeting! Ava",
141
+ "date": "2022-10-10T10:45:00",
142
+ "read": true,
143
+ "active": false,
144
+ "labels": ["meeting", "work"]
145
+ },
146
+ {
147
+ "id": "c1a0ecb4-2540-49c5-86f8-21e5ce79e4e6",
148
+ "initial": "WA",
149
+ "name": "William Anderson",
150
+ "email": "[email protected]",
151
+ "subject": "Product Launch Update",
152
+ "text": "The product launch is on track. I'll provide an update during our call. We've made substantial progress in the development and marketing of our new product.\n\nI'm excited to share the latest updates with you during our upcoming call. It's crucial that we coordinate our efforts to ensure a successful launch. Please come prepared with any questions or insights you may have.\n\nLet's make this product launch a resounding success!\n\nBest regards, William",
153
+ "date": "2022-09-20T12:00:00",
154
+ "read": false,
155
+ "active": false,
156
+ "labels": ["meeting", "work", "important"]
157
+ },
158
+ {
159
+ "id": "ba54eefd-4097-4949-99f2-2a9ae4d1a836",
160
+ "initial": "MH",
161
+ "name": "Mia Harris",
162
+ "email": "[email protected]",
163
+ "subject": "Re: Travel Itinerary",
164
+ "text": "I've received the travel itinerary. It looks great! Thank you for your prompt assistance in arranging the details. I've reviewed the schedule and the accommodations, and everything seems to be in order. I'm looking forward to the trip, and I'm confident it'll be a smooth and enjoyable experience.\n\nIf there are any specific activities or attractions you recommend at our destination, please feel free to share your suggestions.\n\nExcited for the trip! Mia",
165
+ "date": "2022-09-10T13:15:00",
166
+ "read": true,
167
+ "active": false,
168
+ "labels": ["personal", "travel"]
169
+ },
170
+ {
171
+ "id": "df09b6ed-28bd-4e0c-85a9-9320ec5179aa",
172
+ "initial": "EC",
173
+ "name": "Ethan Clark",
174
+ "email": "[email protected]",
175
+ "subject": "Team Building Event",
176
+ "text": "Let's plan a team-building event for our department. Team cohesion and morale are vital to our success, and I believe a well-organized team-building event can be incredibly beneficial. I've done some research and have a few ideas for fun and engaging activities.\n\nPlease let me know your thoughts and availability. We want this event to be both enjoyable and productive.\n\nTogether, we'll strengthen our team and boost our performance.\n\nRegards, Ethan",
177
+ "date": "2022-08-25T15:30:00",
178
+ "read": false,
179
+ "active": false,
180
+ "labels": ["meeting", "work"]
181
+ },
182
+ {
183
+ "id": "d67c1842-7f8b-4b4b-9be1-1b3b1ab4611d",
184
+ "initial": "CH",
185
+ "name": "Chloe Hall",
186
+ "email": "[email protected]",
187
+ "subject": "Re: Budget Approval",
188
+ "text": "The budget has been approved. We can proceed with the project. I'm delighted to inform you that our budget proposal has received the green light from the finance department. This is a significant milestone, and it means we can move forward with the project as planned.\n\nI've attached the finalized budget for your reference. Let's ensure that we stay on track and deliver the project on time and within budget.\n\nIt's an exciting time for us! Chloe",
189
+ "date": "2022-08-10T16:45:00",
190
+ "read": true,
191
+ "active": false,
192
+ "labels": ["work", "budget"]
193
+ },
194
+ {
195
+ "id": "6c9a7f94-8329-4d70-95d3-51f68c186ae1",
196
+ "initial": "ST",
197
+ "name": "Samuel Turner",
198
+ "email": "[email protected]",
199
+ "subject": "Weekend Hike",
200
+ "text": "Who's up for a weekend hike in the mountains? I've been craving some outdoor adventure, and a hike in the mountains sounds like the perfect escape. If you're up for the challenge, we can explore some scenic trails and enjoy the beauty of nature.\n\nI've done some research and have a few routes in mind.\n\nLet me know if you're interested, and we can plan the details.\n\nIt's sure to be a memorable experience! Samuel",
201
+ "date": "2022-07-28T17:30:00",
202
+ "read": false,
203
+ "active": false,
204
+ "labels": ["personal"]
205
+ }
206
+ ]
MonsterUI/docs/data_/status_list.json ADDED
@@ -0,0 +1 @@
 
 
1
+ [{"selected": true, "id": "TASK-8782", "title": "You can't compress the program without quantifying the open-source SSD pixel!", "status": "progress", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-7878", "title": "Try to calculate the EXE feed, maybe it will index the multi-byte pixel!", "status": "backlog", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-7839", "title": "We need to bypass the neural TCP card!", "status": "todo", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-5562", "title": "The SAS interface is down, bypass the open-source pixel so we can back up the PNG bandwidth!", "status": "backlog", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-8686", "title": "I'll parse the wireless SSL protocol, that should driver the API panel!", "status": "cancelled", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-1280", "title": "Use the digital TLS panel, then you can transmit the haptic system!", "status": "done", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-7262", "title": "The UTF8 application is down, parse the neural bandwidth so we can back up the PNG firewall!", "status": "done", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-1138", "title": "Generating the driver won't do anything, we need to quantify the 1080p SMTP bandwidth!", "status": "progress", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-7184", "title": "We need to program the back-end THX pixel!", "status": "todo", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-5160", "title": "Calculating the bus won't do anything, we need to navigate the back-end JSON protocol!", "status": "progress", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-5618", "title": "Generating the driver won't do anything, we need to index the online SSL application!", "status": "done", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-6699", "title": "I'll transmit the wireless JBOD capacitor, that should hard drive the SSD feed!", "status": "backlog", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-2858", "title": "We need to override the online UDP bus!", "status": "backlog", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-9864", "title": "I'll reboot the 1080p FTP panel, that should matrix the HEX hard drive!", "status": "done", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-8404", "title": "We need to generate the virtual HEX alarm!", "status": "progress", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-5365", "title": "Backing up the pixel won't do anything, we need to transmit the primary IB array!", "status": "progress", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-1780", "title": "The CSS feed is down, index the bluetooth transmitter so we can compress the CLI protocol!", "status": "todo", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-6938", "title": "Use the redundant SCSI application, then you can hack the optical alarm!", "status": "todo", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-9885", "title": "We need to compress the auxiliary VGA driver!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-3216", "title": "Transmitting the transmitter won't do anything, we need to compress the virtual HDD sensor!", "status": "backlog", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-9285", "title": "The IP monitor is down, copy the haptic alarm so we can generate the HTTP transmitter!", "status": "todo", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-1024", "title": "Overriding the microchip won't do anything, we need to transmit the digital OCR transmitter!", "status": "progress", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-7068", "title": "You can't generate the capacitor without indexing the wireless HEX pixel!", "status": "cancelled", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-6502", "title": "Navigating the microchip won't do anything, we need to bypass the back-end SQL bus!", "status": "todo", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-5326", "title": "We need to hack the redundant UTF8 transmitter!", "status": "todo", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-6274", "title": "Use the virtual PCI circuit, then you can parse the bluetooth alarm!", "status": "cancelled", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-1571", "title": "I'll input the neural DRAM circuit, that should protocol the SMTP interface!", "status": "progress", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-9518", "title": "Compressing the interface won't do anything, we need to compress the online SDD matrix!", "status": "cancelled", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-5581", "title": "I'll synthesize the digital COM pixel, that should transmitter the UTF8 protocol!", "status": "backlog", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-2197", "title": "Parsing the feed won't do anything, we need to copy the bluetooth DRAM bus!", "status": "todo", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-8484", "title": "We need to parse the solid state UDP firewall!", "status": "progress", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-9892", "title": "If we back up the application, we can get to the UDP application through the multi-byte THX capacitor!", "status": "done", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-9616", "title": "We need to synthesize the cross-platform ASCII pixel!", "status": "progress", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-9744", "title": "Use the back-end IP card, then you can input the solid state hard drive!", "status": "done", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-1376", "title": "Generating the alarm won't do anything, we need to generate the mobile IP capacitor!", "status": "backlog", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-7382", "title": "If we back up the firewall, we can get to the RAM alarm through the primary UTF8 pixel!", "status": "todo", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-2290", "title": "I'll compress the virtual JSON panel, that should application the UTF8 bus!", "status": "cancelled", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-1533", "title": "You can't input the firewall without overriding the wireless TCP firewall!", "status": "done", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-4920", "title": "Bypassing the hard drive won't do anything, we need to input the bluetooth JSON program!", "status": "progress", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-5168", "title": "If we synthesize the bus, we can get to the IP panel through the virtual TLS array!", "status": "progress", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-7103", "title": "We need to parse the multi-byte EXE bandwidth!", "status": "cancelled", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-4314", "title": "If we compress the program, we can get to the XML alarm through the multi-byte COM matrix!", "status": "progress", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-3415", "title": "Use the cross-platform XML application, then you can quantify the solid state feed!", "status": "todo", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-8339", "title": "Try to calculate the DNS interface, maybe it will input the bluetooth capacitor!", "status": "progress", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-6995", "title": "Try to hack the XSS bandwidth, maybe it will override the bluetooth matrix!", "status": "todo", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-8053", "title": "If we connect the program, we can get to the UTF8 matrix through the digital UDP protocol!", "status": "todo", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-4336", "title": "If we synthesize the microchip, we can get to the SAS sensor through the optical UDP program!", "status": "todo", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-8790", "title": "I'll back up the optical COM alarm, that should alarm the RSS capacitor!", "status": "done", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-8980", "title": "Try to navigate the SQL transmitter, maybe it will back up the virtual firewall!", "status": "cancelled", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-7342", "title": "Use the neural CLI card, then you can parse the online port!", "status": "backlog", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-5608", "title": "I'll hack the haptic SSL program, that should bus the UDP transmitter!", "status": "cancelled", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-1606", "title": "I'll generate the bluetooth PNG firewall, that should pixel the SSL driver!", "status": "done", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-7872", "title": "Transmitting the circuit won't do anything, we need to reboot the 1080p RSS monitor!", "status": "cancelled", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-4167", "title": "Use the cross-platform SMS circuit, then you can synthesize the optical feed!", "status": "cancelled", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-9581", "title": "You can't index the port without hacking the cross-platform XSS monitor!", "status": "backlog", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-8806", "title": "We need to bypass the back-end SSL panel!", "status": "done", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-6542", "title": "Try to quantify the RSS firewall, maybe it will quantify the open-source system!", "status": "done", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-6806", "title": "The VGA protocol is down, reboot the back-end matrix so we can parse the CSS panel!", "status": "cancelled", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-9549", "title": "You can't bypass the bus without connecting the neural JBOD bus!", "status": "todo", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-1075", "title": "Backing up the driver won't do anything, we need to parse the redundant RAM pixel!", "status": "done", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-1427", "title": "Use the auxiliary PCI circuit, then you can calculate the cross-platform interface!", "status": "done", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-1907", "title": "Hacking the circuit won't do anything, we need to back up the online DRAM system!", "status": "todo", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-4309", "title": "If we generate the system, we can get to the TCP sensor through the optical GB pixel!", "status": "backlog", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-3973", "title": "I'll parse the back-end ADP array, that should bandwidth the RSS bandwidth!", "status": "todo", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-7962", "title": "Use the wireless RAM program, then you can hack the cross-platform feed!", "status": "cancelled", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-3360", "title": "You can't quantify the program without synthesizing the neural OCR interface!", "status": "done", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-9887", "title": "Use the auxiliary ASCII sensor, then you can connect the solid state port!", "status": "backlog", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-3649", "title": "I'll input the virtual USB system, that should circuit the DNS monitor!", "status": "progress", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-3586", "title": "If we quantify the circuit, we can get to the CLI feed through the mobile SMS hard drive!", "status": "progress", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-5150", "title": "I'll hack the wireless XSS port, that should transmitter the IP interface!", "status": "cancelled", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-3652", "title": "The SQL interface is down, override the optical bus so we can program the ASCII interface!", "status": "backlog", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-6884", "title": "Use the digital PCI circuit, then you can synthesize the multi-byte microchip!", "status": "cancelled", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-1591", "title": "We need to connect the mobile XSS driver!", "status": "progress", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-3802", "title": "Try to override the ASCII protocol, maybe it will parse the virtual matrix!", "status": "progress", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-7253", "title": "Programming the capacitor won't do anything, we need to bypass the neural IB hard drive!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-9739", "title": "We need to hack the multi-byte HDD bus!", "status": "done", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-4424", "title": "Try to hack the HEX alarm, maybe it will connect the optical pixel!", "status": "progress", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-3922", "title": "You can't back up the capacitor without generating the wireless PCI program!", "status": "backlog", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-4921", "title": "I'll index the open-source IP feed, that should system the GB application!", "status": "cancelled", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-5814", "title": "We need to calculate the 1080p AGP feed!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-2645", "title": "Synthesizing the system won't do anything, we need to navigate the multi-byte HDD firewall!", "status": "todo", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-4535", "title": "Try to copy the JSON circuit, maybe it will connect the wireless feed!", "status": "progress", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-4463", "title": "We need to copy the solid state AGP monitor!", "status": "done", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-9745", "title": "If we connect the protocol, we can get to the GB system through the bluetooth PCI microchip!", "status": "cancelled", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-2080", "title": "If we input the bus, we can get to the RAM matrix through the auxiliary RAM card!", "status": "todo", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-3838", "title": "I'll bypass the online TCP application, that should panel the AGP system!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-1340", "title": "We need to navigate the virtual PNG circuit!", "status": "todo", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-6665", "title": "If we parse the monitor, we can get to the SSD hard drive through the cross-platform AGP alarm!", "status": "cancelled", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-7585", "title": "If we calculate the hard drive, we can get to the SSL program through the multi-byte CSS microchip!", "status": "backlog", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-6319", "title": "We need to copy the multi-byte SCSI program!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-4369", "title": "Try to input the SCSI bus, maybe it will generate the 1080p pixel!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-9035", "title": "We need to override the solid state PNG array!", "status": "cancelled", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-3970", "title": "You can't index the transmitter without quantifying the haptic ASCII card!", "status": "todo", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-4473", "title": "You can't bypass the protocol without overriding the neural RSS program!", "status": "todo", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-4136", "title": "You can't hack the hard drive without hacking the primary JSON program!", "status": "cancelled", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-3939", "title": "Use the back-end SQL firewall, then you can connect the neural hard drive!", "status": "done", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-2007", "title": "I'll input the back-end USB protocol, that should bandwidth the PCI system!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-7516", "title": "Use the primary SQL program, then you can generate the auxiliary transmitter!", "status": "done", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-6906", "title": "Try to back up the DRAM system, maybe it will reboot the online transmitter!", "status": "done", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-5207", "title": "The SMS interface is down, copy the bluetooth bus so we can quantify the VGA card!", "status": "progress", "label": "bug", "priority": "low"}]
MonsterUI/docs/data_/statuses.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backlog": {
3
+ "icon": "<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-2 h-4 w-4 text-muted-foreground\"><path d=\"M0.877075 7.49972C0.877075 3.84204 3.84222 0.876892 7.49991 0.876892C11.1576 0.876892 14.1227 3.84204 14.1227 7.49972C14.1227 11.1574 11.1576 14.1226 7.49991 14.1226C3.84222 14.1226 0.877075 11.1574 0.877075 7.49972ZM7.49991 1.82689C4.36689 1.82689 1.82708 4.36671 1.82708 7.49972C1.82708 10.6327 4.36689 13.1726 7.49991 13.1726C10.6329 13.1726 13.1727 10.6327 13.1727 7.49972C13.1727 4.36671 10.6329 1.82689 7.49991 1.82689ZM8.24993 10.5C8.24993 10.9142 7.91414 11.25 7.49993 11.25C7.08571 11.25 6.74993 10.9142 6.74993 10.5C6.74993 10.0858 7.08571 9.75 7.49993 9.75C7.91414 9.75 8.24993 10.0858 8.24993 10.5ZM6.05003 6.25C6.05003 5.57211 6.63511 4.925 7.50003 4.925C8.36496 4.925 8.95003 5.57211 8.95003 6.25C8.95003 6.74118 8.68002 6.99212 8.21447 7.27494C8.16251 7.30651 8.10258 7.34131 8.03847 7.37854L8.03841 7.37858C7.85521 7.48497 7.63788 7.61119 7.47449 7.73849C7.23214 7.92732 6.95003 8.23198 6.95003 8.7C6.95004 9.00376 7.19628 9.25 7.50004 9.25C7.8024 9.25 8.04778 9.00601 8.05002 8.70417L8.05056 8.7033C8.05924 8.6896 8.08493 8.65735 8.15058 8.6062C8.25207 8.52712 8.36508 8.46163 8.51567 8.37436L8.51571 8.37433C8.59422 8.32883 8.68296 8.27741 8.78559 8.21506C9.32004 7.89038 10.05 7.35382 10.05 6.25C10.05 4.92789 8.93511 3.825 7.50003 3.825C6.06496 3.825 4.95003 4.92789 4.95003 6.25C4.95003 6.55376 5.19628 6.8 5.50003 6.8C5.80379 6.8 6.05003 6.55376 6.05003 6.25Z\" fill=\"currentColor\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"></path></svg>",
4
+ "text": "Backlog"
5
+ },
6
+ "cancelled": {
7
+ "icon": "<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-2 h-4 w-4 text-muted-foreground\"><path d=\"M0.877075 7.49988C0.877075 3.84219 3.84222 0.877045 7.49991 0.877045C11.1576 0.877045 14.1227 3.84219 14.1227 7.49988C14.1227 11.1575 11.1576 14.1227 7.49991 14.1227C3.84222 14.1227 0.877075 11.1575 0.877075 7.49988ZM7.49991 1.82704C4.36689 1.82704 1.82708 4.36686 1.82708 7.49988C1.82708 10.6329 4.36689 13.1727 7.49991 13.1727C10.6329 13.1727 13.1727 10.6329 13.1727 7.49988C13.1727 4.36686 10.6329 1.82704 7.49991 1.82704ZM9.85358 5.14644C10.0488 5.3417 10.0488 5.65829 9.85358 5.85355L8.20713 7.49999L9.85358 9.14644C10.0488 9.3417 10.0488 9.65829 9.85358 9.85355C9.65832 10.0488 9.34173 10.0488 9.14647 9.85355L7.50002 8.2071L5.85358 9.85355C5.65832 10.0488 5.34173 10.0488 5.14647 9.85355C4.95121 9.65829 4.95121 9.3417 5.14647 9.14644L6.79292 7.49999L5.14647 5.85355C4.95121 5.65829 4.95121 5.3417 5.14647 5.14644C5.34173 4.95118 5.65832 4.95118 5.85358 5.14644L7.50002 6.79289L9.14647 5.14644C9.34173 4.95118 9.65832 4.95118 9.85358 5.14644Z\" fill=\"currentColor\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"></path></svg>",
8
+ "text": "Cancelled"
9
+ },
10
+ "done": {
11
+ "icon": "<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-2 h-4 w-4 text-muted-foreground\"><path d=\"M7.49991 0.877045C3.84222 0.877045 0.877075 3.84219 0.877075 7.49988C0.877075 11.1575 3.84222 14.1227 7.49991 14.1227C11.1576 14.1227 14.1227 11.1575 14.1227 7.49988C14.1227 3.84219 11.1576 0.877045 7.49991 0.877045ZM1.82708 7.49988C1.82708 4.36686 4.36689 1.82704 7.49991 1.82704C10.6329 1.82704 13.1727 4.36686 13.1727 7.49988C13.1727 10.6329 10.6329 13.1727 7.49991 13.1727C4.36689 13.1727 1.82708 10.6329 1.82708 7.49988ZM10.1589 5.53774C10.3178 5.31191 10.2636 5.00001 10.0378 4.84109C9.81194 4.68217 9.50004 4.73642 9.34112 4.96225L6.51977 8.97154L5.35681 7.78706C5.16334 7.59002 4.84677 7.58711 4.64973 7.78058C4.45268 7.97404 4.44978 8.29061 4.64325 8.48765L6.22658 10.1003C6.33054 10.2062 6.47617 10.2604 6.62407 10.2483C6.77197 10.2363 6.90686 10.1591 6.99226 10.0377L10.1589 5.53774Z\" fill=\"currentColor\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"></path></svg>",
12
+ "text": "Done"
13
+ },
14
+ "progress": {
15
+ "icon": "<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-2 h-4 w-4 text-muted-foreground\"><path d=\"M5.49998 0.5C5.49998 0.223858 5.72383 0 5.99998 0H7.49998H8.99998C9.27612 0 9.49998 0.223858 9.49998 0.5C9.49998 0.776142 9.27612 1 8.99998 1H7.99998V2.11922C9.09832 2.20409 10.119 2.56622 10.992 3.13572C11.0116 3.10851 11.0336 3.08252 11.058 3.05806L11.858 2.25806C12.1021 2.01398 12.4978 2.01398 12.7419 2.25806C12.986 2.50214 12.986 2.89786 12.7419 3.14194L11.967 3.91682C13.1595 5.07925 13.9 6.70314 13.9 8.49998C13.9 12.0346 11.0346 14.9 7.49998 14.9C3.96535 14.9 1.09998 12.0346 1.09998 8.49998C1.09998 5.13362 3.69904 2.3743 6.99998 2.11922V1H5.99998C5.72383 1 5.49998 0.776142 5.49998 0.5ZM2.09998 8.49998C2.09998 5.51764 4.51764 3.09998 7.49998 3.09998C10.4823 3.09998 12.9 5.51764 12.9 8.49998C12.9 11.4823 10.4823 13.9 7.49998 13.9C4.51764 13.9 2.09998 11.4823 2.09998 8.49998ZM7.99998 4.5C7.99998 4.22386 7.77612 4 7.49998 4C7.22383 4 6.99998 4.22386 6.99998 4.5V9.5C6.99998 9.77614 7.22383 10 7.49998 10C7.77612 10 7.99998 9.77614 7.99998 9.5V4.5Z\" fill=\"currentColor\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"></path></svg>",
16
+ "text": "In Progress"
17
+ },
18
+ "todo": {
19
+ "icon": "<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-2 h-4 w-4 text-muted-foreground\"><path d=\"M0.877075 7.49991C0.877075 3.84222 3.84222 0.877075 7.49991 0.877075C11.1576 0.877075 14.1227 3.84222 14.1227 7.49991C14.1227 11.1576 11.1576 14.1227 7.49991 14.1227C3.84222 14.1227 0.877075 11.1576 0.877075 7.49991ZM7.49991 1.82708C4.36689 1.82708 1.82708 4.36689 1.82708 7.49991C1.82708 10.6329 4.36689 13.1727 7.49991 13.1727C10.6329 13.1727 13.1727 10.6329 13.1727 7.49991C13.1727 4.36689 10.6329 1.82708 7.49991 1.82708Z\" fill=\"currentColor\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"></path></svg>",
20
+ "text": "Todo"
21
+ }
22
+ }
MonsterUI/docs/examples/auth.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FrankenUI Auth Example built with MonsterUI (original design by ShadCN)"""
2
+
3
+ from fasthtml.common import *
4
+ from monsterui.all import *
5
+ from fasthtml.svg import *
6
+
7
+ app, rt = fast_app(hdrs=Theme.blue.headers())
8
+
9
+ @rt
10
+ def index():
11
+ left = Div(cls="col-span-1 hidden flex-col justify-between bg-zinc-900 p-8 text-white lg:flex")(
12
+ Div(cls=(TextT.bold))("Acme Inc"),
13
+ Blockquote(cls="space-y-2")(
14
+ P(cls=TextT.lg)('"This library has saved me countless hours of work and helped me deliver stunning designs to my clients faster than ever before."'),
15
+ Footer(cls=TextT.sm)("Sofia Davis")))
16
+
17
+ right = Div(cls="col-span-2 flex flex-col p-8 lg:col-span-1")(
18
+ DivRAligned(Button("Login", cls=ButtonT.ghost)),
19
+ DivCentered(cls='flex-1')(
20
+ Container(
21
+ DivVStacked(
22
+ H3("Create an account"),
23
+ Small("Enter your email below to create your account", cls=TextT.muted)),
24
+ Form(
25
+ Input(placeholder="[email protected]"),
26
+ Button(Span(cls="mr-2", uk_spinner="ratio: 0.54"), "Sign in with Email", cls=(ButtonT.primary, "w-full"), disabled=True),
27
+ DividerSplit(Small("Or continue with"),cls=TextT.muted),
28
+ Button(UkIcon('github',cls='mr-2'), "Github", cls=(ButtonT.default, "w-full")),
29
+ cls='space-y-6'),
30
+ DivVStacked(Small(
31
+ "By clicking continue, you agree to our ",
32
+ A(cls=AT.muted, href="#demo")("Terms of Service")," and ",
33
+ A(cls=AT.muted, href="#demo")("Privacy Policy"),".",
34
+ cls=(TextT.muted,"text-center"))),
35
+ cls="space-y-6")))
36
+
37
+ return Title("Auth Example"),Grid(left,right,cols=2, gap=0,cls='h-screen')
38
+
39
+
40
+ serve()
MonsterUI/docs/examples/cards.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FrankenUI Cards Example built with MonsterUI (original design by ShadCN)"""
2
+
3
+ from fasthtml.common import *
4
+ from fasthtml.components import Uk_input_tag
5
+ from fasthtml.svg import *
6
+ from monsterui.all import *
7
+ import calendar
8
+ from datetime import datetime
9
+
10
+ app, rt = fast_app(hdrs=Theme.blue.headers())
11
+
12
+ CreateAccount = Card(
13
+ Grid(Button(DivLAligned(UkIcon('github'),Div('Github'))),Button('Google')),
14
+ DividerSplit("OR CONTINUE WITH", text_cls=TextPresets.muted_sm),
15
+ LabelInput('Email', id='email', placeholder='[email protected]'),
16
+ LabelInput('Password', id='password',placeholder='Password', type='Password'),
17
+ header=(H3('Create an Account'),Subtitle('Enter your email below to create your account')),
18
+ footer=Button('Create Account',cls=(ButtonT.primary,'w-full')))
19
+
20
+ PaypalSVG_data = "M7.076 21.337H2.47a.641.641 0 0 1-.633-.74L4.944.901C5.026.382 5.474 0 5.998 0h7.46c2.57 0 4.578.543 5.69 1.81 1.01 1.15 1.304 2.42 1.012 4.287-.023.143-.047.288-.077.437-.983 5.05-4.349 6.797-8.647 6.797h-2.19c-.524 0-.968.382-1.05.9l-1.12 7.106zm14.146-14.42a3.35 3.35 0 0 0-.607-.541c-.013.076-.026.175-.041.254-.93 4.778-4.005 7.201-9.138 7.201h-2.19a.563.563 0 0 0-.556.479l-1.187 7.527h-.506l-.24 1.516a.56.56 0 0 0 .554.647h3.882c.46 0 .85-.334.922-.788.06-.26.76-4.852.816-5.09a.932.932 0 0 1 .923-.788h.58c3.76 0 6.705-1.528 7.565-5.946.36-1.847.174-3.388-.777-4.471z"
21
+ AppleSVG_data = "M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"
22
+ Card1Svg = Svg(viewBox="0 0 24 24", fill="none", stroke="currentColor", stroke_linecap="round", stroke_linejoin="round", stroke_width="2", cls="h-6 w-6 mr-1")(Rect(width="20", height="14", x="2", y="5", rx="2"),Path(d="M2 10h20"))
23
+ PaypalSvg = Svg(role="img", viewBox="0 0 24 24", cls="h-6 w-6 mr-1")(Path(d=PaypalSVG_data, fill="currentColor")),
24
+ AppleSvg = Svg(role="img", viewBox="0 0 24 24", cls="h-6 w-6 mr-1")(Path(d=AppleSVG_data, fill="currentColor"))
25
+
26
+ PaymentMethod = Card(
27
+ Grid(Button(DivCentered(Card1Svg, "Card"), cls='h-20 border-2 border-primary'),
28
+ Button(DivCentered(PaypalSvg, "PayPal"), cls='h-20'),
29
+ Button(DivCentered(AppleSvg, "Apple"), cls='h-20')),
30
+ Form(LabelInput('Name', id='name', placeholder='John Doe'),
31
+ LabelInput('Card Number', id='card_number', placeholder='[email protected]'),
32
+ Grid(LabelSelect(*Options(*calendar.month_name[1:],selected_idx=0),label='Expires',id='expire_month'),
33
+ LabelSelect(*Options(*range(2024,2030),selected_idx=0), label='Year', id='expire_year'),
34
+ LabelInput('CVV', id='cvv',placeholder='CVV', cls='mt-0'))),
35
+ header=(H3('Payment Method'),Subtitle('Add a new payment method to your account.')))
36
+
37
+ area_opts = ('Team','Billing','Account','Deployment','Support')
38
+ severity_opts = ('Severity 1 (Highest)', 'Severity 2', 'Severity 3', 'Severity 4 (Lowest)')
39
+ ReportIssue = Card(
40
+ Grid(Div(LabelSelect(*Options(*area_opts), label='Area', id='area')),
41
+ Div(LabelSelect(*Options(*severity_opts),label='Severity',id='area'))),
42
+ LabelInput( label='Subject', id='subject', placeholder='I need help with'),
43
+ LabelTextArea( label='Description', id='description',placeholder='Please include all information relevant to your issue'),
44
+ Div(FormLabel('Tags', fr='#tags'),
45
+ Uk_input_tag(name="Tags",state="danger", value="Spam,Invalid", uk_cloak=True, id='tags')),
46
+ header=(H3('Report Issue'),Subtitle('What area are you having problems with?')),
47
+ footer = DivFullySpaced(Button('Cancel'), Button(cls=ButtonT.primary)('Submit')))
48
+
49
+ monster_desc ="Python-first beautifully designed components because you deserve to focus on features that matter and your app deserves to be beautiful from day one."
50
+ MonsterUI = Card(H4("Monster UI"),
51
+ Subtitle(monster_desc),
52
+ DivLAligned(
53
+ Div("Python"),
54
+ DivLAligned(UkIcon('star'),Div("20k"), cls='space-x-1'),
55
+ Div(datetime.now().strftime("%B %d, %Y")),
56
+ cls=('space-x-4',TextPresets.muted_sm)))
57
+
58
+ def CookieTableRow(heading, description, active=False):
59
+ return Tr(Td(H5(heading)),
60
+ Td(P(description, cls=TextPresets.muted_sm)),
61
+ Td(Switch(checked=active)))
62
+
63
+ CookieSettings = Card(
64
+ Table(Tbody(
65
+ CookieTableRow('Strictly Necessary', 'These cookies are essential in order to use the website and use its features.', True),
66
+ CookieTableRow('Functional Cookies', 'These cookies allow the website to provide personalized functionality.'),
67
+ CookieTableRow('Performance Cookies', 'These cookies help to improve the performance of the website.'))),
68
+ header=(H4('Cookie Settings'),Subtitle('Manage your cookie settings here.')),
69
+ footer=Button('Save Preferences', cls=(ButtonT.primary, 'w-full')))
70
+
71
+ team_members = [("Sofia Davis", "[email protected]", "Owner"),("Jackson Lee", "[email protected]", "Member"),]
72
+ def TeamMemberRow(name, email, role):
73
+ return DivFullySpaced(
74
+ DivLAligned(
75
+ DiceBearAvatar(name, 10,10),
76
+ Div(P(name, cls=(TextT.sm, TextT.medium)),
77
+ P(email, cls=TextPresets.muted_sm))),
78
+ Button(role, UkIcon('chevron-down', cls='ml-4')),
79
+ DropDownNavContainer(map(NavCloseLi, [
80
+ A(Div('Viewer', NavSubtitle('Can view and comment.'))),
81
+ A(Div('Developer', NavSubtitle('Can view, comment and edit.'))),
82
+ A(Div('Billing', NavSubtitle('Can view, comment and manage billing.'))),
83
+ A(Div('Owner', NavSubtitle('Admin-level access to all resources.')))])))
84
+
85
+ TeamMembers = Card(*[TeamMemberRow(*member) for member in team_members],
86
+ header = (H4('Team Members'),Subtitle('Invite your team members to collaborate.')))
87
+
88
+ access_roles = ("Read and write access", "Read-only access")
89
+ team_members = [("Olivia Martin", "[email protected]", "Read and write access"),
90
+ ("Isabella Nguyen", "[email protected]", "Read-only access"),
91
+ ("Sofia Davis", "[email protected]", "Read-only access")]
92
+
93
+ def TeamMemberRow(name, email, role):
94
+ return DivFullySpaced(
95
+ DivLAligned(DiceBearAvatar(name, 10,10),
96
+ Div(P(name, cls=(TextT.sm, TextT.medium)),
97
+ P(email, cls=TextPresets.muted_sm))),
98
+ Select(*Options(*access_roles, selected_idx=access_roles.index(role))))
99
+
100
+ ShareDocument = Card(
101
+ DivLAligned(Input(value='http://example.com/link/to/document'),Button('Copy link', cls='whitespace-nowrap')),
102
+ Divider(),
103
+ H4('People with access', cls=TextPresets.bold_sm),
104
+ *[TeamMemberRow(*member) for member in team_members],
105
+ header = (H4('Share this document'),Subtitle('Anyone with the link can view this document.')))
106
+
107
+ DateCard = Card(Button('Jan 20, 2024 - Feb 09, 2024'))
108
+
109
+ section_content =(('bell','Everything',"Email digest, mentions & all activity."),
110
+ ('user',"Available","Only mentions and comments"),
111
+ ('ban', "Ignoring","Turn of all notifications"))
112
+
113
+ def NotificationRow(icon, name, desc):
114
+ return Li(cls='-mx-1')(A(DivLAligned(UkIcon(icon),Div(P(name),P(desc, cls=TextPresets.muted_sm)))))
115
+
116
+ Notifications = Card(
117
+ NavContainer(
118
+ *[NotificationRow(*row) for row in section_content],
119
+ cls=NavT.secondary),
120
+ header = (H4('Notification'),Subtitle('Choose what you want to be notified about.')),
121
+ body_cls='pt-0')
122
+
123
+ TeamCard = Card(
124
+ DivLAligned(
125
+ DiceBearAvatar("Isaac Flath", h=24, w=24),
126
+ Div(H3("Isaac Flath"), P("Library Creator"))),
127
+ footer=DivFullySpaced(
128
+ DivHStacked(UkIcon("map-pin", height=16), P("Alexandria, VA")),
129
+ DivHStacked(*(UkIconLink(icon, height=16) for icon in ("mail", "linkedin", "github")))),
130
+ cls=CardT.hover)
131
+
132
+ @rt
133
+ def index():
134
+ return Title("Cards Example"),Container(Grid(
135
+ *map(Div,(
136
+ Div(PaymentMethod,CreateAccount, TeamCard, cls='space-y-4'),
137
+ Div(TeamMembers, ShareDocument,DateCard,Notifications, cls='space-y-4'),
138
+ Div(ReportIssue,MonsterUI,CookieSettings, cls='space-y-4'))),
139
+ cols_md=1, cols_lg=2, cols_xl=3))
140
+
141
+ serve()
MonsterUI/docs/examples/dashboard.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FrankenUI Dashboard Example built with MonsterUI (original design by ShadCN)"""
2
+
3
+ from fasthtml.common import * # Bring in all of fasthtml
4
+ import fasthtml.common as fh # Used to get unstyled components
5
+ from monsterui.all import * # Bring in all of monsterui, including shadowing fasthtml components with styled components
6
+ from fasthtml.svg import *
7
+ import numpy as np
8
+ import plotly.express as px
9
+ import pandas as pd
10
+ import numpy as np
11
+
12
+ app, rt = fast_app(hdrs=Theme.blue.headers())
13
+
14
+ def generate_chart(num_points=30):
15
+ df = pd.DataFrame({
16
+ 'Date': pd.date_range('2024-01-01', periods=num_points),
17
+ 'Revenue': np.random.normal(100, 10, num_points).cumsum(),
18
+ 'Users': np.random.normal(80, 8, num_points).cumsum(),
19
+ 'Growth': np.random.normal(60, 6, num_points).cumsum()})
20
+
21
+ fig = px.line(df, x='Date', y=['Revenue', 'Users', 'Growth'], template='plotly_white', line_shape='spline')
22
+
23
+ fig.update_traces(mode='lines+markers')
24
+ fig.update_layout(
25
+ margin=dict(l=20, r=20, t=20, b=20), hovermode='x unified',
26
+ showlegend=True, legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1),
27
+ plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)',
28
+ xaxis=dict(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)'),
29
+ yaxis=dict(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)'))
30
+
31
+ return fig.to_html(include_plotlyjs=True, full_html=False, config={'displayModeBar': False})
32
+
33
+ def InfoCard(title, value, change): return Card(H3(value),P(change, cls=TextPresets.muted_sm), header = H4(title))
34
+
35
+ rev = InfoCard("Total Revenue", "$45,231.89", "+20.1% from last month")
36
+ sub = InfoCard("Subscriptions", "+2350", "+180.1% from last month")
37
+ sal = InfoCard("Sales", "+12,234", "+19% from last month")
38
+ act = InfoCard("Active Now", "+573", "+201 since last hour")
39
+
40
+ info_card_data = [("Total Revenue", "$45,231.89", "+20.1% from last month"),
41
+ ("Subscriptions", "+2350", "+180.1% from last month"),
42
+ ("Sales", "+12,234", "+19% from last month"),
43
+ ("Active Now", "+573", "+201 since last hour")]
44
+
45
+ top_info_row = Grid(*[InfoCard(*row) for row in info_card_data])
46
+
47
+ def AvatarItem(name, email, amount):
48
+ return DivFullySpaced(
49
+ DivLAligned(
50
+ DiceBearAvatar(name, 9,9),
51
+ Div(Strong(name, cls=TextT.sm),
52
+ Address(A(email,href=f'mailto:{email}')))),
53
+ fh.Data(amount, cls="ml-auto font-medium", value=amount[2:]))
54
+
55
+ recent_sales = Card(
56
+ Div(cls="space-y-8")(
57
+ *[AvatarItem(n,e,d) for (n,e,d) in (
58
+ ("Olivia Martin", "[email protected]", "+$1,999.00"),
59
+ ("Jackson Lee", "[email protected]", "+$39.00"),
60
+ ("Isabella Nguyen", "[email protected]", "+$299.00"),
61
+ ("William Kim", "[email protected]", "+$99.00"),
62
+ ("Sofia Davis", "[email protected]", "+$39.00"))]),
63
+ header=Div(H3("Recent Sales"),Subtitle("You made 265 sales this month.")),
64
+ cls='col-span-3')
65
+
66
+ teams = [["Alicia Koch"],['Acme Inc', 'Monster Inc.'],['Create a Team']]
67
+
68
+ opt_hdrs = ["Personal", "Team", ""]
69
+
70
+ team_dropdown = Select(
71
+ Optgroup(Option(A("Alicia Koch")), label="Personal Account"),
72
+ Optgroup(Option(A("Acme Inc")), Option(A("Monster Inc.")), label="Teams"),
73
+ Option(A("Create a Team")),
74
+ cls='flex items-center')
75
+
76
+ hotkeys = [('Profile','⇧⌘P'),('Billing','⌘B'),('Settings','⌘S'),('New Team', ''), ('Logout', '')]
77
+
78
+ def NavSpacedLi(t,s): return NavCloseLi(A(DivFullySpaced(P(t),P(s,cls=TextPresets.muted_sm))))
79
+
80
+ avatar_dropdown = Div(
81
+ DiceBearAvatar('Alicia Koch',8,8),
82
+ DropDownNavContainer(
83
+ NavHeaderLi('sveltecult',NavSubtitle("[email protected]")),
84
+ *[NavSpacedLi(*hk) for hk in hotkeys],))
85
+
86
+ top_nav = NavBar(
87
+ team_dropdown, *map(A, ["Overview", "Customers", "Products", "Settings"]),
88
+ brand=DivLAligned(avatar_dropdown, Input(placeholder='Search')))
89
+
90
+ @rt
91
+ def index():
92
+ return Title("Dashboard Example"), Container(
93
+ top_nav,
94
+ H2('Dashboard'),
95
+ TabContainer(
96
+ Li(A("Overview"),cls='uk-active'),
97
+ *map(lambda x: Li(A(x)), ["Analytics", "Reports", "Notifications"]),
98
+ alt=True),
99
+ top_info_row,
100
+ Grid(
101
+ Card(Safe(generate_chart(100)), cls='col-span-4'),
102
+ recent_sales,
103
+ gap=4,cols_xl=7,cols_lg=7,cols_md=1,cols_sm=1,cols_xs=1),
104
+ cls=('space-y-4', ContainerT.xl))
105
+
106
+ serve()
MonsterUI/docs/examples/data/mail.json ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "id": "6c84fb90-12c4-11e1-840d-7b25c5ee775a",
4
+ "initial": "WS",
5
+ "name": "William Smith",
6
+ "email": "[email protected]",
7
+ "subject": "Meeting Tomorrow",
8
+ "text": "Hi, let's have a meeting tomorrow to discuss the project. I've been reviewing the project details and have some ideas I'd like to share. It's crucial that we align on our next steps to ensure the project's success.\n\nPlease come prepared with any questions or insights you may have. Looking forward to our meeting!\n\nBest regards, William",
9
+ "date": "2023-10-22T09:00:00",
10
+ "read": true,
11
+ "active": true,
12
+ "labels": ["meeting", "work", "important"]
13
+ },
14
+ {
15
+ "id": "110e8400-e29b-11d4-a716-446655440000",
16
+ "initial": "AS",
17
+ "name": "Alice Smith",
18
+ "email": "[email protected]",
19
+ "subject": "Re: Project Update",
20
+ "text": "Thank you for the project update. It looks great! I've gone through the report, and the progress is impressive. The team has done a fantastic job, and I appreciate the hard work everyone has put in.\n\nI have a few minor suggestions that I'll include in the attached document.\n\nLet's discuss these during our next meeting. Keep up the excellent work!\n\nBest regards, Alice",
21
+ "date": "2023-10-22T10:30:00",
22
+ "read": true,
23
+ "active": false,
24
+ "labels": ["work", "important"]
25
+ },
26
+ {
27
+ "id": "3e7c3f6d-bdf5-46ae-8d90-171300f27ae2",
28
+ "initial": "BJ",
29
+ "name": "Bob Johnson",
30
+ "email": "[email protected]",
31
+ "subject": "Weekend Plans",
32
+ "text": "Any plans for the weekend? I was thinking of going hiking in the nearby mountains. It's been a while since we had some outdoor fun.\n\nIf you're interested, let me know, and we can plan the details. It'll be a great way to unwind and enjoy nature.\n\nLooking forward to your response!\n\nBest, Bob",
33
+ "date": "2023-04-10T11:45:00",
34
+ "read": true,
35
+ "active": false,
36
+ "labels": ["personal"]
37
+ },
38
+ {
39
+ "id": "61c35085-72d7-42b4-8d62-738f700d4b92",
40
+ "initial": "ED",
41
+ "name": "Emily Davis",
42
+ "email": "[email protected]",
43
+ "subject": "Re: Question about Budget",
44
+ "text": "I have a question about the budget for the upcoming project. It seems like there's a discrepancy in the allocation of resources.\n\nI've reviewed the budget report and identified a few areas where we might be able to optimize our spending without compromising the project's quality.\n\nI've attached a detailed analysis for your reference. Let's discuss this further in our next meeting.\n\nThanks, Emily",
45
+ "date": "2023-03-25T13:15:00",
46
+ "read": false,
47
+ "active": false,
48
+ "labels": ["work", "budget"]
49
+ },
50
+ {
51
+ "id": "8f7b5db9-d935-4e42-8e05-1f1d0a3dfb97",
52
+ "initial": "MW",
53
+ "name": "Michael Wilson",
54
+ "email": "[email protected]",
55
+ "subject": "Important Announcement",
56
+ "text": "I have an important announcement to make during our team meeting. It pertains to a strategic shift in our approach to the upcoming product launch. We've received valuable feedback from our beta testers, and I believe it's time to make some adjustments to better meet our customers' needs.\n\nThis change is crucial to our success, and I look forward to discussing it with the team. Please be prepared to share your insights during the meeting.\n\nRegards, Michael",
57
+ "date": "2023-03-10T15:00:00",
58
+ "read": false,
59
+ "active": false,
60
+ "labels": ["meeting", "work", "important"]
61
+ },
62
+ {
63
+ "id": "1f0f2c02-e299-40de-9b1d-86ef9e42126b",
64
+ "initial": "SB",
65
+ "name": "Sarah Brown",
66
+ "email": "[email protected]",
67
+ "subject": "Re: Feedback on Proposal",
68
+ "text": "Thank you for your feedback on the proposal. It looks great! I'm pleased to hear that you found it promising. The team worked diligently to address all the key points you raised, and I believe we now have a strong foundation for the project.\n\nI've attached the revised proposal for your review.\n\nPlease let me know if you have any further comments or suggestions. Looking forward to your response.\n\nBest regards, Sarah",
69
+ "date": "2023-02-15T16:30:00",
70
+ "read": true,
71
+ "active": false,
72
+ "labels": ["work"]
73
+ },
74
+ {
75
+ "id": "17c0a96d-4415-42b1-8b4f-764efab57f66",
76
+ "initial": "DL",
77
+ "name": "David Lee",
78
+ "email": "[email protected]",
79
+ "subject": "New Project Idea",
80
+ "text": "I have an exciting new project idea to discuss with you. It involves expanding our services to target a niche market that has shown considerable growth in recent months.\n\nI've prepared a detailed proposal outlining the potential benefits and the strategy for execution.\n\nThis project has the potential to significantly impact our business positively. Let's set up a meeting to dive into the details and determine if it aligns with our current goals.\n\nBest regards, David",
81
+ "date": "2023-01-28T17:45:00",
82
+ "read": false,
83
+ "active": false,
84
+ "labels": ["meeting", "work", "important"]
85
+ },
86
+ {
87
+ "id": "2f0130cb-39fc-44c4-bb3c-0a4337edaaab",
88
+ "initial": "OW",
89
+ "name": "Olivia Wilson",
90
+ "email": "[email protected]",
91
+ "subject": "Vacation Plans",
92
+ "text": "Let's plan our vacation for next month. What do you think? I've been thinking of visiting a tropical paradise, and I've put together some destination options.\n\nI believe it's time for us to unwind and recharge. Please take a look at the options and let me know your preferences.\n\nWe can start making arrangements to ensure a smooth and enjoyable trip.\n\nExcited to hear your thoughts! Olivia",
93
+ "date": "2022-12-20T18:30:00",
94
+ "read": true,
95
+ "active": false,
96
+ "labels": ["personal"]
97
+ },
98
+ {
99
+ "id": "de305d54-75b4-431b-adb2-eb6b9e546014",
100
+ "initial": "JM",
101
+ "name": "James Martin",
102
+ "email": "[email protected]",
103
+ "subject": "Re: Conference Registration",
104
+ "text": "I've completed the registration for the conference next month. The event promises to be a great networking opportunity, and I'm looking forward to attending the various sessions and connecting with industry experts.\n\nI've also attached the conference schedule for your reference.\n\nIf there are any specific topics or sessions you'd like me to explore, please let me know. It's an exciting event, and I'll make the most of it.\n\nBest regards, James",
105
+ "date": "2022-11-30T19:15:00",
106
+ "read": true,
107
+ "active": false,
108
+ "labels": ["work", "conference"]
109
+ },
110
+ {
111
+ "id": "7dd90c63-00f6-40f3-bd87-5060a24e8ee7",
112
+ "initial": "SW",
113
+ "name": "Sophia White",
114
+ "email": "[email protected]",
115
+ "subject": "Team Dinner",
116
+ "text": "Let's have a team dinner next week to celebrate our success. We've achieved some significant milestones, and it's time to acknowledge our hard work and dedication.\n\nI've made reservations at a lovely restaurant, and I'm sure it'll be an enjoyable evening.\n\nPlease confirm your availability and any dietary preferences. Looking forward to a fun and memorable dinner with the team!\n\nBest, Sophia",
117
+ "date": "2022-11-05T20:30:00",
118
+ "read": false,
119
+ "active": false,
120
+ "labels": ["meeting", "work"]
121
+ },
122
+ {
123
+ "id": "99a88f78-3eb4-4d87-87b7-7b15a49a0a05",
124
+ "initial": "DJ",
125
+ "name": "Daniel Johnson",
126
+ "email": "[email protected]",
127
+ "subject": "Feedback Request",
128
+ "text": "I'd like your feedback on the latest project deliverables. We've made significant progress, and I value your input to ensure we're on the right track.\n\nI've attached the deliverables for your review, and I'm particularly interested in any areas where you think we can further enhance the quality or efficiency.\n\nYour feedback is invaluable, and I appreciate your time and expertise. Let's work together to make this project a success.\n\nRegards, Daniel",
129
+ "date": "2022-10-22T09:30:00",
130
+ "read": false,
131
+ "active": false,
132
+ "labels": ["work"]
133
+ },
134
+ {
135
+ "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
136
+ "initial": "AT",
137
+ "name": "Ava Taylor",
138
+ "email": "[email protected]",
139
+ "subject": "Re: Meeting Agenda",
140
+ "text": "Here's the agenda for our meeting next week. I've included all the topics we need to cover, as well as time allocations for each.\n\nIf you have any additional items to discuss or any specific points to address, please let me know, and we can integrate them into the agenda.\n\nIt's essential that our meeting is productive and addresses all relevant matters.\n\nLooking forward to our meeting! Ava",
141
+ "date": "2022-10-10T10:45:00",
142
+ "read": true,
143
+ "active": false,
144
+ "labels": ["meeting", "work"]
145
+ },
146
+ {
147
+ "id": "c1a0ecb4-2540-49c5-86f8-21e5ce79e4e6",
148
+ "initial": "WA",
149
+ "name": "William Anderson",
150
+ "email": "[email protected]",
151
+ "subject": "Product Launch Update",
152
+ "text": "The product launch is on track. I'll provide an update during our call. We've made substantial progress in the development and marketing of our new product.\n\nI'm excited to share the latest updates with you during our upcoming call. It's crucial that we coordinate our efforts to ensure a successful launch. Please come prepared with any questions or insights you may have.\n\nLet's make this product launch a resounding success!\n\nBest regards, William",
153
+ "date": "2022-09-20T12:00:00",
154
+ "read": false,
155
+ "active": false,
156
+ "labels": ["meeting", "work", "important"]
157
+ },
158
+ {
159
+ "id": "ba54eefd-4097-4949-99f2-2a9ae4d1a836",
160
+ "initial": "MH",
161
+ "name": "Mia Harris",
162
+ "email": "[email protected]",
163
+ "subject": "Re: Travel Itinerary",
164
+ "text": "I've received the travel itinerary. It looks great! Thank you for your prompt assistance in arranging the details. I've reviewed the schedule and the accommodations, and everything seems to be in order. I'm looking forward to the trip, and I'm confident it'll be a smooth and enjoyable experience.\n\nIf there are any specific activities or attractions you recommend at our destination, please feel free to share your suggestions.\n\nExcited for the trip! Mia",
165
+ "date": "2022-09-10T13:15:00",
166
+ "read": true,
167
+ "active": false,
168
+ "labels": ["personal", "travel"]
169
+ },
170
+ {
171
+ "id": "df09b6ed-28bd-4e0c-85a9-9320ec5179aa",
172
+ "initial": "EC",
173
+ "name": "Ethan Clark",
174
+ "email": "[email protected]",
175
+ "subject": "Team Building Event",
176
+ "text": "Let's plan a team-building event for our department. Team cohesion and morale are vital to our success, and I believe a well-organized team-building event can be incredibly beneficial. I've done some research and have a few ideas for fun and engaging activities.\n\nPlease let me know your thoughts and availability. We want this event to be both enjoyable and productive.\n\nTogether, we'll strengthen our team and boost our performance.\n\nRegards, Ethan",
177
+ "date": "2022-08-25T15:30:00",
178
+ "read": false,
179
+ "active": false,
180
+ "labels": ["meeting", "work"]
181
+ },
182
+ {
183
+ "id": "d67c1842-7f8b-4b4b-9be1-1b3b1ab4611d",
184
+ "initial": "CH",
185
+ "name": "Chloe Hall",
186
+ "email": "[email protected]",
187
+ "subject": "Re: Budget Approval",
188
+ "text": "The budget has been approved. We can proceed with the project. I'm delighted to inform you that our budget proposal has received the green light from the finance department. This is a significant milestone, and it means we can move forward with the project as planned.\n\nI've attached the finalized budget for your reference. Let's ensure that we stay on track and deliver the project on time and within budget.\n\nIt's an exciting time for us! Chloe",
189
+ "date": "2022-08-10T16:45:00",
190
+ "read": true,
191
+ "active": false,
192
+ "labels": ["work", "budget"]
193
+ },
194
+ {
195
+ "id": "6c9a7f94-8329-4d70-95d3-51f68c186ae1",
196
+ "initial": "ST",
197
+ "name": "Samuel Turner",
198
+ "email": "[email protected]",
199
+ "subject": "Weekend Hike",
200
+ "text": "Who's up for a weekend hike in the mountains? I've been craving some outdoor adventure, and a hike in the mountains sounds like the perfect escape. If you're up for the challenge, we can explore some scenic trails and enjoy the beauty of nature.\n\nI've done some research and have a few routes in mind.\n\nLet me know if you're interested, and we can plan the details.\n\nIt's sure to be a memorable experience! Samuel",
201
+ "date": "2022-07-28T17:30:00",
202
+ "read": false,
203
+ "active": false,
204
+ "labels": ["personal"]
205
+ }
206
+ ]
MonsterUI/docs/examples/data/status_list.json ADDED
@@ -0,0 +1 @@
 
 
1
+ [{"selected": true, "id": "TASK-8782", "title": "You can't compress the program without quantifying the open-source SSD pixel!", "status": "progress", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-7878", "title": "Try to calculate the EXE feed, maybe it will index the multi-byte pixel!", "status": "backlog", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-7839", "title": "We need to bypass the neural TCP card!", "status": "todo", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-5562", "title": "The SAS interface is down, bypass the open-source pixel so we can back up the PNG bandwidth!", "status": "backlog", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-8686", "title": "I'll parse the wireless SSL protocol, that should driver the API panel!", "status": "cancelled", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-1280", "title": "Use the digital TLS panel, then you can transmit the haptic system!", "status": "done", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-7262", "title": "The UTF8 application is down, parse the neural bandwidth so we can back up the PNG firewall!", "status": "done", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-1138", "title": "Generating the driver won't do anything, we need to quantify the 1080p SMTP bandwidth!", "status": "progress", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-7184", "title": "We need to program the back-end THX pixel!", "status": "todo", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-5160", "title": "Calculating the bus won't do anything, we need to navigate the back-end JSON protocol!", "status": "progress", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-5618", "title": "Generating the driver won't do anything, we need to index the online SSL application!", "status": "done", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-6699", "title": "I'll transmit the wireless JBOD capacitor, that should hard drive the SSD feed!", "status": "backlog", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-2858", "title": "We need to override the online UDP bus!", "status": "backlog", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-9864", "title": "I'll reboot the 1080p FTP panel, that should matrix the HEX hard drive!", "status": "done", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-8404", "title": "We need to generate the virtual HEX alarm!", "status": "progress", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-5365", "title": "Backing up the pixel won't do anything, we need to transmit the primary IB array!", "status": "progress", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-1780", "title": "The CSS feed is down, index the bluetooth transmitter so we can compress the CLI protocol!", "status": "todo", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-6938", "title": "Use the redundant SCSI application, then you can hack the optical alarm!", "status": "todo", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-9885", "title": "We need to compress the auxiliary VGA driver!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-3216", "title": "Transmitting the transmitter won't do anything, we need to compress the virtual HDD sensor!", "status": "backlog", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-9285", "title": "The IP monitor is down, copy the haptic alarm so we can generate the HTTP transmitter!", "status": "todo", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-1024", "title": "Overriding the microchip won't do anything, we need to transmit the digital OCR transmitter!", "status": "progress", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-7068", "title": "You can't generate the capacitor without indexing the wireless HEX pixel!", "status": "cancelled", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-6502", "title": "Navigating the microchip won't do anything, we need to bypass the back-end SQL bus!", "status": "todo", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-5326", "title": "We need to hack the redundant UTF8 transmitter!", "status": "todo", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-6274", "title": "Use the virtual PCI circuit, then you can parse the bluetooth alarm!", "status": "cancelled", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-1571", "title": "I'll input the neural DRAM circuit, that should protocol the SMTP interface!", "status": "progress", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-9518", "title": "Compressing the interface won't do anything, we need to compress the online SDD matrix!", "status": "cancelled", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-5581", "title": "I'll synthesize the digital COM pixel, that should transmitter the UTF8 protocol!", "status": "backlog", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-2197", "title": "Parsing the feed won't do anything, we need to copy the bluetooth DRAM bus!", "status": "todo", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-8484", "title": "We need to parse the solid state UDP firewall!", "status": "progress", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-9892", "title": "If we back up the application, we can get to the UDP application through the multi-byte THX capacitor!", "status": "done", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-9616", "title": "We need to synthesize the cross-platform ASCII pixel!", "status": "progress", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-9744", "title": "Use the back-end IP card, then you can input the solid state hard drive!", "status": "done", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-1376", "title": "Generating the alarm won't do anything, we need to generate the mobile IP capacitor!", "status": "backlog", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-7382", "title": "If we back up the firewall, we can get to the RAM alarm through the primary UTF8 pixel!", "status": "todo", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-2290", "title": "I'll compress the virtual JSON panel, that should application the UTF8 bus!", "status": "cancelled", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-1533", "title": "You can't input the firewall without overriding the wireless TCP firewall!", "status": "done", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-4920", "title": "Bypassing the hard drive won't do anything, we need to input the bluetooth JSON program!", "status": "progress", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-5168", "title": "If we synthesize the bus, we can get to the IP panel through the virtual TLS array!", "status": "progress", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-7103", "title": "We need to parse the multi-byte EXE bandwidth!", "status": "cancelled", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-4314", "title": "If we compress the program, we can get to the XML alarm through the multi-byte COM matrix!", "status": "progress", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-3415", "title": "Use the cross-platform XML application, then you can quantify the solid state feed!", "status": "todo", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-8339", "title": "Try to calculate the DNS interface, maybe it will input the bluetooth capacitor!", "status": "progress", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-6995", "title": "Try to hack the XSS bandwidth, maybe it will override the bluetooth matrix!", "status": "todo", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-8053", "title": "If we connect the program, we can get to the UTF8 matrix through the digital UDP protocol!", "status": "todo", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-4336", "title": "If we synthesize the microchip, we can get to the SAS sensor through the optical UDP program!", "status": "todo", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-8790", "title": "I'll back up the optical COM alarm, that should alarm the RSS capacitor!", "status": "done", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-8980", "title": "Try to navigate the SQL transmitter, maybe it will back up the virtual firewall!", "status": "cancelled", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-7342", "title": "Use the neural CLI card, then you can parse the online port!", "status": "backlog", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-5608", "title": "I'll hack the haptic SSL program, that should bus the UDP transmitter!", "status": "cancelled", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-1606", "title": "I'll generate the bluetooth PNG firewall, that should pixel the SSL driver!", "status": "done", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-7872", "title": "Transmitting the circuit won't do anything, we need to reboot the 1080p RSS monitor!", "status": "cancelled", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-4167", "title": "Use the cross-platform SMS circuit, then you can synthesize the optical feed!", "status": "cancelled", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-9581", "title": "You can't index the port without hacking the cross-platform XSS monitor!", "status": "backlog", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-8806", "title": "We need to bypass the back-end SSL panel!", "status": "done", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-6542", "title": "Try to quantify the RSS firewall, maybe it will quantify the open-source system!", "status": "done", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-6806", "title": "The VGA protocol is down, reboot the back-end matrix so we can parse the CSS panel!", "status": "cancelled", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-9549", "title": "You can't bypass the bus without connecting the neural JBOD bus!", "status": "todo", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-1075", "title": "Backing up the driver won't do anything, we need to parse the redundant RAM pixel!", "status": "done", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-1427", "title": "Use the auxiliary PCI circuit, then you can calculate the cross-platform interface!", "status": "done", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-1907", "title": "Hacking the circuit won't do anything, we need to back up the online DRAM system!", "status": "todo", "label": "documentation", "priority": "high"}, {"selected": false, "id": "TASK-4309", "title": "If we generate the system, we can get to the TCP sensor through the optical GB pixel!", "status": "backlog", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-3973", "title": "I'll parse the back-end ADP array, that should bandwidth the RSS bandwidth!", "status": "todo", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-7962", "title": "Use the wireless RAM program, then you can hack the cross-platform feed!", "status": "cancelled", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-3360", "title": "You can't quantify the program without synthesizing the neural OCR interface!", "status": "done", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-9887", "title": "Use the auxiliary ASCII sensor, then you can connect the solid state port!", "status": "backlog", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-3649", "title": "I'll input the virtual USB system, that should circuit the DNS monitor!", "status": "progress", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-3586", "title": "If we quantify the circuit, we can get to the CLI feed through the mobile SMS hard drive!", "status": "progress", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-5150", "title": "I'll hack the wireless XSS port, that should transmitter the IP interface!", "status": "cancelled", "label": "feature", "priority": "medium"}, {"selected": false, "id": "TASK-3652", "title": "The SQL interface is down, override the optical bus so we can program the ASCII interface!", "status": "backlog", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-6884", "title": "Use the digital PCI circuit, then you can synthesize the multi-byte microchip!", "status": "cancelled", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-1591", "title": "We need to connect the mobile XSS driver!", "status": "progress", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-3802", "title": "Try to override the ASCII protocol, maybe it will parse the virtual matrix!", "status": "progress", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-7253", "title": "Programming the capacitor won't do anything, we need to bypass the neural IB hard drive!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-9739", "title": "We need to hack the multi-byte HDD bus!", "status": "done", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-4424", "title": "Try to hack the HEX alarm, maybe it will connect the optical pixel!", "status": "progress", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-3922", "title": "You can't back up the capacitor without generating the wireless PCI program!", "status": "backlog", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-4921", "title": "I'll index the open-source IP feed, that should system the GB application!", "status": "cancelled", "label": "bug", "priority": "low"}, {"selected": false, "id": "TASK-5814", "title": "We need to calculate the 1080p AGP feed!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-2645", "title": "Synthesizing the system won't do anything, we need to navigate the multi-byte HDD firewall!", "status": "todo", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-4535", "title": "Try to copy the JSON circuit, maybe it will connect the wireless feed!", "status": "progress", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-4463", "title": "We need to copy the solid state AGP monitor!", "status": "done", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-9745", "title": "If we connect the protocol, we can get to the GB system through the bluetooth PCI microchip!", "status": "cancelled", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-2080", "title": "If we input the bus, we can get to the RAM matrix through the auxiliary RAM card!", "status": "todo", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-3838", "title": "I'll bypass the online TCP application, that should panel the AGP system!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-1340", "title": "We need to navigate the virtual PNG circuit!", "status": "todo", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-6665", "title": "If we parse the monitor, we can get to the SSD hard drive through the cross-platform AGP alarm!", "status": "cancelled", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-7585", "title": "If we calculate the hard drive, we can get to the SSL program through the multi-byte CSS microchip!", "status": "backlog", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-6319", "title": "We need to copy the multi-byte SCSI program!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-4369", "title": "Try to input the SCSI bus, maybe it will generate the 1080p pixel!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-9035", "title": "We need to override the solid state PNG array!", "status": "cancelled", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-3970", "title": "You can't index the transmitter without quantifying the haptic ASCII card!", "status": "todo", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-4473", "title": "You can't bypass the protocol without overriding the neural RSS program!", "status": "todo", "label": "documentation", "priority": "low"}, {"selected": false, "id": "TASK-4136", "title": "You can't hack the hard drive without hacking the primary JSON program!", "status": "cancelled", "label": "bug", "priority": "medium"}, {"selected": false, "id": "TASK-3939", "title": "Use the back-end SQL firewall, then you can connect the neural hard drive!", "status": "done", "label": "feature", "priority": "low"}, {"selected": false, "id": "TASK-2007", "title": "I'll input the back-end USB protocol, that should bandwidth the PCI system!", "status": "backlog", "label": "bug", "priority": "high"}, {"selected": false, "id": "TASK-7516", "title": "Use the primary SQL program, then you can generate the auxiliary transmitter!", "status": "done", "label": "documentation", "priority": "medium"}, {"selected": false, "id": "TASK-6906", "title": "Try to back up the DRAM system, maybe it will reboot the online transmitter!", "status": "done", "label": "feature", "priority": "high"}, {"selected": false, "id": "TASK-5207", "title": "The SMS interface is down, copy the bluetooth bus so we can quantify the VGA card!", "status": "progress", "label": "bug", "priority": "low"}]
MonsterUI/docs/examples/data/statuses.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backlog": {
3
+ "icon": "<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-2 h-4 w-4 text-muted-foreground\"><path d=\"M0.877075 7.49972C0.877075 3.84204 3.84222 0.876892 7.49991 0.876892C11.1576 0.876892 14.1227 3.84204 14.1227 7.49972C14.1227 11.1574 11.1576 14.1226 7.49991 14.1226C3.84222 14.1226 0.877075 11.1574 0.877075 7.49972ZM7.49991 1.82689C4.36689 1.82689 1.82708 4.36671 1.82708 7.49972C1.82708 10.6327 4.36689 13.1726 7.49991 13.1726C10.6329 13.1726 13.1727 10.6327 13.1727 7.49972C13.1727 4.36671 10.6329 1.82689 7.49991 1.82689ZM8.24993 10.5C8.24993 10.9142 7.91414 11.25 7.49993 11.25C7.08571 11.25 6.74993 10.9142 6.74993 10.5C6.74993 10.0858 7.08571 9.75 7.49993 9.75C7.91414 9.75 8.24993 10.0858 8.24993 10.5ZM6.05003 6.25C6.05003 5.57211 6.63511 4.925 7.50003 4.925C8.36496 4.925 8.95003 5.57211 8.95003 6.25C8.95003 6.74118 8.68002 6.99212 8.21447 7.27494C8.16251 7.30651 8.10258 7.34131 8.03847 7.37854L8.03841 7.37858C7.85521 7.48497 7.63788 7.61119 7.47449 7.73849C7.23214 7.92732 6.95003 8.23198 6.95003 8.7C6.95004 9.00376 7.19628 9.25 7.50004 9.25C7.8024 9.25 8.04778 9.00601 8.05002 8.70417L8.05056 8.7033C8.05924 8.6896 8.08493 8.65735 8.15058 8.6062C8.25207 8.52712 8.36508 8.46163 8.51567 8.37436L8.51571 8.37433C8.59422 8.32883 8.68296 8.27741 8.78559 8.21506C9.32004 7.89038 10.05 7.35382 10.05 6.25C10.05 4.92789 8.93511 3.825 7.50003 3.825C6.06496 3.825 4.95003 4.92789 4.95003 6.25C4.95003 6.55376 5.19628 6.8 5.50003 6.8C5.80379 6.8 6.05003 6.55376 6.05003 6.25Z\" fill=\"currentColor\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"></path></svg>",
4
+ "text": "Backlog"
5
+ },
6
+ "cancelled": {
7
+ "icon": "<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-2 h-4 w-4 text-muted-foreground\"><path d=\"M0.877075 7.49988C0.877075 3.84219 3.84222 0.877045 7.49991 0.877045C11.1576 0.877045 14.1227 3.84219 14.1227 7.49988C14.1227 11.1575 11.1576 14.1227 7.49991 14.1227C3.84222 14.1227 0.877075 11.1575 0.877075 7.49988ZM7.49991 1.82704C4.36689 1.82704 1.82708 4.36686 1.82708 7.49988C1.82708 10.6329 4.36689 13.1727 7.49991 13.1727C10.6329 13.1727 13.1727 10.6329 13.1727 7.49988C13.1727 4.36686 10.6329 1.82704 7.49991 1.82704ZM9.85358 5.14644C10.0488 5.3417 10.0488 5.65829 9.85358 5.85355L8.20713 7.49999L9.85358 9.14644C10.0488 9.3417 10.0488 9.65829 9.85358 9.85355C9.65832 10.0488 9.34173 10.0488 9.14647 9.85355L7.50002 8.2071L5.85358 9.85355C5.65832 10.0488 5.34173 10.0488 5.14647 9.85355C4.95121 9.65829 4.95121 9.3417 5.14647 9.14644L6.79292 7.49999L5.14647 5.85355C4.95121 5.65829 4.95121 5.3417 5.14647 5.14644C5.34173 4.95118 5.65832 4.95118 5.85358 5.14644L7.50002 6.79289L9.14647 5.14644C9.34173 4.95118 9.65832 4.95118 9.85358 5.14644Z\" fill=\"currentColor\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"></path></svg>",
8
+ "text": "Cancelled"
9
+ },
10
+ "done": {
11
+ "icon": "<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-2 h-4 w-4 text-muted-foreground\"><path d=\"M7.49991 0.877045C3.84222 0.877045 0.877075 3.84219 0.877075 7.49988C0.877075 11.1575 3.84222 14.1227 7.49991 14.1227C11.1576 14.1227 14.1227 11.1575 14.1227 7.49988C14.1227 3.84219 11.1576 0.877045 7.49991 0.877045ZM1.82708 7.49988C1.82708 4.36686 4.36689 1.82704 7.49991 1.82704C10.6329 1.82704 13.1727 4.36686 13.1727 7.49988C13.1727 10.6329 10.6329 13.1727 7.49991 13.1727C4.36689 13.1727 1.82708 10.6329 1.82708 7.49988ZM10.1589 5.53774C10.3178 5.31191 10.2636 5.00001 10.0378 4.84109C9.81194 4.68217 9.50004 4.73642 9.34112 4.96225L6.51977 8.97154L5.35681 7.78706C5.16334 7.59002 4.84677 7.58711 4.64973 7.78058C4.45268 7.97404 4.44978 8.29061 4.64325 8.48765L6.22658 10.1003C6.33054 10.2062 6.47617 10.2604 6.62407 10.2483C6.77197 10.2363 6.90686 10.1591 6.99226 10.0377L10.1589 5.53774Z\" fill=\"currentColor\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"></path></svg>",
12
+ "text": "Done"
13
+ },
14
+ "progress": {
15
+ "icon": "<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-2 h-4 w-4 text-muted-foreground\"><path d=\"M5.49998 0.5C5.49998 0.223858 5.72383 0 5.99998 0H7.49998H8.99998C9.27612 0 9.49998 0.223858 9.49998 0.5C9.49998 0.776142 9.27612 1 8.99998 1H7.99998V2.11922C9.09832 2.20409 10.119 2.56622 10.992 3.13572C11.0116 3.10851 11.0336 3.08252 11.058 3.05806L11.858 2.25806C12.1021 2.01398 12.4978 2.01398 12.7419 2.25806C12.986 2.50214 12.986 2.89786 12.7419 3.14194L11.967 3.91682C13.1595 5.07925 13.9 6.70314 13.9 8.49998C13.9 12.0346 11.0346 14.9 7.49998 14.9C3.96535 14.9 1.09998 12.0346 1.09998 8.49998C1.09998 5.13362 3.69904 2.3743 6.99998 2.11922V1H5.99998C5.72383 1 5.49998 0.776142 5.49998 0.5ZM2.09998 8.49998C2.09998 5.51764 4.51764 3.09998 7.49998 3.09998C10.4823 3.09998 12.9 5.51764 12.9 8.49998C12.9 11.4823 10.4823 13.9 7.49998 13.9C4.51764 13.9 2.09998 11.4823 2.09998 8.49998ZM7.99998 4.5C7.99998 4.22386 7.77612 4 7.49998 4C7.22383 4 6.99998 4.22386 6.99998 4.5V9.5C6.99998 9.77614 7.22383 10 7.49998 10C7.77612 10 7.99998 9.77614 7.99998 9.5V4.5Z\" fill=\"currentColor\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"></path></svg>",
16
+ "text": "In Progress"
17
+ },
18
+ "todo": {
19
+ "icon": "<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"mr-2 h-4 w-4 text-muted-foreground\"><path d=\"M0.877075 7.49991C0.877075 3.84222 3.84222 0.877075 7.49991 0.877075C11.1576 0.877075 14.1227 3.84222 14.1227 7.49991C14.1227 11.1576 11.1576 14.1227 7.49991 14.1227C3.84222 14.1227 0.877075 11.1576 0.877075 7.49991ZM7.49991 1.82708C4.36689 1.82708 1.82708 4.36689 1.82708 7.49991C1.82708 10.6329 4.36689 13.1727 7.49991 13.1727C10.6329 13.1727 13.1727 10.6329 13.1727 7.49991C13.1727 4.36689 10.6329 1.82708 7.49991 1.82708Z\" fill=\"currentColor\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"></path></svg>",
20
+ "text": "Todo"
21
+ }
22
+ }
MonsterUI/docs/examples/forms.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FrankenUI Forms Example built with MonsterUI (original design by ShadCN)"""
2
+
3
+
4
+ from fasthtml.common import *
5
+ from monsterui.all import *
6
+ from fasthtml.svg import *
7
+
8
+ app, rt = fast_app(hdrs=Theme.blue.headers())
9
+
10
+ def HelpText(c): return P(c,cls=TextPresets.muted_sm)
11
+
12
+ def heading():
13
+ return Div(cls="space-y-5")(
14
+ H2("Settings"),
15
+ Subtitle("Manage your account settings and set e-mail preferences."),
16
+ DividerSplit())
17
+
18
+
19
+ sidebar = NavContainer(
20
+ *map(lambda x: Li(A(x)), ("Profile", "Account", "Appearance", "Notifications", "Display")),
21
+ uk_switcher="connect: #component-nav; animation: uk-animation-fade",
22
+ cls=(NavT.secondary,"space-y-4 p-4 w-1/5"))
23
+
24
+
25
+ def FormSectionDiv(*c, cls='space-y-2', **kwargs): return Div(*c, cls=cls, **kwargs)
26
+
27
+ def FormLayout(title, subtitle, *content, cls='space-y-3 mt-4'): return Container(Div(H3(title), Subtitle(subtitle), DividerLine(), Form(*content, cls=cls)))
28
+
29
+ def profile_form():
30
+ content = (FormSectionDiv(
31
+ LabelInput("Username", placeholder='sveltecult', id='username'),
32
+ HelpText("This is your public display name. It can be your real name or a pseudonym. You can only change this once every 30 days.")),
33
+ FormSectionDiv(
34
+ LabelSelect(
35
+ Option("Select a verified email to display", value="", selected=True, disabled=True),
36
+ *[Option(o, value=o) for o in ('[email protected]', '[email protected]', '[email protected]')],
37
+ label="Email", id="email"),
38
+ HelpText("You can manage verified email addresses in your email settings.")),
39
+ FormSectionDiv(
40
+ LabelTextArea("Bio", id="bio", placeholder="Tell us a little bit about yourself"),
41
+ HelpText("You can @mention other users and organizations to link to them."),
42
+ P("String must contain at least 4 character(s)", cls="text-destructive")),
43
+ FormSectionDiv(
44
+ FormLabel("URLs"),
45
+ HelpText("Add links to your website, blog, or social media profiles."),
46
+ Input(value="https://www.franken-ui.dev"),
47
+ Input(value="https://github.com/sveltecult/franken-ui"),
48
+ Button("Add URL")),
49
+ Button('Update profile', cls=ButtonT.primary))
50
+
51
+ return FormLayout('Profile', 'This is how others will see you on the site.', *content)
52
+
53
+ def account_form():
54
+ content = (
55
+ FormSectionDiv(
56
+ LabelInput("Name", placeholder="Your name", id="name"),
57
+ HelpText("This is the name that will be displayed on your profile and in emails.")),
58
+ FormSectionDiv(
59
+ LabelInput("Date of Birth", type="date", placeholder="Pick a date", id="date_of_birth"),
60
+ HelpText("Your date of birth is used to calculate your age.")),
61
+ FormSectionDiv(
62
+ LabelSelect(*Options("Select a language", "English", "French", "German", "Spanish", "Portuguese", selected_idx=1, disabled_idxs={0}),
63
+ label='Language', id="language"),
64
+ HelpText("This is the language that will be used in the dashboard.")),
65
+ Button('Update profile', cls=ButtonT.primary))
66
+
67
+ return FormLayout('Account', 'Update your account settings. Set your preferred language and timezone.', *content)
68
+
69
+ def appearance_form():
70
+ def theme_item(bg_color, content_bg, text_bg):
71
+ common_content = f"space-y-2 rounded-md {content_bg} p-2 shadow-sm"
72
+ item_row = lambda: Div(cls=f"flex items-center space-x-2 {common_content}")(
73
+ Div(cls=f"h-4 w-4 rounded-full {text_bg}"),
74
+ Div(cls=f"h-2 w-[100px] rounded-lg {text_bg}"))
75
+
76
+ return Div(cls=f"space-y-2 rounded-sm {bg_color} p-2")(
77
+ Div(cls=common_content)(
78
+ Div(cls=f"h-2 w-[80px] rounded-lg {text_bg}"),
79
+ Div(cls=f"h-2 w-[100px] rounded-lg {text_bg}")),
80
+ item_row(),
81
+ item_row())
82
+
83
+ common_toggle_cls = "block cursor-pointer items-center rounded-md border-2 border-muted p-1 ring-ring"
84
+
85
+ content = (
86
+ FormSectionDiv(
87
+ LabelSelect(*Options('Select a font family', 'Inter', 'Geist', 'Open Sans', selected_idx=2, disabled_idxs={0}),
88
+ label='Font Family', id='font_family'),
89
+ HelpText("Set the font you want to use in the dashboard.")),
90
+ FormSectionDiv(
91
+ FormLabel("Theme"),
92
+ HelpText("Select the theme for the dashboard."),
93
+ Grid(
94
+ A(id="theme-toggle-light", cls=common_toggle_cls)(theme_item("bg-[#ecedef]", "bg-white", "bg-[#ecedef]")),
95
+ A(id="theme-toggle-dark", cls=f"{common_toggle_cls} bg-popover")(theme_item("bg-slate-950", "bg-slate-800", "bg-slate-400")),
96
+ cols_max=2,cls=('max-w-md','gap-8'))),
97
+ Button('Update preferences', cls=ButtonT.primary))
98
+
99
+ return FormLayout('Appearance', 'Customize the appearance of the app. Automatically switch between day and night themes.', *content)
100
+
101
+
102
+ notification_items = [
103
+ {"title": "Communication emails", "description": "Receive emails about your account activity.", "checked": False, "disabled": False},
104
+ {"title": "Marketing emails", "description": "Receive emails about new products, features, and more.", "checked": False, "disabled": False},
105
+ {"title": "Social emails", "description": "Receive emails for friend requests, follows, and more.", "checked": True, "disabled": False},
106
+ {"title": "Security emails", "description": "Receive emails about your account activity and security.", "checked": True, "disabled": True}]
107
+
108
+ def notifications_form():
109
+ def RadioLabel(label): return DivLAligned(Radio(name="notification", checked=(label=="Nothing")), FormLabel(label))
110
+
111
+ def NotificationCard(item):
112
+ return Card(
113
+ Div(cls="space-y-0.5")(
114
+ FormLabel(Strong(item['title'], cls=TextT.sm),
115
+ HelpText(item['description']))))
116
+ content = Div(
117
+ FormSectionDiv(
118
+ FormLabel("Notify me about"),
119
+ *map(RadioLabel, ["All new messages", "Direct messages and mentions", "Nothing"])),
120
+ Div(
121
+ H4("Email Notifications", cls="mb-4"),
122
+ Grid(*map(NotificationCard, notification_items), cols=1)),
123
+ LabelCheckboxX("Use different settings for my mobile devices", id="notification_mobile"),
124
+ HelpText("You can manage your mobile notifications in the mobile settings page."),
125
+ Button('Update notifications', cls=ButtonT.primary))
126
+
127
+ return FormLayout('Notifications', 'Configure how you receive notifications.', *content)
128
+
129
+ def display_form():
130
+ content = (
131
+ Div(cls="space-y-2")(
132
+ Div(cls="mb-4")(
133
+ H5("Sidebar"),
134
+ Subtitle("Select the items you want to display in the sidebar.")),
135
+ *[Div(CheckboxX(id=f"display_{i}", checked=i in [0, 1, 2]),FormLabel(label))
136
+ for i, label in enumerate(["Recents", "Home", "Applications", "Desktop", "Downloads", "Documents"])]),
137
+ Button('Update display', cls=ButtonT.primary))
138
+ return FormLayout('Display', 'Turn items on or off to control what\'s displayed in the app.', *content)
139
+
140
+ @rt
141
+ def index():
142
+ return Title("Forms Example"),Container(
143
+ heading(),
144
+ Div(cls="flex gap-x-12")(
145
+ sidebar,
146
+ Ul(id="component-nav", cls="uk-switcher max-w-2xl")(
147
+ Li(cls="uk-active")(profile_form(),
148
+ *map(Li, [account_form(), appearance_form(), notifications_form(), display_form()])))))
149
+
150
+ serve()
MonsterUI/docs/examples/mail.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FrankenUI Mail Example built with MonsterUI (original design by ShadCN)"""
2
+
3
+ from fasthtml.common import *
4
+ from monsterui.all import *
5
+ from fasthtml.svg import *
6
+ import pathlib, json
7
+ from datetime import datetime
8
+
9
+ app, rt = fast_app(hdrs=Theme.blue.headers())
10
+
11
+ sidebar_group1 = (('home', 'Inbox', '128'), ('file-text', 'Drafts', '9'), (' arrow-up-right', 'Sent', ''),
12
+ ('ban', 'Junk', '23'), ('trash', 'Trash', ''), ('folder', 'Archive', ''))
13
+
14
+ sidebar_group2 = (('globe','Social','972'),('info','Updates','342'),('messages-square','Forums','128'),
15
+ ('shopping-cart','Shopping','8'),('shopping-bag','Promotions','21'),)
16
+
17
+ def MailSbLi(icon, title, cnt):
18
+ return Li(A(DivLAligned(Span(UkIcon(icon)),Span(title),P(cnt, cls=TextPresets.muted_sm)),href='#', cls='hover:bg-secondary p-4'))
19
+
20
+ sidebar = NavContainer(
21
+ NavHeaderLi(H3("Email"), cls='p-3'),
22
+ Li(Select(map(Option, ('[email protected]','[email protected]', '[email protected]')))),
23
+ *[MailSbLi(i, t, c) for i, t, c in sidebar_group1],
24
+ Li(Hr()),
25
+ *[MailSbLi(i, t, c) for i, t, c in sidebar_group2],
26
+ cls='mt-3')
27
+
28
+ mail_data = json.load(open(pathlib.Path('data_/mail.json')))
29
+
30
+ def format_date(date_str):
31
+ date_obj = datetime.fromisoformat(date_str)
32
+ return date_obj.strftime("%Y-%m-%d %I:%M %p")
33
+
34
+ def MailItem(mail):
35
+ cls_base = 'relative rounded-lg border border-border p-3 text-sm hover:bg-secondary space-y-2'
36
+ cls = f"{cls_base} {'bg-muted' if mail == mail_data[0] else ''} {'tag-unread' if not mail['read'] else 'tag-mail'}"
37
+
38
+ return Li(
39
+ DivFullySpaced(
40
+ DivLAligned(
41
+ Strong(mail['name']),
42
+ Span(cls='flex h-2 w-2 rounded-full bg-blue-600') if not mail['read'] else ''),
43
+ Time(format_date(mail['date']), cls='text-xs')),
44
+ Small(mail['subject'], href=f"#mail-{mail['id']}"),
45
+ Div(mail['text'][:100] + '...', cls=TextPresets.muted_sm),
46
+ DivLAligned(
47
+ *[Label(A(label, href='#'), cls='uk-label-primary' if label == 'work' else '') for label in mail['labels']]),
48
+ cls=cls)
49
+
50
+ def MailList(mails): return Ul(cls='js-filter space-y-2 p-4 pt-0')(*[MailItem(mail) for mail in mails])
51
+
52
+ def MailContent():
53
+ return Div(cls='flex flex-col',uk_filter="target: .js-filter")(
54
+ Div(cls='flex px-4 py-2 ')(
55
+ H3('Inbox'),
56
+ TabContainer(Li(A("All Mail",href='#', role='button'),cls='uk-active', uk_filter_control="filter: .tag-mail"),
57
+ Li(A("Unread",href='#', role='button'), uk_filter_control="filter: .tag-unread"),
58
+ alt=True, cls='ml-auto max-w-40', )),
59
+ Div(cls='flex flex-1 flex-col')(
60
+ Div(cls='p-4')(
61
+ Div(cls='uk-inline w-full')(
62
+ Span(cls='uk-form-icon text-muted-foreground')(UkIcon('search')),
63
+ Input(placeholder='Search'))),
64
+ Div(cls='flex-1 overflow-y-auto max-h-[600px]')(MailList(mail_data))))
65
+
66
+ def IconNavItem(*d): return [Li(A(UkIcon(o[0],uk_tooltip=o[1]))) for o in d]
67
+ def IconNav(*c,cls=''): return Ul(cls=f'uk-iconnav {cls}')(*c)
68
+
69
+ def MailDetailView(mail):
70
+ top_icons = [('folder','Archive'), ('ban','Move to junk'), ('trash','Move to trash')]
71
+ reply_icons = [('reply','Reply'), ('reply','Reply all'), ('forward','Forward')]
72
+ dropdown_items = ['Mark as unread', 'Star read', 'Add Label', 'Mute Thread']
73
+
74
+ return Container(
75
+ DivFullySpaced(
76
+ DivLAligned(
77
+ DivLAligned(*[UkIcon(o[0],uk_tooltip=o[1]) for o in top_icons]),
78
+ Div(UkIcon('clock', uk_tooltip='Snooze'), cls='pl-2'),
79
+ cls='space-x-2 divide-x divide-border'),
80
+ DivLAligned(
81
+ *[UkIcon(o[0],uk_tooltip=o[1]) for o in reply_icons],
82
+ Div(UkIcon('ellipsis-vertical',button=True)),
83
+ DropDownNavContainer(*map(lambda x: Li(A(x)), dropdown_items)))),
84
+ DivLAligned(
85
+ Span(mail['name'][:2], cls='flex h-10 w-10 items-center justify-center rounded-full bg-muted'),
86
+ Div(Strong(mail['name']),
87
+ Div(mail['subject']),
88
+ DivLAligned(P('Reply-To:'), A(mail['email'], href=f"mailto:{mail['email']}"), cls='space-x-1'),
89
+ P(Time(format_date(mail['date']))),
90
+ cls='space-y-1'+TextT.sm),
91
+ cls='m-4 space-x-4'),
92
+ DividerLine(),
93
+ P(mail['text'], cls=TextT.sm +'p-4'),
94
+ DividerLine(),
95
+ Div(TextArea(id='message', placeholder=f"Reply {mail['name']}"),
96
+ DivFullySpaced(
97
+ LabelSwitch('Mute this thread',id='mute'),
98
+ Button('Send', cls=ButtonT.primary)),
99
+ cls='space-y-4'))
100
+
101
+ @rt
102
+ def index():
103
+ return Title("Mail Example"),Container(
104
+ Grid(Div(sidebar, cls='col-span-1'),
105
+ Div(MailContent(), cls='col-span-2'),
106
+ Div(MailDetailView(mail_data[0]), cls='col-span-2'),
107
+ cols_sm=1, cols_md=1, cols_lg=5, cols_xl=5,
108
+ gap=0, cls='flex-1'),
109
+ cls=('flex', ContainerT.xl))
110
+
111
+ serve()
MonsterUI/docs/examples/music.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FrankenUI Music Example build with MonsterUI (Original design by ShadCN)"""
2
+
3
+ from fasthtml.common import *
4
+
5
+ from monsterui.all import *
6
+
7
+ app, rt = fast_app(hdrs=Theme.blue.headers())
8
+
9
+ def MusicLi(t,hk=''): return Li(A(DivFullySpaced(t,P(hk,cls=TextPresets.muted_sm))))
10
+
11
+ music_items = [("About Music", "" ),
12
+ ("Preferences", "⌘" ),
13
+ ("Hide Music" , "⌘H" ),
14
+ ("Hide Others", "⇧⌘H"),
15
+ ("Quit Music" , "⌘Q" )]
16
+
17
+ file_dd_items = [("New", ""),
18
+ ("Open Stream URL", "⌘U"),
19
+ ("Close Window", "⌘W"),
20
+ ("Library", ""),
21
+ ("Import", "⌘O"),
22
+ ("Burn Playlist to Disc", ""),
23
+ ("Show in Finder", "⇧⌘R"),
24
+ ("Convert", ""),
25
+ ("Page Setup", "Print")]
26
+
27
+ edit_actions = [("Undo", "⌘Z"),
28
+ ("Redo", "⇧⌘Z"),
29
+ ("Cut", "⌘X"),
30
+ ("Copy", "⌘C"),
31
+ ("Paste", "⌘V"),
32
+ ("Select All", "⌘A"),
33
+ ("Deselect All", "⇧⌘A")]
34
+
35
+ view_dd_data = ["Show Playing Next", "Show Lyrics", "Show Status Bar", "Hide Sidebar", "Enter Full Screen"]
36
+
37
+
38
+ music_headers = NavBar(
39
+ Button("Music", cls=ButtonT.ghost+TextT.gray),DropDownNavContainer(Li(A("Music"),NavContainer(map(lambda x: MusicLi(*x), music_items)))),
40
+ Button("File", cls=ButtonT.ghost+TextT.gray), DropDownNavContainer(Li(A("File"), NavContainer(map(lambda x: MusicLi(*x), file_dd_items)))),
41
+ Button("Edit", cls=ButtonT.ghost+TextT.gray), DropDownNavContainer(Li(A("Edit")),NavContainer(
42
+ *map(lambda x: MusicLi(*x), edit_actions),
43
+ Li(A(DivFullySpaced("Smart Dictation",UkIcon("mic")))),
44
+ Li(A(DivFullySpaced("Emojis & Symbols",UkIcon("globe")))))),
45
+ Button("View", cls=ButtonT.ghost+TextT.gray),DropDownNavContainer(Li(A("View"),NavContainer(map(lambda x: MusicLi(x), view_dd_data)))),
46
+ brand=DivLAligned(H2("Purrify"))
47
+ )
48
+
49
+
50
+
51
+
52
+ # music_headers = NavBarContainer(
53
+ # NavBarLSide(
54
+ # NavBarNav(
55
+ # Li(A("Music"),NavBarNavContainer(map(lambda x: MusicLi(*x), music_items))),
56
+ # Li(A("File"), NavBarNavContainer(map(lambda x: MusicLi(*x), file_dd_items))),
57
+ # Li(A("Edit")),
58
+ # NavBarNavContainer(
59
+ # *map(lambda x: MusicLi(*x), edit_actions),
60
+ # Li(A(DivFullySpaced("Smart Dictation",UkIcon("mic")))),
61
+ # Li(A(DivFullySpaced("Emojis & Symbols",UkIcon("globe"))))),
62
+ # Li(A("View"),
63
+ # NavBarNavContainer(map(lambda x: MusicLi(x), view_dd_data))),
64
+ # Li(A("Account"),
65
+ # NavBarNavContainer(
66
+ # NavHeaderLi("Switch Account"),
67
+ # *map(MusicLi, ("Andy", "Benoit", "Luis", "Manage Family", "Add Account")))))))
68
+
69
+
70
+ def Album(title,artist):
71
+ img_url = 'https://ucarecdn.com/e5607eaf-2b2a-43b9-ada9-330824b6afd7/music1.webp'
72
+ return Div(
73
+ Div(cls="overflow-hidden rounded-md")(Img(cls="transition-transform duration-200 hover:scale-105", src=img_url)),
74
+ Div(cls='space-y-1')(Strong(title),P(artist,cls=TextT.muted)))
75
+
76
+ listen_now_albums = (("Roar", "Catty Perry"), ("Feline on a Prayer", "Cat Jovi"),("Fur Elise", "Ludwig van Beethovpurr"),("Purrple Rain", "Prince's Cat"))
77
+
78
+ made_for_you_albums = [("Like a Feline", "Catdonna"),
79
+ ("Livin' La Vida Purrda", "Ricky Catin"),
80
+ ("Meow Meow Rocket", "Elton Cat"),
81
+ ("Rolling in the Purr", "Catdelle"),
82
+ ("Purrs of Silence", "Cat Garfunkel"),
83
+ ("Meow Me Maybe", "Carly Rae Purrsen"),]
84
+
85
+ music_content = (Div(H3("Listen Now"), cls="mt-6 space-y-1"),
86
+ Subtitle("Top picks for you. Updated daily."),
87
+ DividerLine(),
88
+ Grid(*[Album(t,a) for t,a in listen_now_albums], cls='gap-8'),
89
+ Div(H3("Made for You"), cls="mt-6 space-y-1"),
90
+ Subtitle("Your personal playlists. Updated daily."),
91
+ DividerLine(),
92
+ Grid(*[Album(t,a) for t,a in made_for_you_albums], cols_xl=6))
93
+
94
+ tabs = TabContainer(
95
+ Li(A('Music', href='#'), cls='uk-active'),
96
+ Li(A('Podcasts', href='#')),
97
+ Li(A('Live', cls='opacity-50'), cls='uk-disabled'),
98
+ uk_switcher='connect: #component-nav; animation: uk-animation-fade',
99
+ alt=True)
100
+
101
+ def podcast_tab():
102
+ return Div(
103
+ Div(cls='space-y-3 mt-6')(
104
+ H3("New Episodes"),
105
+ Subtitle("Your favorite podcasts. Updated daily.")),
106
+ Div(cls="uk-placeholder flex h-[450px] items-center justify-center rounded-md mt-4",uk_placeholder=True)(
107
+ DivVStacked(cls="space-y-6")(
108
+ UkIcon("microphone", 3),
109
+ H4("No episodes added"),
110
+ Subtitle("You have not added any podcasts. Add one below."),
111
+ Button("Add Podcast", cls=ButtonT.primary))))
112
+
113
+ discoved_data = [("play-circle","Listen Now"), ("binoculars", "Browse"), ("rss","Radio")]
114
+ library_data = [("play-circle", "Playlists"), ("music", "Songs"), ("user", "Made for You"), ("users", "Artists"), ("bookmark", "Albums")]
115
+ playlists_data = [("library","Recently Added"), ("library","Recently Played")]
116
+
117
+ def MusicSidebarLi(icon, text): return Li(A(DivLAligned(UkIcon(icon), P(text))))
118
+ sidebar = NavContainer(
119
+ NavHeaderLi(H3("Discover")), *[MusicSidebarLi(*o) for o in discoved_data],
120
+ NavHeaderLi(H3("Library")), *[MusicSidebarLi(*o) for o in library_data],
121
+ NavHeaderLi(H3("Playlists")),*[MusicSidebarLi(*o) for o in playlists_data],
122
+ cls=(NavT.primary,'space-y-3','pl-8'))
123
+
124
+ @rt
125
+ def index():
126
+ return Title("Music Example"),Container(music_headers, DividerSplit(),
127
+ Grid(sidebar,
128
+ Div(cls="col-span-4 border-l border-border")(
129
+ Div(cls="px-8 py-6")(
130
+ DivFullySpaced(
131
+ Div(cls="max-w-80")(tabs),
132
+ Button(cls=ButtonT.primary)(DivLAligned(UkIcon('circle-plus')),Div("Add music"))),
133
+ Ul(id="component-nav", cls="uk-switcher")(
134
+ Li(*music_content),
135
+ Li(podcast_tab())))),
136
+ cols_sm=1, cols_md=1, cols_lg=5, cols_xl=5))
137
+
138
+ serve()
MonsterUI/docs/examples/playground.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FrankenUI Playground Example built with MonsterUI (original design by ShadCN)"""
2
+
3
+ from fasthtml.common import *
4
+ from monsterui.all import *
5
+ from fasthtml.svg import *
6
+
7
+ app, rt = fast_app(hdrs=Theme.blue.headers())
8
+
9
+ preset_options = ["Grammatical Standard English", "Summarize for a 2nd grader",
10
+ "Text to command","Q&A","English to other languages","Parse unstructured data",
11
+ "Classification","Natural language to Python","Explain code","Chat","More examples"]
12
+
13
+ def playground_navbar():
14
+ save_modal = Modal(
15
+ ModalTitle("Save preset"),
16
+ P("This will save the current playground state as a preset which you can access later or share with others.",cls=("mt-1.5", TextPresets.muted_sm)),
17
+ LabelInput("Name", id="name"),
18
+ LabelInput("Description", id="description"),
19
+ ModalCloseButton("Save", cls=ButtonT.primary),
20
+ id="save")
21
+
22
+ share_dd = Div(cls="space-y-6 p-4")(
23
+ H3("Share preset"),
24
+ P("Anyone who has this link and an OpenAI account will be able to view this.", cls=TextPresets.muted_sm),
25
+ Div(Input(value="https://platform.openai.com/playground/p/7bbKYQvsVkNmVb8NGcdUOLae?model=text-davinci-003", readonly=True),
26
+ Button(UkIcon('copy'), cls=(ButtonT.primary, "uk-drop-close",'mt-4'))))
27
+
28
+ rnav = (
29
+ Select(*Options(*preset_options), name='preset', optgroup_label="Examples",
30
+ placeholder='Load a preset', searchable=True, cls='h-9 w-[200px] lg:w-[300px]'),
31
+ Button("Save", cls=ButtonT.secondary, data_uk_toggle="#save"),save_modal,
32
+ Button("View Code", cls=ButtonT.secondary),
33
+ Button("Share", cls=ButtonT.secondary),DropDownNavContainer(share_dd),
34
+ Button(UkIcon(icon="ellipsis"), cls=ButtonT.secondary),
35
+ DropDownNavContainer(
36
+ Li(A("Content filter preferences")),
37
+ NavDividerLi(),
38
+ Li(A("Delete preset", cls="text-destructive")),
39
+ uk_dropdown="mode: click"))
40
+
41
+ return NavBar(*rnav, brand=H4('Playground'))
42
+
43
+ rsidebar = NavContainer(
44
+ Select(
45
+ Optgroup(map(Option,("text-davinci-003", "text-curie-001", "text-babbage-001", "text-ada-001")),label='GPT-3'),
46
+ Optgroup(map(Option,("code-davinci-002", "code-cushman-001")),label='Codex'),
47
+ label="Model",
48
+ searchable=True),
49
+ LabelRange(label='Temperature', value='12'),
50
+ LabelRange(label='Maximum Length', value='80'),
51
+ LabelRange(label='Top P', value='40'),
52
+ cls='space-y-6 mt-8')
53
+
54
+ @rt
55
+ def index():
56
+ navbar = playground_navbar()
57
+ main_content = Div(
58
+ Div(cls="flex-1")(
59
+ Textarea(cls="uk-textarea h-full p-4", placeholder="Write a tagline for an ice cream shop")),
60
+ cls="flex h-[700px] p-8 w-4/5")
61
+
62
+ bottom_buttons = Div(
63
+ Button("Submit", cls=ButtonT.primary),
64
+ Button(UkIcon(icon="history"), cls=ButtonT.secondary),
65
+ cls="flex gap-x-2")
66
+
67
+ return Title("Playground Example"),Div(navbar, Div(cls="flex w-full")(main_content, rsidebar), bottom_buttons)
68
+
69
+ serve()
MonsterUI/docs/examples/scrollspy.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "MonsterUI Scrollspy Example application"
2
+
3
+ from fasthtml.common import *
4
+ from monsterui.all import *
5
+ import random
6
+
7
+ # Using the "slate" theme with Highlight.js enabled
8
+ hdrs = Theme.slate.headers(highlightjs=True)
9
+ app, rt = fast_app(hdrs=hdrs)
10
+
11
+ ################################
12
+ ### Example Data and Content ###
13
+ ################################
14
+ products = [
15
+ {"name": "Laptop", "price": "$999"},
16
+ {"name": "Smartphone", "price": "$599"}
17
+ ]
18
+
19
+ code_example = """
20
+ # Python Code Example
21
+ def greet(name):
22
+ return f"Hello, {name}!"
23
+
24
+ print(greet("World"))
25
+ """
26
+ testimonials = [
27
+ {"name": "Alice", "feedback": "Great products and excellent customer service!"},
28
+ {"name": "Bob", "feedback": "Fast shipping and amazing quality!"},
29
+ {"name": "Charlie", "feedback": "Amazing experience! Will definitely buy again."},
30
+ {"name": "Diana", "feedback": "Affordable prices and great variety!"},
31
+ {"name": "Edward", "feedback": "Customer support was very helpful."},
32
+ {"name": "Fiona", "feedback": "Loved the design and quality!"}
33
+ ]
34
+
35
+ # Team members
36
+ team = [
37
+ {"name": "Isaac Flath", "role": "CEO"},
38
+ {"name": "Benjamin Clavié", "role": "AI Researcher"},
39
+ {"name": "Alexis Gallagher", "role": "ML Engineer"},
40
+ {"name": "Hamel Husain", "role": "Data Scientist"},
41
+ {"name": "Austin Huang", "role": "Software Engineer"},
42
+ {"name": "Benjamin Warner", "role": "Product Manager"},
43
+ {"name": "Jonathan Whitaker", "role": "UX Designer"},
44
+ {"name": "Kerem Turgutlu", "role": "DevOps Engineer"},
45
+ {"name": "Curtis Allan", "role": "DevOps Engineer"},
46
+ {"name": "Audrey Roy Greenfeld", "role": "Security Analyst"},
47
+ {"name": "Nathan Cooper", "role": "Full Stack Developer"},
48
+ {"name": "Jeremy Howard", "role": "CTO"},
49
+ {"name": "Wayde Gilliam", "role": "Cloud Architect"},
50
+ {"name": "Daniel Roy Greenfeld", "role": "Blockchain Expert"},
51
+ {"name": "Tommy Collins", "role": "AI Ethics Researcher"}
52
+ ]
53
+
54
+
55
+ def ProductCard(p,img_id=1):
56
+ return Card(
57
+ PicSumImg(w=500, height=100, id=img_id),
58
+ DivFullySpaced(H4(p["name"]), P(Strong(p["price"], cls=TextT.sm))),
59
+ Button("Details", cls=(ButtonT.primary, "w-full")))
60
+
61
+ def TestimonialCard(t,img_id=1):
62
+ return Card(
63
+ DivLAligned(PicSumImg(w=50, h=50, cls='rounded-full', id=img_id), H4(t["name"])),
64
+ P(Q((t["feedback"]))))
65
+
66
+
67
+ def TeamCard(m,img_id=1):
68
+ return Card(
69
+ DivLAligned(
70
+ PicSumImg(w=50, h=50, cls='rounded-full', id=img_id),
71
+ Div(H4(m["name"]), P(m["role"]))),
72
+ DivRAligned(
73
+ UkIcon('twitter', cls='w-5 h-5'),
74
+ UkIcon('linkedin', cls='w-5 h-5'),
75
+ UkIcon('github', cls='w-5 h-5'),
76
+ cls=TextT.gray+'space-x-2'
77
+ ),
78
+ cls='p-3')
79
+
80
+ ################################
81
+ ### Navigation and Scrollspy ###
82
+ ################################
83
+
84
+ scrollspy_links = (
85
+ A("Welcome", href="#welcome-section"),
86
+ A("Products", href="#products-section"),
87
+ A("Testimonials", href="#testimonials-section"),
88
+ A("Team", href="#team-section"),
89
+ A("Code Example", href="#code-section"))
90
+ @rt
91
+ def index():
92
+ def _Section(*c, **kwargs): return Section(*c, cls='space-y-3 my-48',**kwargs)
93
+ return Container(
94
+ NavBar(
95
+ *scrollspy_links,
96
+ brand=DivLAligned(H3("Scrollspy Demo!"),UkIcon('rocket',height=30,width=30)),
97
+ sticky=True, uk_scrollspy_nav=True,
98
+ scrollspy_cls=ScrollspyT.bold),
99
+ NavContainer(
100
+ *map(Li, scrollspy_links),
101
+ uk_scrollspy_nav=True,
102
+ sticky=True,
103
+ cls=(NavT.primary,'pt-20 px-5 pr-10')),
104
+ Container(
105
+ # Notice the ID of each section corresponds to the `scrollspy_links` dictionary
106
+ # So in scollspy `NavContainer` the `href` of each `Li` is the ID of the section
107
+ DivCentered(
108
+ H1("Welcome to the Store!"),
109
+ Subtitle("Explore our products and enjoy dynamic code examples."),
110
+ id="welcome-section"),
111
+ _Section(H2("Products"),
112
+ Grid(*[ProductCard(p,img_id=i) for i,p in enumerate(products)], cols_lg=2),
113
+ id="products-section"),
114
+ _Section(H2("Testimonials"),
115
+ Slider(*[TestimonialCard(t,img_id=i) for i,t in enumerate(testimonials)]),
116
+ id="testimonials-section"),
117
+ _Section(H2("Our Team"),
118
+ Grid(*[TeamCard(m,img_id=i) for i,m in enumerate(team)], cols_lg=2, cols_max=3),
119
+ id="team-section"),
120
+ _Section(H2("Code Example"),
121
+ CodeBlock(code_example, lang="python"),
122
+ id="code-section")),
123
+ cls=(ContainerT.xl,'uk-container-expand'))
124
+
125
+ serve()
MonsterUI/docs/examples/tasks.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FrankenUI Tasks Example built with MonsterUI (original design by ShadCN)"""
2
+
3
+ from fasthtml.common import *
4
+ from monsterui.all import *
5
+ from fasthtml.svg import *
6
+ import json
7
+
8
+ app, rt = fast_app(hdrs=Theme.blue.headers())
9
+
10
+ def LAlignedCheckTxt(txt): return DivLAligned(UkIcon(icon='check'), P(txt, cls=TextPresets.muted_sm))
11
+
12
+ with open('data_/status_list.json', 'r') as f: data = json.load(f)
13
+ with open('data_/statuses.json', 'r') as f: statuses = json.load(f)
14
+
15
+ def _create_tbl_data(d):
16
+ return {'Done': d['selected'], 'Task': d['id'], 'Title': d['title'],
17
+ 'Status' : d['status'], 'Priority': d['priority'] }
18
+
19
+ data = [_create_tbl_data(d) for d in data]
20
+ page_size = 15
21
+ current_page = 0
22
+ paginated_data = data[current_page*page_size:(current_page+1)*page_size]
23
+
24
+ priority_dd = [{'priority': "low", 'count': 36 }, {'priority': "medium", 'count': 33 }, {'priority': "high", 'count': 31 }]
25
+
26
+ status_dd = [{'status': "backlog", 'count': 21 },{'status': "todo", 'count': 21 },{'status': "progress", 'count': 20 },{'status': "done",'count': 19 },{'status': "cancelled", 'count': 19 }]
27
+
28
+ def create_hotkey_li(hotkey): return NavCloseLi(A(DivFullySpaced(hotkey[0], Span(hotkey[1], cls=TextPresets.muted_sm))))
29
+
30
+ hotkeys_a = (('Profile','⇧⌘P'),('Billing','⌘B'),('Settings','⌘S'),('New Team',''))
31
+ hotkeys_b = (('Logout',''), )
32
+
33
+ avatar_opts = DropDownNavContainer(
34
+ NavHeaderLi(P('sveltecult'),NavSubtitle('[email protected]')),
35
+ NavDividerLi(),
36
+ *map(create_hotkey_li, hotkeys_a),
37
+ NavDividerLi(),
38
+ *map(create_hotkey_li, hotkeys_b),)
39
+
40
+ def CreateTaskModal():
41
+ return Modal(
42
+ Div(cls='p-6')(
43
+ ModalTitle('Create Task'),
44
+ P('Fill out the information below to create a new task', cls=TextPresets.muted_sm),
45
+ Br(),
46
+ Form(cls='space-y-6')(
47
+ Grid(Div(Select(*map(Option,('Documentation', 'Bug', 'Feature')), label='Task Type', id='task_type')),
48
+ Div(Select(*map(Option,('In Progress', 'Backlog', 'Todo', 'Cancelled', 'Done')), label='Status', id='task_status')),
49
+ Div(Select(*map(Option, ('Low', 'Medium', 'High')), label='Priority', id='task_priority'))),
50
+ TextArea(label='Title', placeholder='Please describe the task that needs to be completed'),
51
+ DivRAligned(
52
+ ModalCloseButton('Cancel', cls=ButtonT.ghost),
53
+ ModalCloseButton('Submit', cls=ButtonT.primary),
54
+ cls='space-x-5'))),
55
+ id='TaskForm')
56
+
57
+ page_heading = DivFullySpaced(cls='space-y-2')(
58
+ Div(cls='space-y-2')(
59
+ H2('Welcome back!'),P("Here's a list of your tasks for this month!", cls=TextPresets.muted_sm)),
60
+ Div(DiceBearAvatar("sveltcult",8,8),avatar_opts))
61
+
62
+ table_controls =(Input(cls='w-[250px]',placeholder='Filter task'),
63
+ Button("Status"),
64
+ DropDownNavContainer(map(NavCloseLi,[A(DivFullySpaced(P(a['status']), P(a['count'])),cls='capitalize') for a in status_dd])),
65
+ Button("Priority"),
66
+ DropDownNavContainer(map(NavCloseLi,[A(DivFullySpaced(LAlignedCheckTxt(a['priority']), a['count']),cls='capitalize') for a in priority_dd])),
67
+ Button("View"),
68
+ DropDownNavContainer(map(NavCloseLi,[A(LAlignedCheckTxt(o)) for o in ['Title','Status','Priority']])),
69
+ Button('Create Task',cls=(ButtonT.primary, TextPresets.bold_sm), data_uk_toggle="target: #TaskForm"))
70
+
71
+ def task_dropdown():
72
+ return Div(Button(UkIcon('ellipsis')),
73
+ DropDownNavContainer(
74
+ map(NavCloseLi,[
75
+ *map(A,('Edit', 'Make a copy', 'Favorite')),
76
+ A(DivFullySpaced(*[P(o, cls=TextPresets.muted_sm) for o in ('Delete', '⌘⌫')]))])))
77
+ def header_render(col):
78
+ match col:
79
+ case "Done": return Th(CheckboxX(), shrink=True)
80
+ case 'Actions': return Th("", shrink=True)
81
+ case _: return Th(col, expand=True)
82
+
83
+ def cell_render(col, val):
84
+ def _Td(*args,cls='', **kwargs): return Td(*args, cls=f'p-2 {cls}',**kwargs)
85
+ match col:
86
+ case "Done": return _Td(shrink=True)(CheckboxX(selected=val))
87
+ case "Task": return _Td(val, cls='uk-visible@s') # Hide on small screens
88
+ case "Title": return _Td(val, cls='font-medium', expand=True)
89
+ case "Status" | "Priority": return _Td(cls='uk-visible@m uk-text-nowrap capitalize')(Span(val))
90
+ case "Actions": return _Td(task_dropdown(), shrink=True)
91
+ case _: raise ValueError(f"Unknown column: {col}")
92
+
93
+ task_columns = ["Done", 'Task', 'Title', 'Status', 'Priority', 'Actions']
94
+
95
+ tasks_table = Div(cls='mt-4')(
96
+ TableFromDicts(
97
+ header_data=task_columns,
98
+ body_data=paginated_data,
99
+ body_cell_render=cell_render,
100
+ header_cell_render=header_render,
101
+ sortable=True,
102
+ cls=(TableT.responsive, TableT.sm, TableT.divider)))
103
+
104
+
105
+ def footer():
106
+ total_pages = (len(data) + page_size - 1) // page_size
107
+ return DivFullySpaced(
108
+ Div('1 of 100 row(s) selected.', cls=TextPresets.muted_sm),
109
+ DivLAligned(
110
+ DivCentered(f'Page {current_page + 1} of {total_pages}', cls=TextT.sm),
111
+ DivLAligned(*[UkIconLink(icon=i, button=True) for i in ('chevrons-left', 'chevron-left', 'chevron-right', 'chevrons-right')])))
112
+
113
+ tasks_ui = Div(DivFullySpaced(DivLAligned(table_controls), cls='mt-8'), tasks_table, footer())
114
+
115
+ @rt
116
+ def index(): return Container(page_heading, tasks_ui, CreateTaskModal())
117
+
118
+ serve()
MonsterUI/docs/examples/ticket.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """MonsterUI Help Desk Example - Professional Dashboard with DaisyUI components"""
2
+ from fasthtml.common import *
3
+ from monsterui.all import *
4
+ from datetime import datetime
5
+
6
+ app, rt = fast_app(hdrs=Theme.blue.headers(daisy=True))
7
+
8
+ def TicketSteps(step):
9
+ return Steps(
10
+ LiStep("Submitted", data_content="📝",
11
+ cls=StepT.success if step > 0 else StepT.primary if step == 0 else StepT.neutral),
12
+ LiStep("In Review", data_content="🔎",
13
+ cls=StepT.success if step > 1 else StepT.primary if step == 1 else StepT.neutral),
14
+ LiStep("Processing", data_content="⚙️",
15
+ cls=StepT.success if step > 2 else StepT.primary if step == 2 else StepT.neutral),
16
+ LiStep("Resolved", data_content="✅",
17
+ cls=StepT.success if step > 3 else StepT.primary if step == 3 else StepT.neutral),
18
+ cls="w-full")
19
+
20
+ def StatusBadge(status):
21
+ styles = {'high': AlertT.error, 'medium': AlertT.warning,'low': AlertT.info}
22
+ alert_type = styles.get(status, AlertT.info)
23
+ return Alert(f"{status.title()} Priority", cls=(alert_type,"w-32 shadow-sm"))
24
+
25
+ def TicketCard(id, title, description, status, step, department):
26
+ return Card(
27
+ CardHeader(
28
+ DivFullySpaced(
29
+ Div(H3(f"#{id}", cls=TextT.muted),
30
+ H4(title),
31
+ cls='space-y-2'),
32
+ StatusBadge(status))),
33
+ CardBody(
34
+ P(description, cls=(TextT.muted, "mb-6")),
35
+ DividerSplit(cls="my-6"),
36
+ TicketSteps(step),
37
+ DividerSplit(cls="my-6"),
38
+ DivFullySpaced(
39
+ Div(Strong("Department"),
40
+ P(department),
41
+ cls=('space-y-3', TextPresets.muted_sm)),
42
+ Div(Strong("Last Updated"),
43
+ P(Time(datetime.now().strftime('%b %d, %H:%M'))),
44
+ cls=('space-y-3', TextPresets.muted_sm)),
45
+ Button("View Details", cls=ButtonT.primary),
46
+ cls='mt-6')),
47
+ cls=CardT.hover)
48
+
49
+ def NewTicketModal():
50
+ return Modal(
51
+ ModalHeader(H3("Create New Support Ticket")),
52
+ ModalBody(
53
+ Alert(
54
+ DivLAligned(UkIcon("info"), Span("Please provide as much detail as possible to help us assist you quickly.")),
55
+ cls=(AlertT.info,"mb-4")),
56
+ Form(
57
+ Grid(LabelInput("Title", id="title", placeholder="Brief description of your issue"),
58
+ LabelSelect(Options("IT Support", "HR", "Facilities", "Finance"), label="Department", id="department")),
59
+ LabelSelect(Options("Low", "Medium", "High"), label="Priority Level", id="priority"),
60
+ LabelTextArea("Description", id="description", placeholder="Please provide detailed information about your issue"),
61
+ DivRAligned(
62
+ Button("Cancel", cls=ButtonT.ghost, data_uk_toggle="target: #new-ticket"),
63
+ Button(Loading(cls=LoadingT.spinner), "Submit Ticket", cls=ButtonT.primary, data_uk_toggle="target: #success-toast; target: #new-ticket")),
64
+ cls='space-y-8')),
65
+ id="new-ticket")
66
+
67
+ @rt
68
+ def index():
69
+ tickets = [
70
+ {'id': "TK-1001", 'title': "Cloud Storage Access Error",
71
+ 'description': "Unable to access cloud storage with persistent authorization errors. Multiple users affected across marketing department.",
72
+ 'status': 'high', 'step': 2, 'department': 'IT Support'},
73
+ {'id': "TK-1002", 'title': "Email Integration Issue",
74
+ 'description': "Exchange server not syncing with mobile devices. Affecting external client communications.",
75
+ 'status': 'medium', 'step': 1, 'department': 'IT Support'},
76
+ {'id': "TK-1003", 'title': "Office Equipment Setup",
77
+ 'description': "New department printer needs configuration and network integration. Required for upcoming client presentation.",
78
+ 'status': 'low', 'step': 0, 'department': 'Facilities'}
79
+ ]
80
+
81
+ return Title("Help Desk Dashboard"), Container(
82
+ Section(
83
+ DivFullySpaced(
84
+ H2("Active Tickets"),
85
+ Button(UkIcon("plus-circle", cls="mr-2"), "New Ticket", cls=ButtonT.primary, data_uk_toggle="target: #new-ticket"),
86
+ cls='mb-8'),
87
+ Grid(*[TicketCard(**ticket) for ticket in tickets], cols=1),
88
+ cls="my-6"),
89
+ NewTicketModal(),
90
+ Toast(DivLAligned(UkIcon('check-circle', cls='mr-2'), "Ticket submitted successfully! Our team will review it shortly."), id="success-toast", alert_cls=AlertT.success, cls=(ToastHT.end, ToastVT.bottom)),
91
+ Loading(htmx_indicator=True, type=LoadingT.dots, cls="fixed top-0 right-0 m-4"),
92
+ cls="mx-auto max-w-7xl"
93
+ )
94
+
95
+ serve()
MonsterUI/docs/favicon.ico ADDED

Git LFS Details

  • SHA256: f07da47ab7b8723e505f2f614213ca0202ee44c5368a62fc563bb3c4eedaa76e
  • Pointer size: 131 Bytes
  • Size of remote file: 270 kB
MonsterUI/docs/getting_started/GettingStarted.md ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MonsterUI
2
+
3
+ MonsterUI is a UI framework for FastHTML for building beautiful web interfaces with minimal code. It combines the simplicity of Python with the power of Tailwind. Perfect for data scientists, ML engineers, and developers who want to quickly turn their Python code into polished web apps without the complexity of traditional UI frameworks. Follows semantic HTML patterns when possible.
4
+
5
+ MonsterUI adds the following Tailwind-based libraries [Franken UI](https://franken-ui.dev/) and [DaisyUI](https://daisyui.com/) to FastHTML, as well as Python's [Mistletoe](https://github.com/miyuchina/mistletoe) for Markdown, [HighlightJS](https://highlightjs.org/) for code highlighting, and [Katex](https://katex.org/) for latex support.
6
+
7
+ # Getting Started
8
+
9
+ ## Installation
10
+
11
+ To install this library, uses
12
+
13
+ `pip install MonsterUI`
14
+
15
+ ## Getting Started
16
+
17
+ ### TLDR
18
+
19
+ Run `python file.py` on this to start:
20
+
21
+ ``` python
22
+ from fasthtml.common import *
23
+ from monsterui.all import *
24
+
25
+ # Choose a theme color (blue, green, red, etc)
26
+ hdrs = Theme.blue.headers()
27
+
28
+ # Create your app with the theme
29
+ app, rt = fast_app(hdrs=hdrs)
30
+
31
+ @rt
32
+ def index():
33
+ socials = (('github','https://github.com/AnswerDotAI/MonsterUI'),
34
+ ('twitter','https://twitter.com/isaac_flath/'),
35
+ ('linkedin','https://www.linkedin.com/in/isaacflath/'))
36
+ return Titled("Your First App",
37
+ Card(
38
+ H1("Welcome!"),
39
+ P("Your first MonsterUI app", cls=TextPresets.muted_sm),
40
+ P("I'm excited to see what you build with MonsterUI!"),
41
+ footer=DivLAligned(*[UkIconLink(icon,href=url) for icon,url in socials])))
42
+
43
+ serve()
44
+ ```
45
+
46
+ ## LLM context files
47
+
48
+ Using LLMs for development is a best practice way to get started and
49
+ explore. While LLMs cannot code for you, they can be helpful assistants.
50
+ You must check, refactor, test, and vet any code any LLM generates for
51
+ you - but they are helpful productivity tools. Take a look inside the
52
+ `llms.txt` file to see links to particularly useful context files!
53
+
54
+ - [llms.txt](https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/llms.txt): Links to what is included
55
+ - [llms-ctx.txt](https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/llms-ctx.txt): MonsterUI Documentation Pages
56
+ - [API list](https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/apilist.txt): API list for MonsterUI (included in llms-ctx.txt)
57
+ - [llms-ctx-full.txt](https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/llms-ctx-full.txt): Full context that includes all api reference pages as markdown
58
+
59
+ In addition you can add `/md` (for markdown) to a url to get a markdown representation and `/rmd` for rendered markdown representation (nice for looking to see what would be put into context.
60
+
61
+ ### Step by Step
62
+
63
+ To get started, check out:
64
+
65
+ 1. Start by importing the modules as follows:
66
+
67
+ ``` python
68
+ from fasthtml.common import *
69
+ from monsterui.all import *
70
+ ```
71
+
72
+ 2. Instantiate the app with the MonsterUI headers
73
+
74
+ ``` python
75
+ app = FastHTML(hdrs=Theme.blue.headers())
76
+
77
+ # Alternatively, using the fast_app method
78
+ app, rt = fast_app(hdrs=Theme.slate.headers())
79
+ ```
80
+
81
+ > *The color option can be any of the theme options available out of the
82
+ > box*
83
+
84
+ > `katex` and `highlightjs` are not included by default. To include them set `katex=True` or `highlightjs=True` when calling `.headers`. (i.e. `Theme.slate.headers(katex=True)`)*
85
+
86
+ From here, you can explore the API Reference & examples to see how to
87
+ implement the components. You can also check out these demo videos to as
88
+ a quick start guide:
89
+
90
+ - MonsterUI [documentation page and Tutorial
91
+ app](https://monsterui.answer.ai/tutorial_app)
92
+ - Isaac & Hamel : [Building his website’s team
93
+ page](https://youtu.be/22Jn46-mmM0)
94
+ - Isaac & Audrey : [Building a blog](https://youtu.be/gVWAsywxLXE)
95
+ - Isaac : [Building a blog](https://youtu.be/22NJgfAqgko)
96
+
97
+ More resources and improvements to the documentation will be added here
98
+ soon!
MonsterUI/docs/getting_started/StylingRulesOfThumb.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fasthtml.common import *
2
+ from monsterui.all import *
3
+ from utils import create_flippable_card, fn2code_string
4
+
5
+ def prerequisites():
6
+ return Section(
7
+ H2("Prerequisites"),
8
+ P("""The MonsterUI library automatically handles a lot of styling for you, but it assumes you structure your page with HTML.
9
+ If you aren't familiar with the basics of HTML, check out the """,
10
+ A("W3 Schools HTML references", href="https://www.w3schools.com/html", cls=AT.muted),
11
+ " to learn more about the basics of HTML."),
12
+ cls='my-4 py-4'
13
+ )
14
+
15
+ def next_steps():
16
+ return Section(
17
+ H2("Next Steps"),
18
+ P("""Once you have a good grasp of HTML, you can reference the following resources to continue to expand your capabilities. Instead of trying to learn all of these, focus on the ones that are relevant to something specific you want to do."""),
19
+ List(map(Li, [
20
+ A("Improving Aesthetics with Spacing", href="https://frankenui.fasthtml.io/docs/getting_started/SpacingTutorial", cls=AT.muted),
21
+ A("Manipulating Page and Element Layout", href="https://frankenui.fasthtml.io/docs/getting_started/LayoutTutorial", cls=AT.muted),
22
+ A("FlexBox Froggy", href="https://flexboxfroggy.com/", cls=AT.muted),
23
+ A("Accessibility", href="https://frankenui.fasthtml.io/docs/getting_started/Accessibility", cls=AT.muted),
24
+ ]), cls=ListT.bullet),
25
+ cls='my-4 py-4'
26
+ )
27
+
28
+ def page():
29
+ return Article(
30
+ ArticleTitle("Styling Rules of Thumb"),
31
+ ArticleMeta("A guide to making a pretty good looking website in a hurry"),
32
+ prerequisites(),
33
+ next_steps(),
34
+ # button_section(),
35
+ # typography_section(),
36
+ )
37
+
38
+
39
+ def accessibility_section():
40
+ # TODO: Alt tags
41
+ # TODO: Aria labels
42
+ # TODO: High contrast
43
+ # TODO: Prefers reduced motion
44
+ pass
45
+
46
+ def further_reading():
47
+ # TODO: Tailwind CSS
48
+ # TODO: FlexBox Froggy
49
+ # TODO: Accessibility
50
+ pass
51
+
52
+ def button_section():
53
+ def _ex_buttons():
54
+ return Form(
55
+ Grid(LabelInput("Email"),
56
+ LabelInput("Name"),
57
+ cols=2),
58
+ Grid(Button("Submit Information", cls=ButtonT.primary),
59
+ Button("Delete Information", cls=ButtonT.destructive),
60
+ Button("Cancel"),
61
+ cols=3)
62
+ )
63
+
64
+ return Section(
65
+ H2("Pick button styles based on desired behavior"),
66
+ Blockquote("The aethetic of a button should match the desired behavior",cls='uk-blockquote mb-8'),
67
+ Strong("What to do:"),
68
+ List(
69
+ Li("Use ButtonT.primary for the most important actions (ie add to card, checkout, etc.)"),
70
+ Li("Use ButtonT.secondary for actions that are important but not the primary action (ie save, etc.)"),
71
+ Li("Use ButtonT.destructive for destructive actions"),
72
+ Li("Use default styling for UX actions (ie go cancel, close etc.)"),
73
+ cls=ListT.bullet
74
+ ),
75
+ create_flippable_card(*fn2code_string(_ex_buttons)),
76
+ cls='my-4 py-4'
77
+ )
78
+
79
+ def typography_section():
80
+ def _ex_typography():
81
+ return Div(cls='space-y-5')(
82
+ Div(cls='space-y-3')(
83
+ H1("The main heading"),
84
+ Blockquote("A section describing easy ways to make generally good looking text"),
85
+ ),
86
+ Div(cls='space-y-3')(
87
+ H2("My First Section"),
88
+ P("A short description of what's in this section", cls=TextPresets.muted_sm),
89
+ P("""Now I can write the main content of the page with a normal P tag.
90
+ We can use this for longer text like paragraphs.
91
+ It's ideal because this text is highly readable.
92
+ I can write longer sentences and paragraphs without is being really hard to read with highly styled text.
93
+ Often if you aren't careful with styling you can make the text hard to read, especially if you aren't thinking about light vs dark backgrounds.
94
+ """))
95
+ )
96
+
97
+
98
+ return Section(
99
+ H2("Use consistent typography"),
100
+ Blockquote("Consistency is key to a polished user experience",cls='uk-blockquote mb-8'),
101
+ Strong("What to do:"),
102
+ List(
103
+ Li("Use H1-4 for headings"),
104
+ Li("Use P with cls=TextPresets.muted_sm subheadings like "),
105
+ Li("Use P for most body text"),
106
+ cls=ListT.bullet),
107
+ create_flippable_card(*fn2code_string(_ex_typography)),
108
+ cls='my-4 py-4'
109
+ )
110
+
MonsterUI/docs/getting_started/app_product_gallery.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fasthtml.common import *
2
+ # MonsterUI shadows fasthtml components with the same name
3
+ from monsterui.all import *
4
+ # If you don't want shadowing behavior, you use import monsterui.core as ... style instead
5
+
6
+ # Get frankenui and tailwind headers via CDN using Theme.blue.headers()
7
+ hdrs = Theme.blue.headers()
8
+
9
+ # fast_app is shadowed by MonsterUI to make it default to no Pico, and add body classes
10
+ # needed for frankenui theme styling
11
+ app, rt = fast_app(hdrs=hdrs)
12
+
13
+ # Examples Product Data to render in the gallery and detail pages  
14
+ products = [
15
+ {"name": "Laptop", "price": "$999", "img": "https://picsum.photos/400/100?random=1"},
16
+ {"name": "Smartphone", "price": "$599", "img": "https://picsum.photos/400/100?random=2"},
17
+ {"name": "Headphones", "price": "$199", "img": "https://picsum.photos/400/100?random=3"},
18
+ {"name": "Smartwatch", "price": "$299", "img": "https://picsum.photos/400/100?random=4"},
19
+ {"name": "Tablet", "price": "$449", "img": "https://picsum.photos/400/100?random=5"},
20
+ {"name": "Camera", "price": "$799", "img": "https://picsum.photos/400/100?random=6"},]
21
+
22
+ def ProductCard(p):
23
+ # Card does lots of boilerplate classes so you can just pass in the content
24
+ return Card(
25
+ # width:100% makes the image take the full width so we are guarenteed that we won't
26
+ # have the image cut off or not large enough. Because all our images are a consistent
27
+ # size we do not need to worry about stretching or skewing the image, this is ideal.
28
+ # If you have images of different sizes, you will need to use object-fit:cover and/or
29
+ # height to either strech, shrink, or crop the image. It is much better to adjust your
30
+ # images to be a consistent size upfront so you don't have to handle edge cases of
31
+ # different images skeweing/stretching differently.
32
+ Img(src=p["img"], alt=p["name"], style="width:100%"),
33
+ # All components can take a cls argument to add additional styling - `mt-2` adds margin
34
+ # to the top (see spacing tutorial for details on spacing).
35
+ #
36
+ # Often adding space makes a site look more put together - usually the 2 - 5 range is a
37
+ # good choice
38
+ H4(p["name"], cls="mt-2"),
39
+ # There are helpful Enums, such as TextPresetsT, ButtonT, ContainerT, etc that allow for easy
40
+ # discoverability of class options.
41
+ # bold_sm is helpful for things that you want to look like regular text, but stand out
42
+ # visually for emphasis.
43
+ P(p["price"], cls=TextPresets.bold_sm),
44
+ # ButtonT.primary is useful for actions you really want the user to take (like adding
45
+ # something to the card) - these stand out visually. For dangerous actions (like
46
+ # deleting something) you generally would want to use ButtonT.destructive. For UX actions
47
+ # that aren't a goal of the page (like cancelling something that hasn't been submitted)
48
+ # you generally want the default styling.
49
+ Button("Click me!", cls=(ButtonT.primary, "mt-2"),
50
+ # HTMX can be used as normal on any component
51
+ hx_get=product_detail.to(product_name=p['name']),
52
+ hx_push_url='true',
53
+ hx_target='body'))
54
+
55
+ @rt
56
+ def index():
57
+ # Titled using a H1 title, sets the page title, and wraps contents in Main(Container(...)) using
58
+ # frankenui styles. Generally you will want to use Titled for all of your pages
59
+ return Titled("Example Store Front!",
60
+ Grid(*[ProductCard(p) for p in products], cols_lg=3))
61
+
62
+ example_product_description = """\n
63
+ This is a sample detailed description of the {product_name}. You can see when clicking on the card
64
+ from the gallery you can:
65
+
66
+ + Have a detailed description of the product on the page
67
+ + Have an order form to fill out and submit
68
+ + Anything else you want!
69
+ """
70
+
71
+ @rt
72
+ def product_detail(product_name:str):
73
+ return Titled("Product Detail",
74
+ # Grid lays out its children in a responsive grid
75
+ Grid(
76
+ Div(
77
+ H1(product_name),
78
+ # render_md is a helper that renders markdown into HTML using frankenui styles.
79
+ render_md(example_product_description.format(product_name=product_name))),
80
+ Div(
81
+ H3("Order Form"),
82
+ # Form automatically has a class of 'space-y-3' for a margin between each child.
83
+ Form(
84
+ # LabelInput is a convience wrapper for a label and input that links them.
85
+ LabelInput("Name", id='name'),
86
+ LabelInput("Email", id='email'),
87
+ LabelInput("Quantity", id='quantity'),
88
+ # ButtonT.primary because this is the primary action of the page!
89
+ Button("Submit", cls=ButtonT.primary))
90
+
91
+ ),
92
+ # Grid has defaults and args for cols at different breakpoints, but you can pass in
93
+ # your own to customize responsiveness.
94
+ cols_lg=2))
95
+
96
+ serve()
MonsterUI/docs/guides/Layout.ipynb ADDED
@@ -0,0 +1,591 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "09a2b6fa",
6
+ "metadata": {},
7
+ "source": [
8
+ "# MonterUI Page Layout Guide \n",
9
+ "\n",
10
+ "This guide will discuss 3 tools for laying out your app pages, Grid, Flexbox, and Columns. This page will discuss the strengths and when to use each individually, and then a section for how to combine them for more complex layouts at the end.\n",
11
+ "\n",
12
+ "> Note: This guide is designed to get you started building layouts quickly, not to teach you all the details needed to build every possible custom layout with pixel-perfect control. To get more detailed and lower-level control, explore the tailwind docs.\n",
13
+ "\n",
14
+ "\n",
15
+ "This guide is for creating flexible layouts you envision, but does not discuss responsiveness to make different layouts that are both mobile and desktop friendly. Stay tunes for a responsiveness guide that will help with that!"
16
+ ]
17
+ },
18
+ {
19
+ "cell_type": "markdown",
20
+ "id": "3bdf365b",
21
+ "metadata": {},
22
+ "source": [
23
+ "# Grid\n",
24
+ "\n",
25
+ "Grids are best for regular predictable layouts with lots of the same shape of things that may need to change a lot for different screen sizes. I think the best way to see what it can do is to see a bunch of examples, so here they are!"
26
+ ]
27
+ },
28
+ {
29
+ "cell_type": "markdown",
30
+ "id": "7d1bc6e0",
31
+ "metadata": {},
32
+ "source": [
33
+ "## Minimal Image Cards\n",
34
+ "\n",
35
+ "This is a minimal example of a grid that just shows image and text. This is the foundation for many more complex layouts so make sure to understand what's going on here first before moving on!\n",
36
+ "\n",
37
+ "A grid lays things out in a...grid. As you can see, we have evenly sized cards by default."
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": 1,
43
+ "id": "8b6ef3ea",
44
+ "metadata": {
45
+ "scrolled": true
46
+ },
47
+ "outputs": [],
48
+ "source": [
49
+ "def picsum_img(seed): return Img(src=f'https://picsum.photos/300/200?random={seed}')\n",
50
+ " \n",
51
+ "Grid(*[Card(picsum_img(i),P(f\"Image {i}\")) for i in range(6)])"
52
+ ]
53
+ },
54
+ {
55
+ "cell_type": "markdown",
56
+ "id": "c35376e2",
57
+ "metadata": {},
58
+ "source": [
59
+ "## Dashboard Example"
60
+ ]
61
+ },
62
+ {
63
+ "cell_type": "markdown",
64
+ "id": "a7c9149c",
65
+ "metadata": {},
66
+ "source": [
67
+ "However, they don't have to be evenly sized! By providing `row-span-{int}` and `col-span-{int}` we can control how many rows or columns specific grid elements take up. By doing this, we can create a grid that has lots of different shapes and types of elements.\n",
68
+ "\n",
69
+ "Let's look at a dashboard layout at an examples of this."
70
+ ]
71
+ },
72
+ {
73
+ "cell_type": "code",
74
+ "execution_count": 54,
75
+ "id": "5abd8bd1",
76
+ "metadata": {
77
+ "scrolled": false
78
+ },
79
+ "outputs": [
80
+ {
81
+ "data": {
82
+ "text/html": [
83
+ "<iframe src=\"http://localhost:8000/_WvNL2TY3R0K8wGkaRFZ6GQ\" style=\"width: 100%; height: auto; border: none;\" onload=\"{\n",
84
+ " let frame = this;\n",
85
+ " window.addEventListener('message', function(e) {\n",
86
+ " if (e.source !== frame.contentWindow) return; // Only proceed if the message is from this iframe\n",
87
+ " if (e.data.height) frame.style.height = (e.data.height+1) + 'px';\n",
88
+ " }, false);\n",
89
+ " }\" allow=\"accelerometer; autoplay; camera; clipboard-read; clipboard-write; display-capture; encrypted-media; fullscreen; gamepad; geolocation; gyroscope; hid; identity-credentials-get; idle-detection; magnetometer; microphone; midi; payment; picture-in-picture; publickey-credentials-get; screen-wake-lock; serial; usb; web-share; xr-spatial-tracking\"></iframe> "
90
+ ],
91
+ "text/plain": [
92
+ "<IPython.core.display.HTML object>"
93
+ ]
94
+ },
95
+ "execution_count": 54,
96
+ "metadata": {},
97
+ "output_type": "execute_result"
98
+ }
99
+ ],
100
+ "source": [
101
+ "def StatCard(title, value, color='primary'):\n",
102
+ " \"A card with a statistics. Since there is no row/col span class it will take up 1 slot\"\n",
103
+ " return Card(P(title, cls=TextPresets.muted_sm), H3(value, cls=f'text-{color}'),)\n",
104
+ "\n",
105
+ "stats = [StatCard(*data) for data in [\n",
106
+ " (\"Total Users\", \"1,234\", \"blue-600\"),\n",
107
+ " (\"Active Now\", \"342\", \"green-600\"),\n",
108
+ " (\"Revenue\", \"$45,678\", \"purple-600\"),\n",
109
+ " (\"Conversion\", \"2.4%\", \"amber-600\")]]\n",
110
+ "\n",
111
+ "def ChartCard(title): \n",
112
+ " \"A card for a chart. col-span-2 means it will take up 2 columns\"\n",
113
+ " return Div(cls=\"col-span-2\")( \n",
114
+ " Card(H3(title),Div(\"Chart Goes Here\", cls=\"h-64 uk-background-muted\")))\n",
115
+ "chart_cards = [ChartCard(title) for title in (\"Monthly Revenue\", \"User Growth\")]\n",
116
+ "\n",
117
+ "\n",
118
+ "sidebar = Form(\n",
119
+ " H3(\"SideBar\"),\n",
120
+ " LabelRange(\"Range For Filters\", min=0, max=100),\n",
121
+ " LabelInput(\"A search Bar\"),\n",
122
+ " LabelSelect(map(Option, [\"Product Line A\", \"Product Line B\", \"Product Line C\", \"Product Line D\"]),\n",
123
+ " label=\"Choose Product Line\"),\n",
124
+ " LabelCheckboxX(\"Include Inactive Users\"),\n",
125
+ " LabelCheckboxX(\"Include Users without order\"),\n",
126
+ " LabelCheckboxX(\"Include Users without email\"),\n",
127
+ " # This sidebar will take up 2 rows b/c of row-span-2\n",
128
+ " cls='row-span-2 space-y-5'\n",
129
+ ")\n",
130
+ "\n",
131
+ "Container(Grid(sidebar, *stats, *chart_cards, cols=5))"
132
+ ]
133
+ },
134
+ {
135
+ "cell_type": "markdown",
136
+ "id": "cc9bb132",
137
+ "metadata": {},
138
+ "source": [
139
+ "# Flexbox"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "markdown",
144
+ "id": "1dcb8075",
145
+ "metadata": {},
146
+ "source": [
147
+ "Using Grid for the overall layout, and flex for the individual elements is a powerful pattern. With `MonsterUI` you can do quite a bit without knowing anything about flexbox, which is what will be taught here. \n",
148
+ "\n",
149
+ "However, flexbox is well worth learning about it in more detail. You will run into situations where you need more flexbox knowledge than is covered here to build your vision. Thankfully you can get that knowledge by playing a [fantastic tutorial game called FlexBox Froggy](https://flexboxfroggy.com/)!"
150
+ ]
151
+ },
152
+ {
153
+ "cell_type": "markdown",
154
+ "id": "d10557e5",
155
+ "metadata": {},
156
+ "source": [
157
+ "## Forms\n",
158
+ "\n",
159
+ "Often you want to stack things horizontally. You can use the `DivHStacked` component to do this.\n",
160
+ "\n",
161
+ "`DivHStacked` is a helper function for flexbox and creates a div with these classes by default `cls=(FlexT.block, FlexT.row, FlexT.middle, 'space-x-4')`. "
162
+ ]
163
+ },
164
+ {
165
+ "cell_type": "code",
166
+ "execution_count": 71,
167
+ "id": "eaa39f3a",
168
+ "metadata": {},
169
+ "outputs": [
170
+ {
171
+ "data": {
172
+ "text/html": [
173
+ "<iframe src=\"http://localhost:8000/__LtKiA4BQ_mTEOe1cbj0tg\" style=\"width: 100%; height: auto; border: none;\" onload=\"{\n",
174
+ " let frame = this;\n",
175
+ " window.addEventListener('message', function(e) {\n",
176
+ " if (e.source !== frame.contentWindow) return; // Only proceed if the message is from this iframe\n",
177
+ " if (e.data.height) frame.style.height = (e.data.height+1) + 'px';\n",
178
+ " }, false);\n",
179
+ " }\" allow=\"accelerometer; autoplay; camera; clipboard-read; clipboard-write; display-capture; encrypted-media; fullscreen; gamepad; geolocation; gyroscope; hid; identity-credentials-get; idle-detection; magnetometer; microphone; midi; payment; picture-in-picture; publickey-credentials-get; screen-wake-lock; serial; usb; web-share; xr-spatial-tracking\"></iframe> "
180
+ ],
181
+ "text/plain": [
182
+ "<IPython.core.display.HTML object>"
183
+ ]
184
+ },
185
+ "execution_count": 71,
186
+ "metadata": {},
187
+ "output_type": "execute_result"
188
+ }
189
+ ],
190
+ "source": [
191
+ "def InputGroup(label, placeholder='', button_text='Submit', cls=''):\n",
192
+ " # Div H Stacked makes the label and input show up on the same row instead of putting the input on a newline\n",
193
+ " return DivHStacked(\n",
194
+ " FormLabel(label, cls='whitespace-nowrap'),\n",
195
+ " Input(placeholder=placeholder))\n",
196
+ "\n",
197
+ "Container(\n",
198
+ " H3(\"Form with Input Groups\"),\n",
199
+ " Form(cls='space-y-4')(\n",
200
+ " InputGroup(\"Search Users\", \"Enter username...\"),\n",
201
+ " InputGroup(\"Filter Tags\", \"Add tags...\", \"Add\"),\n",
202
+ " InputGroup(\"Email List\", \"Enter email...\", \"Subscribe\"),\n",
203
+ " Div(*( Button(UkIcon(icon, cls='mr-2'), text) for icon, text in [(\"rocket\", \"Submit\"), (\"circle-x\", \"Cancel\")]), cls='space-x-4')))"
204
+ ]
205
+ },
206
+ {
207
+ "cell_type": "markdown",
208
+ "id": "c4afd0d0",
209
+ "metadata": {},
210
+ "source": [
211
+ "## Avatar "
212
+ ]
213
+ },
214
+ {
215
+ "cell_type": "markdown",
216
+ "id": "9154ae8f",
217
+ "metadata": {},
218
+ "source": [
219
+ "You can use this same `DivHStacked` to align things like text next to images. And you can use `DivVStacked` to stack things vertically to create design structures you like. `DivVStacked` works by using `cls=(FlexT.block,FlexT.column,FlexT.middle)`"
220
+ ]
221
+ },
222
+ {
223
+ "cell_type": "code",
224
+ "execution_count": 170,
225
+ "id": "f782c6ca",
226
+ "metadata": {},
227
+ "outputs": [
228
+ {
229
+ "data": {
230
+ "text/markdown": [
231
+ "```html\n",
232
+ "<div class=\"uk-flex uk-flex-row uk-flex-middle space-x-4\">\n",
233
+ "<span class=\"relative flex h-20 w-20 shrink-0 overflow-hidden rounded-full bg-accent\"><img alt=\"Avatar\" loading=\"lazy\" src=\"https://api.dicebear.com/8.x/lorelei/svg?seed=user\" class=\"aspect-square h-20 w-20\"></span> <div class=\"uk-flex uk-flex-column uk-flex-middle \">\n",
234
+ " <p class=\"uk-text-large \">John Doe</p>\n",
235
+ " <p class=\"uk-text-muted \">[email protected]</p>\n",
236
+ " <p class=\"uk-text-muted \">+1-123-456-7890</p>\n",
237
+ " </div>\n",
238
+ "</div>\n",
239
+ "\n",
240
+ "```"
241
+ ],
242
+ "text/plain": [
243
+ "div((span((img((),{'alt': 'Avatar', 'loading': 'lazy', 'src': 'https://api.dicebear.com/8.x/lorelei/svg?seed=user', 'class': 'aspect-square h-20 w-20'}),),{'class': 'relative flex h-20 w-20 shrink-0 overflow-hidden rounded-full bg-accent'}), div((p(('John Doe',),{'class': 'uk-text-large '}), p(('[email protected]',),{'class': 'uk-text-muted '}), p(('+1-123-456-7890',),{'class': 'uk-text-muted '})),{'class': 'uk-flex uk-flex-column uk-flex-middle '})),{'class': 'uk-flex uk-flex-row uk-flex-middle space-x-4'})"
244
+ ]
245
+ },
246
+ "execution_count": 170,
247
+ "metadata": {},
248
+ "output_type": "execute_result"
249
+ }
250
+ ],
251
+ "source": [
252
+ "# DivHStacked makes the a single row so text is to on same line as avatar\n",
253
+ "DivHStacked(\n",
254
+ " DiceBearAvatar(\"user\"), \n",
255
+ " # DivVStacked stacks things vertically together and centers it with flex\n",
256
+ " DivVStacked(\n",
257
+ " P(\"John Doe\", cls=TextT.lg),\n",
258
+ " P(\"[email protected]\", cls=TextT.muted), \n",
259
+ " P(\"+1-123-456-7890\"), cls=TextT.muted))"
260
+ ]
261
+ },
262
+ {
263
+ "cell_type": "markdown",
264
+ "id": "6234fdf8",
265
+ "metadata": {},
266
+ "source": [
267
+ "## Pricing Card\n",
268
+ "\n",
269
+ "These can be combined with icons and other styling to create larger components like a pricing card."
270
+ ]
271
+ },
272
+ {
273
+ "cell_type": "code",
274
+ "execution_count": 165,
275
+ "id": "f1846dc1",
276
+ "metadata": {},
277
+ "outputs": [
278
+ {
279
+ "data": {
280
+ "text/markdown": [
281
+ "```html\n",
282
+ "<div class=\"uk-flex uk-flex-column uk-flex-middle space-y-4\">\n",
283
+ " <div class=\"uk-card \">\n",
284
+ " <div class=\"uk-card-body space-y-6\">\n",
285
+ " <div class=\"uk-flex uk-flex-column uk-flex-middle space-y-1\">\n",
286
+ " <h2 class=\"uk-h2 \">Pro Plan</h2>\n",
287
+ " <h3 class=\"uk-h3 text-primary\">$99</h3>\n",
288
+ " <p class=\"uk-text-muted \">per month</p>\n",
289
+ " </div>\n",
290
+ " <ul class=\"space-y-4\">\n",
291
+ " <div class=\"uk-flex uk-flex-row uk-flex-middle space-x-4\">\n",
292
+ "<uk-icon icon=\"check\" class=\"text-green-500 mr-2\"></uk-icon> <li>Unlimited users</li>\n",
293
+ " </div>\n",
294
+ " <div class=\"uk-flex uk-flex-row uk-flex-middle space-x-4\">\n",
295
+ "<uk-icon icon=\"check\" class=\"text-green-500 mr-2\"></uk-icon> <li>24/7 priority support</li>\n",
296
+ " </div>\n",
297
+ " <div class=\"uk-flex uk-flex-row uk-flex-middle space-x-4\">\n",
298
+ "<uk-icon icon=\"check\" class=\"text-green-500 mr-2\"></uk-icon> <li>Custom branding options</li>\n",
299
+ " </div>\n",
300
+ " <div class=\"uk-flex uk-flex-row uk-flex-middle space-x-4\">\n",
301
+ "<uk-icon icon=\"check\" class=\"text-green-500 mr-2\"></uk-icon> <li>Advanced analytics dashboard</li>\n",
302
+ " </div>\n",
303
+ " <div class=\"uk-flex uk-flex-row uk-flex-middle space-x-4\">\n",
304
+ "<uk-icon icon=\"check\" class=\"text-green-500 mr-2\"></uk-icon> <li>Full API access</li>\n",
305
+ " </div>\n",
306
+ " <div class=\"uk-flex uk-flex-row uk-flex-middle space-x-4\">\n",
307
+ "<uk-icon icon=\"check\" class=\"text-green-500 mr-2\"></uk-icon> <li>Priority request queue</li>\n",
308
+ " </div>\n",
309
+ " </ul>\n",
310
+ "<button type=\"submit\" class=\"uk-btn uk-btn-primary w-full\">Subscribe Now</button> </div>\n",
311
+ " </div>\n",
312
+ "</div>\n",
313
+ "\n",
314
+ "```"
315
+ ],
316
+ "text/plain": [
317
+ "div((div((div((div((h2(('Pro Plan',),{'class': 'uk-h2 '}), h3(('$99',),{'class': 'uk-h3 text-primary'}), p(('per month',),{'class': 'uk-text-muted '})),{'class': 'uk-flex uk-flex-column uk-flex-middle space-y-1'}), ul((div((uk-icon((),{'icon': 'check', 'class': 'text-green-500 mr-2'}), li(('Unlimited users',),{})),{'class': 'uk-flex uk-flex-row uk-flex-middle space-x-4'}), div((uk-icon((),{'icon': 'check', 'class': 'text-green-500 mr-2'}), li(('24/7 priority support',),{})),{'class': 'uk-flex uk-flex-row uk-flex-middle space-x-4'}), div((uk-icon((),{'icon': 'check', 'class': 'text-green-500 mr-2'}), li(('Custom branding options',),{})),{'class': 'uk-flex uk-flex-row uk-flex-middle space-x-4'}), div((uk-icon((),{'icon': 'check', 'class': 'text-green-500 mr-2'}), li(('Advanced analytics dashboard',),{})),{'class': 'uk-flex uk-flex-row uk-flex-middle space-x-4'}), div((uk-icon((),{'icon': 'check', 'class': 'text-green-500 mr-2'}), li(('Full API access',),{})),{'class': 'uk-flex uk-flex-row uk-flex-middle space-x-4'}), div((uk-icon((),{'icon': 'check', 'class': 'text-green-500 mr-2'}), li(('Priority request queue',),{})),{'class': 'uk-flex uk-flex-row uk-flex-middle space-x-4'})),{'class': 'space-y-4'}), button(('Subscribe Now',),{'type': 'submit', 'class': 'uk-btn uk-btn-primary w-full'})),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}),),{'class': 'uk-flex uk-flex-column uk-flex-middle space-y-4'})"
318
+ ]
319
+ },
320
+ "execution_count": 165,
321
+ "metadata": {},
322
+ "output_type": "execute_result"
323
+ }
324
+ ],
325
+ "source": [
326
+ "features = [\n",
327
+ " \"Unlimited users\",\n",
328
+ " \"24/7 priority support\",\n",
329
+ " \"Custom branding options\", \n",
330
+ " \"Advanced analytics dashboard\",\n",
331
+ " \"Full API access\",\n",
332
+ " \"Priority request queue\"\n",
333
+ "]\n",
334
+ "\n",
335
+ "\n",
336
+ "def PricingCard(plan, price, features):\n",
337
+ " \"Create a polished pricing card with consistent styling\"\n",
338
+ " return Card(\n",
339
+ " DivVStacked( # Center and veritcally stack the plan name and price\n",
340
+ " H2(plan),\n",
341
+ " H3(price, cls='text-primary'),\n",
342
+ " P('per month',cls=TextT.muted),\n",
343
+ " cls='space-y-1'),\n",
344
+ " # DivHStacked makes green check and feature Li show up on same row instead of newline\n",
345
+ " Ul(*[DivHStacked(UkIcon('check', cls='text-green-500 mr-2'), Li(feature)) for feature in features], \n",
346
+ " cls='space-y-4'),\n",
347
+ " Button(\"Subscribe Now\", cls=(ButtonT.primary, 'w-full')))\n",
348
+ "\n",
349
+ "DivVStacked(PricingCard(\"Pro Plan\", \"$99\", features))"
350
+ ]
351
+ },
352
+ {
353
+ "cell_type": "markdown",
354
+ "id": "ddf9cf78",
355
+ "metadata": {},
356
+ "source": [
357
+ "## Footer\n",
358
+ "\n",
359
+ "Or you can combine things to make advanced footers that have titles, organized links, and icons!\n",
360
+ "\n",
361
+ "In this example we add another flex helper function, `DivFullySpaced`. `DivFullySpaced` is a flex class that puts as much space between items as possible"
362
+ ]
363
+ },
364
+ {
365
+ "cell_type": "code",
366
+ "execution_count": 176,
367
+ "id": "ee79e8cf",
368
+ "metadata": {
369
+ "scrolled": false
370
+ },
371
+ "outputs": [
372
+ {
373
+ "data": {
374
+ "text/markdown": [
375
+ "```html\n",
376
+ "<div class=\"uk-container bg-gray-50 py-12\">\n",
377
+ " <div class=\"space-y-8\">\n",
378
+ " <div class=\"uk-flex uk-flex-between uk-flex-middle w-full\">\n",
379
+ " <h3 class=\"uk-h3 \">Company Name</h3>\n",
380
+ " <div class=\"uk-flex uk-flex-row uk-flex-middle space-x-4\">\n",
381
+ "<uk-icon icon=\"twitter\" class=\"uk-text-lead\"></uk-icon><uk-icon icon=\"facebook\" class=\"uk-text-lead\"></uk-icon><uk-icon icon=\"github\" class=\"uk-text-lead\"></uk-icon><uk-icon icon=\"linkedin\" class=\"uk-text-lead\"></uk-icon> </div>\n",
382
+ " </div>\n",
383
+ "<hr class=\"my-4 h-[2px] w-full bg-secondary\"> <div class=\"uk-flex uk-flex-between uk-flex-middle w-full\">\n",
384
+ " <div class=\"uk-flex uk-flex-column uk-flex-middle space-y-4\">\n",
385
+ " <h4 class=\"uk-h4 \">Company</h4>\n",
386
+ "<a href=\"#about\" class=\"uk-text-muted\">About</a><a href=\"#blog\" class=\"uk-text-muted\">Blog</a><a href=\"#careers\" class=\"uk-text-muted\">Careers</a><a href=\"#press-kit\" class=\"uk-text-muted\">Press Kit</a> </div>\n",
387
+ " <div class=\"uk-flex uk-flex-column uk-flex-middle space-y-4\">\n",
388
+ " <h4 class=\"uk-h4 \">Resources</h4>\n",
389
+ "<a href=\"#documentation\" class=\"uk-text-muted\">Documentation</a><a href=\"#help-center\" class=\"uk-text-muted\">Help Center</a><a href=\"#status\" class=\"uk-text-muted\">Status</a><a href=\"#contact-sales\" class=\"uk-text-muted\">Contact Sales</a> </div>\n",
390
+ " <div class=\"uk-flex uk-flex-column uk-flex-middle space-y-4\">\n",
391
+ " <h4 class=\"uk-h4 \">Legal</h4>\n",
392
+ "<a href=\"#terms-of-service\" class=\"uk-text-muted\">Terms of Service</a><a href=\"#privacy-policy\" class=\"uk-text-muted\">Privacy Policy</a><a href=\"#cookie-settings\" class=\"uk-text-muted\">Cookie Settings</a><a href=\"#accessibility\" class=\"uk-text-muted\">Accessibility</a> </div>\n",
393
+ " </div>\n",
394
+ "<hr class=\"my-4 h-[2px] w-full bg-secondary\"> <p class=\"uk-text-small uk-text-lead\">© 2024 Company Name. All rights reserved.</p>\n",
395
+ " </div>\n",
396
+ "</div>\n",
397
+ "\n",
398
+ "```"
399
+ ],
400
+ "text/plain": [
401
+ "div((div((div((h3(('Company Name',),{'class': 'uk-h3 '}), div((uk-icon((),{'icon': 'twitter', 'class': <TextT.lead: 'uk-text-lead'>}), uk-icon((),{'icon': 'facebook', 'class': <TextT.lead: 'uk-text-lead'>}), uk-icon((),{'icon': 'github', 'class': <TextT.lead: 'uk-text-lead'>}), uk-icon((),{'icon': 'linkedin', 'class': <TextT.lead: 'uk-text-lead'>})),{'class': 'uk-flex uk-flex-row uk-flex-middle space-x-4'})),{'class': 'uk-flex uk-flex-between uk-flex-middle w-full'}), hr((),{'class': 'my-4 h-[2px] w-full bg-secondary'}), div((div((h4(('Company',),{'class': 'uk-h4 '}), a(('About',),{'href': '#about', 'class': <TextT.muted: 'uk-text-muted'>}), a(('Blog',),{'href': '#blog', 'class': <TextT.muted: 'uk-text-muted'>}), a(('Careers',),{'href': '#careers', 'class': <TextT.muted: 'uk-text-muted'>}), a(('Press Kit',),{'href': '#press-kit', 'class': <TextT.muted: 'uk-text-muted'>})),{'class': 'uk-flex uk-flex-column uk-flex-middle space-y-4'}), div((h4(('Resources',),{'class': 'uk-h4 '}), a(('Documentation',),{'href': '#documentation', 'class': <TextT.muted: 'uk-text-muted'>}), a(('Help Center',),{'href': '#help-center', 'class': <TextT.muted: 'uk-text-muted'>}), a(('Status',),{'href': '#status', 'class': <TextT.muted: 'uk-text-muted'>}), a(('Contact Sales',),{'href': '#contact-sales', 'class': <TextT.muted: 'uk-text-muted'>})),{'class': 'uk-flex uk-flex-column uk-flex-middle space-y-4'}), div((h4(('Legal',),{'class': 'uk-h4 '}), a(('Terms of Service',),{'href': '#terms-of-service', 'class': <TextT.muted: 'uk-text-muted'>}), a(('Privacy Policy',),{'href': '#privacy-policy', 'class': <TextT.muted: 'uk-text-muted'>}), a(('Cookie Settings',),{'href': '#cookie-settings', 'class': <TextT.muted: 'uk-text-muted'>}), a(('Accessibility',),{'href': '#accessibility', 'class': <TextT.muted: 'uk-text-muted'>})),{'class': 'uk-flex uk-flex-column uk-flex-middle space-y-4'})),{'class': 'uk-flex uk-flex-between uk-flex-middle w-full'}), hr((),{'class': 'my-4 h-[2px] w-full bg-secondary'}), p(('© 2024 Company Name. All rights reserved.',),{'class': 'uk-text-small uk-text-lead'})),{'class': 'space-y-8'}),),{'class': 'uk-container bg-gray-50 py-12'})"
402
+ ]
403
+ },
404
+ "execution_count": 176,
405
+ "metadata": {},
406
+ "output_type": "execute_result"
407
+ }
408
+ ],
409
+ "source": [
410
+ "def FooterLinkGroup(title, links):\n",
411
+ " # DivVStacked centers and makes title and each link stack vertically\n",
412
+ " return DivVStacked(\n",
413
+ " H4(title),\n",
414
+ " *[A(text, href=f\"#{text.lower().replace(' ', '-')}\", cls=TextT.muted) for text in links])\n",
415
+ "\n",
416
+ "company = [\"About\", \"Blog\", \"Careers\", \"Press Kit\"]\n",
417
+ "resource = [\"Documentation\", \"Help Center\", \"Status\", \"Contact Sales\"]\n",
418
+ "legal = [\"Terms of Service\", \"Privacy Policy\", \"Cookie Settings\", \"Accessibility\"]\n",
419
+ "\n",
420
+ "Container(cls='uk-background-muted py-12')(Div(\n",
421
+ " # Company Name and social icons will be on the same row with as much sapce between as possible\n",
422
+ " DivFullySpaced( \n",
423
+ " H3(\"Company Name\"),\n",
424
+ " # DivHStacked makes the icons be on the same row in a group\n",
425
+ " DivHStacked(*[UkIcon(icon, cls=TextT.lead) for icon in \n",
426
+ " ['twitter', 'facebook', 'github', 'linkedin']])),\n",
427
+ " DividerLine(),\n",
428
+ " DivFullySpaced( # Each child will be spread out as much as possible based on number of children\n",
429
+ " FooterLinkGroup(\"Company\", company),\n",
430
+ " FooterLinkGroup(\"Resources\", resource),\n",
431
+ " FooterLinkGroup(\"Legal\", legal)), \n",
432
+ " DividerLine(),\n",
433
+ " P(\"© 2024 Company Name. All rights reserved.\", cls=TextT.lead+TextT.sm),\n",
434
+ " cls='space-y-8 p-8'))"
435
+ ]
436
+ },
437
+ {
438
+ "cell_type": "markdown",
439
+ "id": "bb311899",
440
+ "metadata": {},
441
+ "source": [
442
+ "## Dashboard"
443
+ ]
444
+ },
445
+ {
446
+ "cell_type": "code",
447
+ "execution_count": 5,
448
+ "id": "1e29f9de",
449
+ "metadata": {},
450
+ "outputs": [],
451
+ "source": [
452
+ "def StatsCard(label, value, change):\n",
453
+ " color = 'green' if change[0] == '+' else 'red'\n",
454
+ " return Card(DivVStacked( # Stacks vertically and centers all elements\n",
455
+ " P(label, cls=TextPresets.muted_sm),\n",
456
+ " H3(value),\n",
457
+ " P(f\"{change}% from last month\", cls=f\"text-{color}-600 text-sm\")))\n",
458
+ " \n",
459
+ "def RecentActivity(user, action, time):\n",
460
+ " return DivHStacked( # Makes Avatar and text be on same row\n",
461
+ " DiceBearAvatar(user, h=8, w=8),\n",
462
+ " P(f\"{user} {action}\", cls=\"flex-1\"),\n",
463
+ " P(time, cls=TextPresets.muted_sm))\n",
464
+ " \n",
465
+ "DivVStacked( # Centers the entire dashboard layout\n",
466
+ " # Page header\n",
467
+ " DivVStacked( # Stacks vertically and centers the title/subtitle\n",
468
+ " H2(\"Welcome back, Isaac!\"),\n",
469
+ " P(\"Here's what's happening with your projects today.\",cls=TextT.muted)),\n",
470
+ "\n",
471
+ " # DivHStacked puts all the stats cards on the same row\n",
472
+ " DivHStacked(*(StatsCard(label, value, change)\n",
473
+ " for label, value, change in [\n",
474
+ " (\"Total Projects\", \"12\", \"+2.5\"),\n",
475
+ " (\"Hours Logged\", \"164\", \"+12.3\"),\n",
476
+ " (\"Tasks Complete\", \"64%\", \"-4.1\"),\n",
477
+ " (\"Team Velocity\", \"23\", \"+8.4\")]\n",
478
+ " )),\n",
479
+ "\n",
480
+ " # Recent activity\n",
481
+ " Card(*(RecentActivity(user, action, time) \n",
482
+ " for user, action, time in [\n",
483
+ " (\"Sarah Chen\", \"completed Project Alpha deployment\", \"2h ago\"),\n",
484
+ " (\"James Wilson\", \"commented on Project Beta\", \"4h ago\"),\n",
485
+ " (\"Maria Garcia\", \"uploaded new design files\", \"6h ago\"),\n",
486
+ " (\"Alex Kumar\", \"started Sprint Planning\", \"8h ago\")]),\n",
487
+ " header=H3(\"Recent Activity\"),\n",
488
+ " ),\n",
489
+ " cls=\"space-y-6\"\n",
490
+ ")"
491
+ ]
492
+ },
493
+ {
494
+ "cell_type": "markdown",
495
+ "id": "edd8dc07",
496
+ "metadata": {},
497
+ "source": [
498
+ "## Columns\n",
499
+ "\n",
500
+ "Columns are a great for sections that have a lot of text."
501
+ ]
502
+ },
503
+ {
504
+ "cell_type": "code",
505
+ "execution_count": 181,
506
+ "id": "6dfbd634",
507
+ "metadata": {},
508
+ "outputs": [
509
+ {
510
+ "data": {
511
+ "text/markdown": [
512
+ "```html\n",
513
+ "<div class=\"uk-container mt-5 uk-container-xlarge\">\n",
514
+ " <h1 class=\"uk-h1 text-center mb-8\">Lorem Ipsum</h1>\n",
515
+ " <div class=\"columns-2 gap-12\">\n",
516
+ " <p class=\"uk-paragraph \">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do \n",
517
+ " eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad \n",
518
+ " minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip \n",
519
+ " ex ea commodo consequat.</p>\n",
520
+ " <div class=\"uk-flex uk-flex-column uk-flex-middle uk-flex-center mt-8\">\n",
521
+ " <p class=\"uk-text-large uk-text-bold uk-text-center uk-text-italic text-primary\">Duis aute irure dolor in reprehenderit in voluptate velit esse \n",
522
+ " cillum dolore eu fugiat nulla pariatur.</p>\n",
523
+ " </div>\n",
524
+ " <p class=\"uk-paragraph \">Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \n",
525
+ " officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde \n",
526
+ " omnis iste natus error sit voluptatem accusantium doloremque laudantium.</p>\n",
527
+ " <p class=\"uk-paragraph \">Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit \n",
528
+ " aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem \n",
529
+ " sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor.</p>\n",
530
+ " </div>\n",
531
+ "</div>\n",
532
+ "\n",
533
+ "```"
534
+ ],
535
+ "text/plain": [
536
+ "div((h1(('Lorem Ipsum',),{'class': 'uk-h1 text-center mb-8'}), div((p(('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do \\n eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad \\n minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip \\n ex ea commodo consequat.',),{'class': 'uk-paragraph '}), div((p(('Duis aute irure dolor in reprehenderit in voluptate velit esse \\n cillum dolore eu fugiat nulla pariatur.',),{'class': 'uk-text-large uk-text-bold uk-text-center uk-text-italic text-primary'}),),{'class': 'uk-flex uk-flex-column uk-flex-middle uk-flex-center mt-8'}), p(('Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \\n officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde \\n omnis iste natus error sit voluptatem accusantium doloremque laudantium.',),{'class': 'uk-paragraph '}), p(('Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit \\n aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem \\n sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor.',),{'class': 'uk-paragraph '})),{'class': 'columns-2 gap-12'})),{'class': 'uk-container mt-5 uk-container-xlarge'})"
537
+ ]
538
+ },
539
+ "execution_count": 181,
540
+ "metadata": {},
541
+ "output_type": "execute_result"
542
+ }
543
+ ],
544
+ "source": [
545
+ "Container(\n",
546
+ " H1(\"Lorem Ipsum\", cls=\"text-center mb-8\"),\n",
547
+ "\n",
548
+ " # Use 2 columns for the main content\n",
549
+ " Div(cls=\"columns-2 gap-12\")(\n",
550
+ " P(\"\"\"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do \n",
551
+ " eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad \n",
552
+ " minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip \n",
553
+ " ex ea commodo consequat.\"\"\"),\n",
554
+ "\n",
555
+ " DivCentered(cls='mt-8')(\n",
556
+ " P(\"\"\"Duis aute irure dolor in reprehenderit in voluptate velit esse \n",
557
+ " cillum dolore eu fugiat nulla pariatur.\"\"\", \n",
558
+ " cls=(TextT.lg, TextT.bold, TextT.center, TextT.italic, \"text-primary\"))),\n",
559
+ "\n",
560
+ " P(\"\"\"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \n",
561
+ " officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde \n",
562
+ " omnis iste natus error sit voluptatem accusantium doloremque laudantium.\"\"\"),\n",
563
+ "\n",
564
+ " P(\"\"\"Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit \n",
565
+ " aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem \n",
566
+ " sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor.\"\"\")))"
567
+ ]
568
+ }
569
+ ],
570
+ "metadata": {
571
+ "kernelspec": {
572
+ "display_name": "Python 3 (ipykernel)",
573
+ "language": "python",
574
+ "name": "python3"
575
+ },
576
+ "language_info": {
577
+ "codemirror_mode": {
578
+ "name": "ipython",
579
+ "version": 3
580
+ },
581
+ "file_extension": ".py",
582
+ "mimetype": "text/x-python",
583
+ "name": "python",
584
+ "nbconvert_exporter": "python",
585
+ "pygments_lexer": "ipython3",
586
+ "version": "3.12.8"
587
+ }
588
+ },
589
+ "nbformat": 4,
590
+ "nbformat_minor": 5
591
+ }
MonsterUI/docs/guides/Spacing.ipynb ADDED
@@ -0,0 +1,482 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "ce15239f",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Padding & Margin & Spacing, Oh my! (MonsterUI Spacing Guide)\n",
9
+ "\n",
10
+ "This guide will cover some essentials about how to properly space apps and what the differences are between:\n",
11
+ "\n",
12
+ "- Padding\n",
13
+ "- Margin\n",
14
+ "- Spacing\n",
15
+ "- Gap\n",
16
+ "\n",
17
+ "Manipulating the space between components can make a huge difference to the percieved quality of the page. Being able to tweak the spacing can have a big impact!\n",
18
+ "\n",
19
+ "> Tip: I find it works best to get everything on the page without adjusting spacing much, and adjusting spacing at the end. \n",
20
+ "\n",
21
+ "## Abreviations:\n",
22
+ "\n",
23
+ "First a few abbreviations that are helpful to know with tailwind (and a convention we follow in `MonsterUI`).\n",
24
+ "\n",
25
+ "- `t`, `b`, `l`, `r` = top, bottom, left, right\n",
26
+ "- `p`, `m` = padding, margin\n",
27
+ "- `x`, `y` = horizontal, vertical\n",
28
+ "\n",
29
+ "That means:\n",
30
+ "\n",
31
+ "- `mt` means margin on top of the element\n",
32
+ "- `px` means padding on the x axis (both left and right)\n",
33
+ "- `space-y` means apply spacing on the y axis (both top and bottom)\n",
34
+ "\n",
35
+ "## Padding vs Margin\n",
36
+ "\n",
37
+ "Margin applies space to the left of the component, and padding applies space on the left inside of the component. \n",
38
+ "\n",
39
+ "Please reference the example with cards below:\n",
40
+ "\n",
41
+ "- `ml-20` applies space to the left of the card (outside the card)\n",
42
+ "- `pl-20` applies space on the left inside of the card (inside the card)\n",
43
+ "\n",
44
+ "This means that if you want to move the whole thing but keep the actual container unchanged, use margin. If you want to change the container by adding space inside of it, use padding."
45
+ ]
46
+ },
47
+ {
48
+ "cell_type": "code",
49
+ "execution_count": 2,
50
+ "id": "aef6844a",
51
+ "metadata": {
52
+ "scrolled": true
53
+ },
54
+ "outputs": [
55
+ {
56
+ "data": {
57
+ "text/markdown": [
58
+ "```html\n",
59
+ "<div class=\"grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-4\">\n",
60
+ " <div class=\"uk-card ml-20\">\n",
61
+ " <div class=\"uk-card-body space-y-6\">\n",
62
+ " <h4 class=\"uk-h4 \" style=\"background-color: red\">A Simple Card with ml-20</h4>\n",
63
+ " </div>\n",
64
+ " </div>\n",
65
+ " <div class=\"uk-card pl-20\">\n",
66
+ " <div class=\"uk-card-body space-y-6\">\n",
67
+ " <h4 class=\"uk-h4 \" style=\"background-color: red\">A Simple Card with pl-20</h4>\n",
68
+ " </div>\n",
69
+ " </div>\n",
70
+ "</div>\n",
71
+ "\n",
72
+ "```"
73
+ ],
74
+ "text/plain": [
75
+ "div((div((div((h4(('A Simple Card with ml-20',),{'class': 'uk-h4 ', 'style': 'background-color: red'}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card ml-20'}), div((div((h4(('A Simple Card with pl-20',),{'class': 'uk-h4 ', 'style': 'background-color: red'}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card pl-20'})),{'class': 'grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-4'})"
76
+ ]
77
+ },
78
+ "execution_count": 2,
79
+ "metadata": {},
80
+ "output_type": "execute_result"
81
+ }
82
+ ],
83
+ "source": [
84
+ "Grid(\n",
85
+ " Card(H4(\"A Simple Card with ml-20\",style='background-color: red'), \n",
86
+ " cls='ml-20'),\n",
87
+ " Card(H4(\"A Simple Card with pl-20\", style='background-color: red'),\n",
88
+ " cls='pl-20'))"
89
+ ]
90
+ },
91
+ {
92
+ "cell_type": "markdown",
93
+ "id": "59ed6d0d",
94
+ "metadata": {},
95
+ "source": [
96
+ "## Space vs gap\n",
97
+ "\n",
98
+ "Spacing and gap are both about setting the space between components.\n",
99
+ "\n",
100
+ "+ Spacing applies margin to every element except for the first element in a group. \n",
101
+ "+ Gap creates a gap between every element in flexbox elements and grids.\n",
102
+ "\n",
103
+ ">Rule of thumb: Use Gap when using grids.\n",
104
+ "\n",
105
+ "Let's take a look at some grid examples."
106
+ ]
107
+ },
108
+ {
109
+ "cell_type": "markdown",
110
+ "id": "22ad2226",
111
+ "metadata": {},
112
+ "source": [
113
+ "#### Grid"
114
+ ]
115
+ },
116
+ {
117
+ "cell_type": "code",
118
+ "execution_count": 8,
119
+ "id": "a296d044",
120
+ "metadata": {},
121
+ "outputs": [
122
+ {
123
+ "data": {
124
+ "text/markdown": [
125
+ "```html\n",
126
+ "<div class=\"grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 \">\n",
127
+ " <div class=\"uk-card \">\n",
128
+ " <div class=\"uk-card-body space-y-6\">\n",
129
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
130
+ " </div>\n",
131
+ " </div>\n",
132
+ " <div class=\"uk-card \">\n",
133
+ " <div class=\"uk-card-body space-y-6\">\n",
134
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
135
+ " </div>\n",
136
+ " </div>\n",
137
+ " <div class=\"uk-card \">\n",
138
+ " <div class=\"uk-card-body space-y-6\">\n",
139
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
140
+ " </div>\n",
141
+ " </div>\n",
142
+ " <div class=\"uk-card \">\n",
143
+ " <div class=\"uk-card-body space-y-6\">\n",
144
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
145
+ " </div>\n",
146
+ " </div>\n",
147
+ " <div class=\"uk-card \">\n",
148
+ " <div class=\"uk-card-body space-y-6\">\n",
149
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
150
+ " </div>\n",
151
+ " </div>\n",
152
+ " <div class=\"uk-card \">\n",
153
+ " <div class=\"uk-card-body space-y-6\">\n",
154
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
155
+ " </div>\n",
156
+ " </div>\n",
157
+ "</div>\n",
158
+ "\n",
159
+ "```"
160
+ ],
161
+ "text/plain": [
162
+ "div((div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '})),{'class': 'grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 '})"
163
+ ]
164
+ },
165
+ "execution_count": 8,
166
+ "metadata": {},
167
+ "output_type": "execute_result"
168
+ }
169
+ ],
170
+ "source": [
171
+ "Grid(\n",
172
+ " Card(H4(\"A Simple Card\")),\n",
173
+ " Card(H4(\"A Simple Card\")),\n",
174
+ " Card(H4(\"A Simple Card\")),\n",
175
+ " Card(H4(\"A Simple Card\")),\n",
176
+ " Card(H4(\"A Simple Card\")),\n",
177
+ " Card(H4(\"A Simple Card\")),\n",
178
+ " cls='')"
179
+ ]
180
+ },
181
+ {
182
+ "cell_type": "markdown",
183
+ "id": "286c245f",
184
+ "metadata": {},
185
+ "source": [
186
+ "#### Grid with gap"
187
+ ]
188
+ },
189
+ {
190
+ "cell_type": "code",
191
+ "execution_count": 7,
192
+ "id": "ed24f5d3",
193
+ "metadata": {},
194
+ "outputs": [
195
+ {
196
+ "data": {
197
+ "text/markdown": [
198
+ "```html\n",
199
+ "<div class=\"grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-4\">\n",
200
+ " <div class=\"uk-card \">\n",
201
+ " <div class=\"uk-card-body space-y-6\">\n",
202
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
203
+ " </div>\n",
204
+ " </div>\n",
205
+ " <div class=\"uk-card \">\n",
206
+ " <div class=\"uk-card-body space-y-6\">\n",
207
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
208
+ " </div>\n",
209
+ " </div>\n",
210
+ " <div class=\"uk-card \">\n",
211
+ " <div class=\"uk-card-body space-y-6\">\n",
212
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
213
+ " </div>\n",
214
+ " </div>\n",
215
+ " <div class=\"uk-card \">\n",
216
+ " <div class=\"uk-card-body space-y-6\">\n",
217
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
218
+ " </div>\n",
219
+ " </div>\n",
220
+ " <div class=\"uk-card \">\n",
221
+ " <div class=\"uk-card-body space-y-6\">\n",
222
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
223
+ " </div>\n",
224
+ " </div>\n",
225
+ " <div class=\"uk-card \">\n",
226
+ " <div class=\"uk-card-body space-y-6\">\n",
227
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
228
+ " </div>\n",
229
+ " </div>\n",
230
+ "</div>\n",
231
+ "\n",
232
+ "```"
233
+ ],
234
+ "text/plain": [
235
+ "div((div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '})),{'class': 'grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-4'})"
236
+ ]
237
+ },
238
+ "execution_count": 7,
239
+ "metadata": {},
240
+ "output_type": "execute_result"
241
+ }
242
+ ],
243
+ "source": [
244
+ "Grid(\n",
245
+ " Card(H4(\"A Simple Card\")),\n",
246
+ " Card(H4(\"A Simple Card\")),\n",
247
+ " Card(H4(\"A Simple Card\")),\n",
248
+ " Card(H4(\"A Simple Card\")),\n",
249
+ " Card(H4(\"A Simple Card\")),\n",
250
+ " Card(H4(\"A Simple Card\")),\n",
251
+ " cls='gap-4')"
252
+ ]
253
+ },
254
+ {
255
+ "cell_type": "markdown",
256
+ "id": "7bb43e6d",
257
+ "metadata": {},
258
+ "source": [
259
+ "#### Grid with space"
260
+ ]
261
+ },
262
+ {
263
+ "cell_type": "code",
264
+ "execution_count": 5,
265
+ "id": "44130942",
266
+ "metadata": {},
267
+ "outputs": [
268
+ {
269
+ "data": {
270
+ "text/markdown": [
271
+ "```html\n",
272
+ "<div class=\"grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 space-x-4 space-y-4\">\n",
273
+ " <div class=\"uk-card \">\n",
274
+ " <div class=\"uk-card-body space-y-6\">\n",
275
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
276
+ " </div>\n",
277
+ " </div>\n",
278
+ " <div class=\"uk-card \">\n",
279
+ " <div class=\"uk-card-body space-y-6\">\n",
280
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
281
+ " </div>\n",
282
+ " </div>\n",
283
+ " <div class=\"uk-card \">\n",
284
+ " <div class=\"uk-card-body space-y-6\">\n",
285
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
286
+ " </div>\n",
287
+ " </div>\n",
288
+ " <div class=\"uk-card \">\n",
289
+ " <div class=\"uk-card-body space-y-6\">\n",
290
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
291
+ " </div>\n",
292
+ " </div>\n",
293
+ " <div class=\"uk-card \">\n",
294
+ " <div class=\"uk-card-body space-y-6\">\n",
295
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
296
+ " </div>\n",
297
+ " </div>\n",
298
+ " <div class=\"uk-card \">\n",
299
+ " <div class=\"uk-card-body space-y-6\">\n",
300
+ " <h4 class=\"uk-h4 \">A Simple Card</h4>\n",
301
+ " </div>\n",
302
+ " </div>\n",
303
+ "</div>\n",
304
+ "\n",
305
+ "```"
306
+ ],
307
+ "text/plain": [
308
+ "div((div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '}), div((div((h4(('A Simple Card',),{'class': 'uk-h4 '}),),{'class': 'uk-card-body space-y-6'}),),{'class': 'uk-card '})),{'class': 'grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 space-x-4 space-y-4'})"
309
+ ]
310
+ },
311
+ "execution_count": 5,
312
+ "metadata": {},
313
+ "output_type": "execute_result"
314
+ }
315
+ ],
316
+ "source": [
317
+ "Grid(\n",
318
+ " Card(H4(\"A Simple Card\")),\n",
319
+ " Card(H4(\"A Simple Card\")),\n",
320
+ " Card(H4(\"A Simple Card\")),\n",
321
+ " Card(H4(\"A Simple Card\")),\n",
322
+ " Card(H4(\"A Simple Card\")),\n",
323
+ " Card(H4(\"A Simple Card\")),\n",
324
+ " cls='space-x-4 space-y-4')"
325
+ ]
326
+ },
327
+ {
328
+ "cell_type": "markdown",
329
+ "id": "50c48f82",
330
+ "metadata": {},
331
+ "source": [
332
+ "### Grid with no gap or space\n",
333
+ "\n",
334
+ "The first example has no gap or not space applied. As expected this means the cards are flush with each other. Often this is not what you want, because a little space between cards looks much nicer.\n",
335
+ "\n",
336
+ "### Grid with gap\n",
337
+ "\n",
338
+ "The second example has the same grid but with gap applied. As youc an see, this gives constent space between all elements of the grid looks great!\n",
339
+ "\n",
340
+ "### Grid with space\n",
341
+ "\n",
342
+ "The third example has the same grid but with space applied. As you can see, it's not really what we want. However it's a really good illustration of how space works so let's notice a few things about it:\n",
343
+ "\n",
344
+ "**X Axis**\n",
345
+ "\n",
346
+ "- The first card is flush with the left side of the page (no margin)\n",
347
+ "- The card below it isn't flush with the left side of the page (has margin)\n",
348
+ "\n",
349
+ "**Y Axis**\n",
350
+ "\n",
351
+ "- The first card is flush with the heading immediately above it (no margin)\n",
352
+ "- The card top it's right isn't flush with the heading above it (has margin)\n",
353
+ "\n",
354
+ "So `space` applies margin to every element except for the first element in a group!\n",
355
+ "\n",
356
+ "> Tip: Use your browser developer tools to inspect the examples\n",
357
+ "\n",
358
+ "Next, let's look at a form example where `gap` isn't a good choice but `space` works beautifully!"
359
+ ]
360
+ },
361
+ {
362
+ "cell_type": "code",
363
+ "execution_count": null,
364
+ "id": "36d1949c",
365
+ "metadata": {},
366
+ "outputs": [],
367
+ "source": [
368
+ "Form(DivCentered(H3(\"My Form\")),\n",
369
+ " LabelInput(\"Name\"),\n",
370
+ " Grid(LabelInput(\"Phone\"), LabelInput(\"Email\"), cols=2),\n",
371
+ " cls='')"
372
+ ]
373
+ },
374
+ {
375
+ "cell_type": "code",
376
+ "execution_count": null,
377
+ "id": "e8c5d280",
378
+ "metadata": {},
379
+ "outputs": [],
380
+ "source": [
381
+ "Form(DivCentered(H3(\"My Form with gap\")),\n",
382
+ " LabelInput(\"Name\"),\n",
383
+ " Grid(LabelInput(\"Phone\"), LabelInput(\"Email\"), cols=2),\n",
384
+ " cls='gap-y-5')"
385
+ ]
386
+ },
387
+ {
388
+ "cell_type": "code",
389
+ "execution_count": 9,
390
+ "id": "b2566530",
391
+ "metadata": {},
392
+ "outputs": [
393
+ {
394
+ "data": {
395
+ "text/markdown": [
396
+ "```html\n",
397
+ "<form enctype=\"multipart/form-data\" class=\"space-y-5\"> <div class=\"uk-flex uk-flex-column uk-flex-middle uk-flex-center space-y-4\">\n",
398
+ " <h3 class=\"uk-h3 \">My Form with Spacing</h3>\n",
399
+ " </div>\n",
400
+ " <div class=\"space-y-2\">\n",
401
+ "<label class=\"uk-form-label \">Name</label> <input class=\"uk-input \">\n",
402
+ " </div>\n",
403
+ " <div class=\"grid grid-cols-2 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-2 gap-4\">\n",
404
+ " <div class=\"space-y-2\">\n",
405
+ "<label class=\"uk-form-label \">Phone</label> <input class=\"uk-input \">\n",
406
+ " </div>\n",
407
+ " <div class=\"space-y-2\">\n",
408
+ "<label class=\"uk-form-label \">Email</label> <input class=\"uk-input \">\n",
409
+ " </div>\n",
410
+ " </div>\n",
411
+ "</form>\n",
412
+ "```"
413
+ ],
414
+ "text/plain": [
415
+ "form((div((h3(('My Form with Spacing',),{'class': 'uk-h3 '}),),{'class': 'uk-flex uk-flex-column uk-flex-middle uk-flex-center space-y-4'}), div((label(('Name',),{'for': '', 'class': 'uk-form-label '}), input((),{'id': '', 'class': 'uk-input '})),{'class': 'space-y-2'}), div((div((label(('Phone',),{'for': '', 'class': 'uk-form-label '}), input((),{'id': '', 'class': 'uk-input '})),{'class': 'space-y-2'}), div((label(('Email',),{'for': '', 'class': 'uk-form-label '}), input((),{'id': '', 'class': 'uk-input '})),{'class': 'space-y-2'})),{'class': 'grid grid-cols-2 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-2 gap-4'})),{'enctype': 'multipart/form-data', 'class': 'space-y-5'})"
416
+ ]
417
+ },
418
+ "execution_count": 9,
419
+ "metadata": {},
420
+ "output_type": "execute_result"
421
+ }
422
+ ],
423
+ "source": [
424
+ "Form(DivCentered(H3(\"My Form with Spacing\")),\n",
425
+ " LabelInput(\"Name\"),\n",
426
+ " Grid(LabelInput(\"Phone\"), LabelInput(\"Email\"), cols=2),\n",
427
+ " cls='space-y-5')"
428
+ ]
429
+ },
430
+ {
431
+ "cell_type": "markdown",
432
+ "id": "85e821ad",
433
+ "metadata": {},
434
+ "source": [
435
+ "### Form with no gap or space\n",
436
+ "\n",
437
+ "The top form looks a bit scrunched with defaults, but it's certainly passable. There is a bit of a space between the label and it's associated input because of the defaults in MonsterUI.\n",
438
+ "\n",
439
+ "### Form with gap\n",
440
+ "\n",
441
+ "The second form with gap is identical to the first. Because we're not in a flex element or a grid, it doesn't do anything at all!\n",
442
+ "\n",
443
+ "### Form with space\n",
444
+ "\n",
445
+ "`Space-y-5` adds vertical space between each child which really spreads out the form for a nice aesthetic. If you recall from the grid example, it does not apply this margin to the first element - but in this situation (and many others) we do not want the spacing above the top element (heading) to be the same as the spacing between the form elements.\n",
446
+ "\n",
447
+ "> Tip: Use your browser developer tools to inspect the examples\n"
448
+ ]
449
+ },
450
+ {
451
+ "cell_type": "markdown",
452
+ "id": "83d0f4ea",
453
+ "metadata": {},
454
+ "source": [
455
+ "# Further reading\n",
456
+ "\n",
457
+ "For further reading, check out the [Tailwind CSS guide](https://tailwindcss.com/docs/margin#adding-margin-to-a-single-side), which other users have found to be a useful as an additional guide."
458
+ ]
459
+ }
460
+ ],
461
+ "metadata": {
462
+ "kernelspec": {
463
+ "display_name": "Python 3 (ipykernel)",
464
+ "language": "python",
465
+ "name": "python3"
466
+ },
467
+ "language_info": {
468
+ "codemirror_mode": {
469
+ "name": "ipython",
470
+ "version": 3
471
+ },
472
+ "file_extension": ".py",
473
+ "mimetype": "text/x-python",
474
+ "name": "python",
475
+ "nbconvert_exporter": "python",
476
+ "pygments_lexer": "ipython3",
477
+ "version": "3.12.8"
478
+ }
479
+ },
480
+ "nbformat": 4,
481
+ "nbformat_minor": 5
482
+ }
MonsterUI/docs/htmxindicator.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fasthtml.common import *
2
+ from monsterui.all import *
3
+ import time
4
+ from fasthtml.components import Uk_theme_switcher
5
+
6
+ app, rt = fast_app(hdrs=Theme.blue.headers())
7
+
8
+ @rt
9
+ def index():
10
+ return Titled("Loading Demo",
11
+ Button("Load", id='load',
12
+ hx_get=load, hx_target='#content', hx_swap='beforeend',
13
+ hx_indicator='#loading'),
14
+ Div(id='content'),
15
+ Loading(id='loading', htmx_indicator=True))
16
+
17
+ @rt
18
+ def load():
19
+ time.sleep(1)
20
+ return P("Loading Demo")
21
+
22
+ @rt
23
+ def theme(): return Uk_theme_switcher()
24
+
25
+ serve()
MonsterUI/docs/llms-ctx-full.txt ADDED
The diff for this file is too large to render. See raw diff
 
MonsterUI/docs/llms-ctx.txt ADDED
@@ -0,0 +1,1603 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <project title="MonsterUI Documentation">> MonsterUI is a python library which brings styling to python for FastHTML apps.<api reference><doc title="API List" desc="Complete API Reference"># monsterui Module Documentation
2
+
3
+ ## monsterui.core
4
+
5
+ - `class ThemeRadii(Enum)`
6
+ Members: none, sm, md, lg
7
+
8
+
9
+ - `class ThemeShadows`
10
+
11
+ - `class ThemeFont`
12
+
13
+ - `class Theme(Enum)`
14
+ Selector to choose theme and get all headers needed for app. Includes frankenui + tailwind + daisyui + highlight.js options
15
+ Members: slate, stone, gray, neutral, red, rose, orange, green, blue, yellow, violet, zinc
16
+
17
+ - `headers(self, mode, icons, daisy, highlightjs, katex, apex_charts, radii, shadows, font)`
18
+ Create frankenui and tailwind cdns
19
+
20
+ - `local_headers(self, mode, static_dir, icons, daisy, highlightjs, katex, apex_charts, radii, shadows, font)`
21
+ Create headers using local files downloaded from CDNs
22
+
23
+
24
+ ## monsterui.daisy
25
+
26
+ - `class AlertT(Enum)`
27
+ Alert styles from DaisyUI
28
+ Members: info, success, warning, error
29
+
30
+
31
+ - `def Alert(*c, **kwargs)`
32
+ Alert informs users about important events.
33
+
34
+ - `class StepsT(Enum)`
35
+ Options for Steps
36
+ Members: vertical, horizonal
37
+
38
+
39
+ - `class StepT(Enum)`
40
+ Step styles for LiStep
41
+ Members: primary, secondary, accent, info, success, warning, error, neutral
42
+
43
+
44
+ - `def Steps(*li, **kwargs)`
45
+ Creates a steps container
46
+
47
+ - `def LiStep(*c, **kwargs)`
48
+ Creates a step list item
49
+
50
+ - `class LoadingT(Enum)`
51
+ Members: spinner, dots, ring, ball, bars, infinity, xs, sm, md, lg
52
+
53
+
54
+ - `def Loading(cls, htmx_indicator, **kwargs)`
55
+ Creates a loading animation component
56
+
57
+ - `class ToastHT(Enum)`
58
+ Horizontal position for Toast
59
+ Members: start, center, end
60
+
61
+
62
+ - `class ToastVT(Enum)`
63
+ Vertical position for Toast
64
+ Members: top, middle, bottom
65
+
66
+
67
+ ## monsterui.foundations
68
+
69
+ > Data Structures and Utilties
70
+
71
+ - `def stringify(o)`
72
+ Converts input types into strings that can be passed to FT components
73
+
74
+ - `class VEnum(Enum)`
75
+ Members:
76
+
77
+ - `__str__(self)`
78
+ - `__add__(self, other)`
79
+ - `__radd__(self, other)`
80
+
81
+ ## monsterui.franken
82
+
83
+ - `class TextT(Enum)`
84
+ Text Styles from https://franken-ui.dev/docs/text
85
+ Members: paragraph, lead, meta, gray, italic, xs, sm, lg, xl, light, normal, medium, bold, extrabold, muted, primary, secondary, success, warning, error, info, left, right, center, justify, start, end, top, middle, bottom, truncate, break_, nowrap, underline, highlight
86
+
87
+
88
+ - `class TextPresets(Enum)`
89
+ Common Typography Presets
90
+ Members: muted_sm, muted_lg, bold_sm, bold_lg, md_weight_sm, md_weight_muted
91
+
92
+
93
+ - `def CodeSpan(*c, **kwargs)`
94
+ A CodeSpan with Styling
95
+
96
+ - `def CodeBlock(*c, **kwargs)`
97
+ CodeBlock with Styling
98
+
99
+ - `def H1(*c, **kwargs)`
100
+ H1 with styling and appropriate size
101
+
102
+ - `def H2(*c, **kwargs)`
103
+ H2 with styling and appropriate size
104
+
105
+ - `def H3(*c, **kwargs)`
106
+ H3 with styling and appropriate size
107
+
108
+ - `def H4(*c, **kwargs)`
109
+ H4 with styling and appropriate size
110
+
111
+ - `def H5(*c, **kwargs)`
112
+ H5 with styling and appropriate size
113
+
114
+ - `def H6(*c, **kwargs)`
115
+ H6 with styling and appropriate size
116
+
117
+ - `def Subtitle(*c, **kwargs)`
118
+ Styled muted_sm text designed to go under Headings and Titles
119
+
120
+ - `def Q(*c, **kwargs)`
121
+ Styled quotation mark
122
+
123
+ - `def Em(*c, **kwargs)`
124
+ Styled emphasis text
125
+
126
+ - `def Strong(*c, **kwargs)`
127
+ Styled strong text
128
+
129
+ - `def I(*c, **kwargs)`
130
+ Styled italic text
131
+
132
+ - `def Small(*c, **kwargs)`
133
+ Styled small text
134
+
135
+ - `def Mark(*c, **kwargs)`
136
+ Styled highlighted text
137
+
138
+ - `def Del(*c, **kwargs)`
139
+ Styled deleted text
140
+
141
+ - `def Ins(*c, **kwargs)`
142
+ Styled inserted text
143
+
144
+ - `def Sub(*c, **kwargs)`
145
+ Styled subscript text
146
+
147
+ - `def Sup(*c, **kwargs)`
148
+ Styled superscript text
149
+
150
+ - `def Blockquote(*c, **kwargs)`
151
+ Blockquote with Styling
152
+
153
+ - `def Caption(*c, **kwargs)`
154
+ Styled caption text
155
+
156
+ - `def Cite(*c, **kwargs)`
157
+ Styled citation text
158
+
159
+ - `def Time(*c, **kwargs)`
160
+ Styled time element
161
+
162
+ - `def Address(*c, **kwargs)`
163
+ Styled address element
164
+
165
+ - `def Abbr(*c, **kwargs)`
166
+ Styled abbreviation with dotted underline
167
+
168
+ - `def Dfn(*c, **kwargs)`
169
+ Styled definition term with italic and medium weight
170
+
171
+ - `def Kbd(*c, **kwargs)`
172
+ Styled keyboard input with subtle background
173
+
174
+ - `def Samp(*c, **kwargs)`
175
+ Styled sample output with subtle background
176
+
177
+ - `def Var(*c, **kwargs)`
178
+ Styled variable with italic monospace
179
+
180
+ - `def Figure(*c, **kwargs)`
181
+ Styled figure container with card-like appearance
182
+
183
+ - `def Details(*c, **kwargs)`
184
+ Styled details element
185
+
186
+ - `def Summary(*c, **kwargs)`
187
+ Styled summary element
188
+
189
+ - `def Data(*c, **kwargs)`
190
+ Styled data element
191
+
192
+ - `def Meter(*c, **kwargs)`
193
+ Styled meter element
194
+
195
+ - `def S(*c, **kwargs)`
196
+ Styled strikethrough text (different semantic meaning from Del)
197
+
198
+ - `def U(*c, **kwargs)`
199
+ Styled underline (for proper names in Chinese, proper spelling etc)
200
+
201
+ - `def Output(*c, **kwargs)`
202
+ Styled output element for form results
203
+
204
+ - `def PicSumImg(h, w, id, grayscale, blur, **kwargs)`
205
+ Creates a placeholder image using https://picsum.photos/
206
+
207
+ - `def AccordionItem(title, *c)`
208
+ Creates a single item for use within an Accordion component, handling title, content, and open state.
209
+
210
+ - `def Accordion(*c, **kwargs)`
211
+ Creates a styled Accordion container using accordion component.
212
+
213
+ - `class ButtonT(Enum)`
214
+ Options for styling Buttons
215
+ Members: default, ghost, primary, secondary, destructive, text, link, xs, sm, lg, xl, icon
216
+
217
+
218
+ - `def Button(*c, **kwargs)`
219
+ Button with Styling (defaults to `submit` for form submission)
220
+
221
+ - `class ContainerT(Enum)`
222
+ Max width container sizes from https://franken-ui.dev/docs/container
223
+ Members: xs, sm, lg, xl, expand
224
+
225
+
226
+ - `class BackgroundT(Enum)`
227
+ Members: muted, primary, secondary, default
228
+
229
+
230
+ - `def Container(*c, **kwargs)`
231
+ Div to be used as a container that often wraps large sections or a page of content
232
+
233
+ - `def Titled(title, *c, **kwargs)`
234
+ Creates a standard page structure for titled page. Main(Container(title, content))
235
+
236
+ - `class DividerT(Enum)`
237
+ Divider Styles from https://franken-ui.dev/docs/divider
238
+ Members: icon, sm, vertical
239
+
240
+
241
+ - `def Divider(*c, **kwargs)`
242
+ Divider with default styling and margin
243
+
244
+ - `def DividerSplit(*c)`
245
+ Creates a simple horizontal line divider with configurable thickness and vertical spacing
246
+
247
+ - `def Article(*c, **kwargs)`
248
+ A styled article container for blog posts or similar content
249
+
250
+ - `def ArticleTitle(*c, **kwargs)`
251
+ A title component for use within an Article
252
+
253
+ - `def ArticleMeta(*c, **kwargs)`
254
+ A metadata component for use within an Article showing things like date, author etc
255
+
256
+ - `class SectionT(Enum)`
257
+ Section styles from https://franken-ui.dev/docs/section
258
+ Members: default, muted, primary, secondary, xs, sm, lg, xl, remove_vertical
259
+
260
+
261
+ - `def Section(*c, **kwargs)`
262
+ Section with styling and margins
263
+
264
+ - `def Form(*c, **kwargs)`
265
+ A Form with default spacing between form elements
266
+
267
+ - `def Fieldset(*c, **kwargs)`
268
+ A Fieldset with default styling
269
+
270
+ - `def Legend(*c, **kwargs)`
271
+ A Legend with default styling
272
+
273
+ - `def Input(*c, **kwargs)`
274
+ An Input with default styling
275
+
276
+ - `def Radio(*c, **kwargs)`
277
+ A Radio with default styling
278
+
279
+ - `def CheckboxX(*c, **kwargs)`
280
+ A Checkbox with default styling
281
+
282
+ - `def Range(*c, **kwargs)`
283
+ A Range with default styling
284
+
285
+ - `def TextArea(*c, **kwargs)`
286
+ A Textarea with default styling
287
+
288
+ - `def Switch(*c, **kwargs)`
289
+ A Switch with default styling
290
+
291
+ - `def Upload(*c, **kwargs)`
292
+ A file upload component with default styling
293
+
294
+ - `def UploadZone(*c, **kwargs)`
295
+ A file drop zone component with default styling
296
+
297
+ - `def FormLabel(*c, **kwargs)`
298
+ A Label with default styling
299
+
300
+ - `class LabelT(Enum)`
301
+ Members: primary, secondary, destructive
302
+
303
+
304
+ - `def Label(*c, **kwargs)`
305
+ FrankenUI labels, which look like pills
306
+
307
+ - `def UkFormSection(title, description, *c)`
308
+ A form section with a title, description and optional button
309
+
310
+ - `def GenericLabelInput(label, lbl_cls, input_cls, container, cls, id, input_fn, **kwargs)`
311
+ `Div(Label,Input)` component with Uk styling injected appropriately. Generally you should higher level API, such as `LabelInput` which is created for you in this library
312
+
313
+ - `def LabelInput(label, lbl_cls, input_cls, cls, id, **kwargs)`
314
+ A `FormLabel` and `Input` pair that provides default spacing and links/names them based on id
315
+
316
+ - `def LabelRadio(label, lbl_cls, input_cls, container, cls, id, **kwargs)`
317
+ A FormLabel and Radio pair that provides default spacing and links/names them based on id
318
+
319
+ - `def LabelCheckboxX(label, lbl_cls, input_cls, container, cls, id, **kwargs)`
320
+ A FormLabel and CheckboxX pair that provides default spacing and links/names them based on id
321
+
322
+ - `def Options(*c)`
323
+ Helper function to wrap things into `Option`s for use in `Select`
324
+
325
+ - `def Select(*option, **kwargs)`
326
+ Creates a select dropdown with uk styling and option for adding a search box
327
+
328
+ - `def LabelSelect(*option, **kwargs)`
329
+ A FormLabel and Select pair that provides default spacing and links/names them based on id
330
+
331
+ - `@delegates(GenericLabelInput, but=['input_fn', 'cls']) def LabelRange(label, lbl_cls, input_cls, cls, id, value, min, max, step, label_range, **kwargs)`
332
+ A FormLabel and Range pair that provides default spacing and links/names them based on id
333
+
334
+ - `class AT(Enum)`
335
+ Link styles from https://franken-ui.dev/docs/link
336
+ Members: muted, text, reset, primary, classic
337
+
338
+
339
+ - `class ListT(Enum)`
340
+ List styles using Tailwind CSS
341
+ Members: disc, circle, square, decimal, hyphen, bullet, divider, striped
342
+
343
+
344
+ - `def ModalContainer(*c, **kwargs)`
345
+ Creates a modal container that components go in
346
+
347
+ - `def ModalDialog(*c, **kwargs)`
348
+ Creates a modal dialog
349
+
350
+ - `def ModalHeader(*c, **kwargs)`
351
+ Creates a modal header
352
+
353
+ - `def ModalBody(*c, **kwargs)`
354
+ Creates a modal body
355
+
356
+ - `def ModalFooter(*c, **kwargs)`
357
+ Creates a modal footer
358
+
359
+ - `def ModalTitle(*c, **kwargs)`
360
+ Creates a modal title
361
+
362
+ - `def ModalCloseButton(*c, **kwargs)`
363
+ Creates a button that closes a modal with js
364
+
365
+ - `def Modal(*c, **kwargs)`
366
+ Creates a modal with the appropriate classes to put the boilerplate in the appropriate places for you
367
+
368
+ - `def Placeholder(*c, **kwargs)`
369
+ Creates a placeholder
370
+
371
+ - `def Progress(*c, **kwargs)`
372
+ Creates a progress bar
373
+
374
+ - `def UkIcon(icon, height, width, stroke_width, cls, **kwargs)`
375
+ Creates an icon using lucide icons
376
+
377
+ - `def UkIconLink(icon, height, width, stroke_width, cls, button, **kwargs)`
378
+ Creates an icon link using lucide icons
379
+
380
+ - `def DiceBearAvatar(seed_name, h, w)`
381
+ Creates an Avatar using https://dicebear.com/
382
+
383
+ - `def Center(*c, **kwargs)`
384
+ Centers contents both vertically and horizontally by default
385
+
386
+ - `class FlexT(Enum)`
387
+ Flexbox modifiers using Tailwind CSS
388
+ Members: block, inline, left, center, right, between, around, stretch, top, middle, bottom, row, row_reverse, column, column_reverse, nowrap, wrap, wrap_reverse
389
+
390
+
391
+ - `def Grid(*div, **kwargs)`
392
+ Creates a responsive grid layout with smart defaults based on content
393
+
394
+ - `def DivFullySpaced(*c, **kwargs)`
395
+ Creates a flex div with it's components having as much space between them as possible
396
+
397
+ - `def DivCentered(*c, **kwargs)`
398
+ Creates a flex div with it's components centered in it
399
+
400
+ - `def DivLAligned(*c, **kwargs)`
401
+ Creates a flex div with it's components aligned to the left
402
+
403
+ - `def DivRAligned(*c, **kwargs)`
404
+ Creates a flex div with it's components aligned to the right
405
+
406
+ - `def DivVStacked(*c, **kwargs)`
407
+ Creates a flex div with it's components stacked vertically
408
+
409
+ - `def DivHStacked(*c, **kwargs)`
410
+ Creates a flex div with it's components stacked horizontally
411
+
412
+ - `class NavT(Enum)`
413
+ Members: default, primary, secondary
414
+
415
+
416
+ - `def NavContainer(*li, **kwargs)`
417
+ Creates a navigation container (useful for creating a sidebar navigation). A Nav is a list (NavBar is something different)
418
+
419
+ - `def NavParentLi(*nav_container, **kwargs)`
420
+ Creates a navigation list item with a parent nav for nesting
421
+
422
+ - `def NavDividerLi(*c, **kwargs)`
423
+ Creates a navigation list item with a divider
424
+
425
+ - `def NavHeaderLi(*c, **kwargs)`
426
+ Creates a navigation list item with a header
427
+
428
+ - `def NavSubtitle(*c, **kwargs)`
429
+ Creates a navigation subtitle
430
+
431
+ - `def NavCloseLi(*c, **kwargs)`
432
+ Creates a navigation list item with a close button
433
+
434
+ - `class ScrollspyT(Enum)`
435
+ Members: underline, bold
436
+
437
+
438
+ - `def NavBar(*c)`
439
+ Creates a responsive navigation bar with mobile menu support
440
+
441
+ - `def SliderContainer(*c, **kwargs)`
442
+ Creates a slider container
443
+
444
+ - `def SliderItems(*c, **kwargs)`
445
+ Creates a slider items container
446
+
447
+ - `def SliderNav(cls, prev_cls, next_cls, **kwargs)`
448
+ Navigation arrows for Slider component
449
+
450
+ - `def Slider(*c, **kwargs)`
451
+ Creates a slider with optional navigation arrows
452
+
453
+ - `def DropDownNavContainer(*li, **kwargs)`
454
+ A Nav that is part of a DropDown
455
+
456
+ - `def TabContainer(*li, **kwargs)`
457
+ A TabContainer where children will be different tabs
458
+
459
+ - `class CardT(Enum)`
460
+ Card styles from UIkit
461
+ Members: default, primary, secondary, destructive, hover
462
+
463
+
464
+ - `def CardTitle(*c, **kwargs)`
465
+ Creates a card title
466
+
467
+ - `def CardHeader(*c, **kwargs)`
468
+ Creates a card header
469
+
470
+ - `def CardBody(*c, **kwargs)`
471
+ Creates a card body
472
+
473
+ - `def CardFooter(*c, **kwargs)`
474
+ Creates a card footer
475
+
476
+ - `def CardContainer(*c, **kwargs)`
477
+ Creates a card container
478
+
479
+ - `def Card(*c, **kwargs)`
480
+ Creates a Card with a header, body, and footer
481
+
482
+ - `class TableT(Enum)`
483
+ Members: divider, striped, hover, sm, lg, justify, middle, responsive
484
+
485
+
486
+ - `def Table(*c, **kwargs)`
487
+ Creates a table
488
+
489
+ - `def TableFromLists(header_data, body_data, footer_data, header_cell_render, body_cell_render, footer_cell_render, cls, sortable, **kwargs)`
490
+ Creates a Table from a list of header data and a list of lists of body data
491
+
492
+ - `def TableFromDicts(header_data, body_data, footer_data, header_cell_render, body_cell_render, footer_cell_render, cls, sortable, **kwargs)`
493
+ Creates a Table from a list of header data and a list of dicts of body data
494
+
495
+ - `def apply_classes(html_str, class_map, class_map_mods)`
496
+ Apply classes to html string
497
+
498
+ - `class FrankenRenderer`
499
+ Custom renderer for Franken UI that handles image paths
500
+
501
+ - `def __init__(self, *args, **kwargs)`
502
+ - `def render_image(self, token)`
503
+ Modify image paths if they're relative and self.img_dir is specified
504
+
505
+
506
+ - `def render_md(md_content, class_map, class_map_mods, img_dir, renderer)`
507
+ Renders markdown using mistletoe and lxml with custom image handling
508
+
509
+ - `def ThemePicker(color, radii, shadows, font, mode, cls, custom_themes)`
510
+ Theme picker component with configurable sections
511
+
512
+ - `def LightboxContainer(*lightboxitem, **kwargs)`
513
+ Lightbox container that will hold `LightboxItems`
514
+
515
+ - `def LightboxItem(*c, **kwargs)`
516
+ Anchor tag with appropriate structure to go inside a `LightBoxContainer`
517
+
518
+ - `def ApexChart(**kws)`
519
+ Apex chart component
520
+ </doc></api reference><examples><doc title="Cards" desc="FrankenUI Cards Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Cards Example built with MonsterUI (original design by ShadCN)"""
521
+
522
+ from fasthtml.common import *
523
+ from fasthtml.components import Uk_input_tag
524
+ from fasthtml.svg import *
525
+ from monsterui.all import *
526
+ import calendar
527
+ from datetime import datetime
528
+
529
+ app, rt = fast_app(hdrs=Theme.blue.headers())
530
+
531
+ CreateAccount = Card(
532
+ Grid(Button(DivLAligned(UkIcon('github'),Div('Github'))),Button('Google')),
533
+ DividerSplit("OR CONTINUE WITH", text_cls=TextPresets.muted_sm),
534
+ LabelInput('Email', id='email', placeholder='[email protected]'),
535
+ LabelInput('Password', id='password',placeholder='Password', type='Password'),
536
+ header=(H3('Create an Account'),Subtitle('Enter your email below to create your account')),
537
+ footer=Button('Create Account',cls=(ButtonT.primary,'w-full')))
538
+
539
+ PaypalSVG_data = "M7.076 21.337H2.47a.641.641 0 0 1-.633-.74L4.944.901C5.026.382 5.474 0 5.998 0h7.46c2.57 0 4.578.543 5.69 1.81 1.01 1.15 1.304 2.42 1.012 4.287-.023.143-.047.288-.077.437-.983 5.05-4.349 6.797-8.647 6.797h-2.19c-.524 0-.968.382-1.05.9l-1.12 7.106zm14.146-14.42a3.35 3.35 0 0 0-.607-.541c-.013.076-.026.175-.041.254-.93 4.778-4.005 7.201-9.138 7.201h-2.19a.563.563 0 0 0-.556.479l-1.187 7.527h-.506l-.24 1.516a.56.56 0 0 0 .554.647h3.882c.46 0 .85-.334.922-.788.06-.26.76-4.852.816-5.09a.932.932 0 0 1 .923-.788h.58c3.76 0 6.705-1.528 7.565-5.946.36-1.847.174-3.388-.777-4.471z"
540
+ AppleSVG_data = "M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"
541
+ Card1Svg = Svg(viewBox="0 0 24 24", fill="none", stroke="currentColor", stroke_linecap="round", stroke_linejoin="round", stroke_width="2", cls="h-6 w-6 mr-1")(Rect(width="20", height="14", x="2", y="5", rx="2"),Path(d="M2 10h20"))
542
+ PaypalSvg = Svg(role="img", viewBox="0 0 24 24", cls="h-6 w-6 mr-1")(Path(d=PaypalSVG_data, fill="currentColor")),
543
+ AppleSvg = Svg(role="img", viewBox="0 0 24 24", cls="h-6 w-6 mr-1")(Path(d=AppleSVG_data, fill="currentColor"))
544
+
545
+ PaymentMethod = Card(
546
+ Grid(Button(DivCentered(Card1Svg, "Card"), cls='h-20 border-2 border-primary'),
547
+ Button(DivCentered(PaypalSvg, "PayPal"), cls='h-20'),
548
+ Button(DivCentered(AppleSvg, "Apple"), cls='h-20')),
549
+ Form(LabelInput('Name', id='name', placeholder='John Doe'),
550
+ LabelInput('Card Number', id='card_number', placeholder='[email protected]'),
551
+ Grid(LabelSelect(*Options(*calendar.month_name[1:],selected_idx=0),label='Expires',id='expire_month'),
552
+ LabelSelect(*Options(*range(2024,2030),selected_idx=0), label='Year', id='expire_year'),
553
+ LabelInput('CVV', id='cvv',placeholder='CVV', cls='mt-0'))),
554
+ header=(H3('Payment Method'),Subtitle('Add a new payment method to your account.')))
555
+
556
+ area_opts = ('Team','Billing','Account','Deployment','Support')
557
+ severity_opts = ('Severity 1 (Highest)', 'Severity 2', 'Severity 3', 'Severity 4 (Lowest)')
558
+ ReportIssue = Card(
559
+ Grid(Div(LabelSelect(*Options(*area_opts), label='Area', id='area')),
560
+ Div(LabelSelect(*Options(*severity_opts),label='Severity',id='area'))),
561
+ LabelInput( label='Subject', id='subject', placeholder='I need help with'),
562
+ LabelTextArea( label='Description', id='description',placeholder='Please include all information relevant to your issue'),
563
+ Div(FormLabel('Tags', fr='#tags'),
564
+ Uk_input_tag(name="Tags",state="danger", value="Spam,Invalid", uk_cloak=True, id='tags')),
565
+ header=(H3('Report Issue'),Subtitle('What area are you having problems with?')),
566
+ footer = DivFullySpaced(Button('Cancel'), Button(cls=ButtonT.primary)('Submit')))
567
+
568
+ monster_desc ="Python-first beautifully designed components because you deserve to focus on features that matter and your app deserves to be beautiful from day one."
569
+ MonsterUI = Card(H4("Monster UI"),
570
+ Subtitle(monster_desc),
571
+ DivLAligned(
572
+ Div("Python"),
573
+ DivLAligned(UkIcon('star'),Div("20k"), cls='space-x-1'),
574
+ Div(datetime.now().strftime("%B %d, %Y")),
575
+ cls=('space-x-4',TextPresets.muted_sm)))
576
+
577
+ def CookieTableRow(heading, description, active=False):
578
+ return Tr(Td(H5(heading)),
579
+ Td(P(description, cls=TextPresets.muted_sm)),
580
+ Td(Switch(checked=active)))
581
+
582
+ CookieSettings = Card(
583
+ Table(Tbody(
584
+ CookieTableRow('Strictly Necessary', 'These cookies are essential in order to use the website and use its features.', True),
585
+ CookieTableRow('Functional Cookies', 'These cookies allow the website to provide personalized functionality.'),
586
+ CookieTableRow('Performance Cookies', 'These cookies help to improve the performance of the website.'))),
587
+ header=(H4('Cookie Settings'),Subtitle('Manage your cookie settings here.')),
588
+ footer=Button('Save Preferences', cls=(ButtonT.primary, 'w-full')))
589
+
590
+ team_members = [("Sofia Davis", "[email protected]", "Owner"),("Jackson Lee", "[email protected]", "Member"),]
591
+ def TeamMemberRow(name, email, role):
592
+ return DivFullySpaced(
593
+ DivLAligned(
594
+ DiceBearAvatar(name, 10,10),
595
+ Div(P(name, cls=(TextT.sm, TextT.medium)),
596
+ P(email, cls=TextPresets.muted_sm))),
597
+ Button(role, UkIcon('chevron-down', cls='ml-4')),
598
+ DropDownNavContainer(map(NavCloseLi, [
599
+ A(Div('Viewer', NavSubtitle('Can view and comment.'))),
600
+ A(Div('Developer', NavSubtitle('Can view, comment and edit.'))),
601
+ A(Div('Billing', NavSubtitle('Can view, comment and manage billing.'))),
602
+ A(Div('Owner', NavSubtitle('Admin-level access to all resources.')))])))
603
+
604
+ TeamMembers = Card(*[TeamMemberRow(*member) for member in team_members],
605
+ header = (H4('Team Members'),Subtitle('Invite your team members to collaborate.')))
606
+
607
+ access_roles = ("Read and write access", "Read-only access")
608
+ team_members = [("Olivia Martin", "[email protected]", "Read and write access"),
609
+ ("Isabella Nguyen", "[email protected]", "Read-only access"),
610
+ ("Sofia Davis", "[email protected]", "Read-only access")]
611
+
612
+ def TeamMemberRow(name, email, role):
613
+ return DivFullySpaced(
614
+ DivLAligned(DiceBearAvatar(name, 10,10),
615
+ Div(P(name, cls=(TextT.sm, TextT.medium)),
616
+ P(email, cls=TextPresets.muted_sm))),
617
+ Select(*Options(*access_roles, selected_idx=access_roles.index(role))))
618
+
619
+ ShareDocument = Card(
620
+ DivLAligned(Input(value='http://example.com/link/to/document'),Button('Copy link', cls='whitespace-nowrap')),
621
+ Divider(),
622
+ H4('People with access', cls=TextPresets.bold_sm),
623
+ *[TeamMemberRow(*member) for member in team_members],
624
+ header = (H4('Share this document'),Subtitle('Anyone with the link can view this document.')))
625
+
626
+ DateCard = Card(Button('Jan 20, 2024 - Feb 09, 2024'))
627
+
628
+ section_content =(('bell','Everything',"Email digest, mentions & all activity."),
629
+ ('user',"Available","Only mentions and comments"),
630
+ ('ban', "Ignoring","Turn of all notifications"))
631
+
632
+ def NotificationRow(icon, name, desc):
633
+ return Li(cls='-mx-1')(A(DivLAligned(UkIcon(icon),Div(P(name),P(desc, cls=TextPresets.muted_sm)))))
634
+
635
+ Notifications = Card(
636
+ NavContainer(
637
+ *[NotificationRow(*row) for row in section_content],
638
+ cls=NavT.secondary),
639
+ header = (H4('Notification'),Subtitle('Choose what you want to be notified about.')),
640
+ body_cls='pt-0')
641
+
642
+ TeamCard = Card(
643
+ DivLAligned(
644
+ DiceBearAvatar("Isaac Flath", h=24, w=24),
645
+ Div(H3("Isaac Flath"), P("Library Creator"))),
646
+ footer=DivFullySpaced(
647
+ DivHStacked(UkIcon("map-pin", height=16), P("Alexandria, VA")),
648
+ DivHStacked(*(UkIconLink(icon, height=16) for icon in ("mail", "linkedin", "github")))),
649
+ cls=CardT.hover)
650
+
651
+ @rt
652
+ def index():
653
+ return Title("Cards Example"),Container(Grid(
654
+ *map(Div,(
655
+ Div(PaymentMethod,CreateAccount, TeamCard, cls='space-y-4'),
656
+ Div(TeamMembers, ShareDocument,DateCard,Notifications, cls='space-y-4'),
657
+ Div(ReportIssue,MonsterUI,CookieSettings, cls='space-y-4'))),
658
+ cols_md=1, cols_lg=2, cols_xl=3))
659
+
660
+ serve()</doc><doc title="Dashboard" desc="FrankenUI Dashboard Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Dashboard Example built with MonsterUI (original design by ShadCN)"""
661
+
662
+ from fasthtml.common import * # Bring in all of fasthtml
663
+ import fasthtml.common as fh # Used to get unstyled components
664
+ from monsterui.all import * # Bring in all of monsterui, including shadowing fasthtml components with styled components
665
+ from fasthtml.svg import *
666
+ import numpy as np
667
+ import plotly.express as px
668
+ import pandas as pd
669
+ import numpy as np
670
+
671
+ app, rt = fast_app(hdrs=Theme.blue.headers())
672
+
673
+ def generate_chart(num_points=30):
674
+ df = pd.DataFrame({
675
+ 'Date': pd.date_range('2024-01-01', periods=num_points),
676
+ 'Revenue': np.random.normal(100, 10, num_points).cumsum(),
677
+ 'Users': np.random.normal(80, 8, num_points).cumsum(),
678
+ 'Growth': np.random.normal(60, 6, num_points).cumsum()})
679
+
680
+ fig = px.line(df, x='Date', y=['Revenue', 'Users', 'Growth'], template='plotly_white', line_shape='spline')
681
+
682
+ fig.update_traces(mode='lines+markers')
683
+ fig.update_layout(
684
+ margin=dict(l=20, r=20, t=20, b=20), hovermode='x unified',
685
+ showlegend=True, legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1),
686
+ plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)',
687
+ xaxis=dict(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)'),
688
+ yaxis=dict(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)'))
689
+
690
+ return fig.to_html(include_plotlyjs=True, full_html=False, config={'displayModeBar': False})
691
+
692
+ def InfoCard(title, value, change): return Card(H3(value),P(change, cls=TextPresets.muted_sm), header = H4(title))
693
+
694
+ rev = InfoCard("Total Revenue", "$45,231.89", "+20.1% from last month")
695
+ sub = InfoCard("Subscriptions", "+2350", "+180.1% from last month")
696
+ sal = InfoCard("Sales", "+12,234", "+19% from last month")
697
+ act = InfoCard("Active Now", "+573", "+201 since last hour")
698
+
699
+ info_card_data = [("Total Revenue", "$45,231.89", "+20.1% from last month"),
700
+ ("Subscriptions", "+2350", "+180.1% from last month"),
701
+ ("Sales", "+12,234", "+19% from last month"),
702
+ ("Active Now", "+573", "+201 since last hour")]
703
+
704
+ top_info_row = Grid(*[InfoCard(*row) for row in info_card_data])
705
+
706
+ def AvatarItem(name, email, amount):
707
+ return DivFullySpaced(
708
+ DivLAligned(
709
+ DiceBearAvatar(name, 9,9),
710
+ Div(Strong(name, cls=TextT.sm),
711
+ Address(A(email,href=f'mailto:{email}')))),
712
+ fh.Data(amount, cls="ml-auto font-medium", value=amount[2:]))
713
+
714
+ recent_sales = Card(
715
+ Div(cls="space-y-8")(
716
+ *[AvatarItem(n,e,d) for (n,e,d) in (
717
+ ("Olivia Martin", "[email protected]", "+$1,999.00"),
718
+ ("Jackson Lee", "[email protected]", "+$39.00"),
719
+ ("Isabella Nguyen", "[email protected]", "+$299.00"),
720
+ ("William Kim", "[email protected]", "+$99.00"),
721
+ ("Sofia Davis", "[email protected]", "+$39.00"))]),
722
+ header=Div(H3("Recent Sales"),Subtitle("You made 265 sales this month.")),
723
+ cls='col-span-3')
724
+
725
+ teams = [["Alicia Koch"],['Acme Inc', 'Monster Inc.'],['Create a Team']]
726
+
727
+ opt_hdrs = ["Personal", "Team", ""]
728
+
729
+ team_dropdown = Select(
730
+ Optgroup(Option(A("Alicia Koch")), label="Personal Account"),
731
+ Optgroup(Option(A("Acme Inc")), Option(A("Monster Inc.")), label="Teams"),
732
+ Option(A("Create a Team")),
733
+ cls='flex items-center')
734
+
735
+ hotkeys = [('Profile','⇧⌘P'),('Billing','⌘B'),('Settings','⌘S'),('New Team', ''), ('Logout', '')]
736
+
737
+ def NavSpacedLi(t,s): return NavCloseLi(A(DivFullySpaced(P(t),P(s,cls=TextPresets.muted_sm))))
738
+
739
+ avatar_dropdown = Div(
740
+ DiceBearAvatar('Alicia Koch',8,8),
741
+ DropDownNavContainer(
742
+ NavHeaderLi('sveltecult',NavSubtitle("[email protected]")),
743
+ *[NavSpacedLi(*hk) for hk in hotkeys],))
744
+
745
+ top_nav = NavBar(
746
+ team_dropdown, *map(A, ["Overview", "Customers", "Products", "Settings"]),
747
+ brand=DivLAligned(avatar_dropdown, Input(placeholder='Search')))
748
+
749
+ @rt
750
+ def index():
751
+ return Title("Dashboard Example"), Container(
752
+ top_nav,
753
+ H2('Dashboard'),
754
+ TabContainer(
755
+ Li(A("Overview"),cls='uk-active'),
756
+ *map(lambda x: Li(A(x)), ["Analytics", "Reports", "Notifications"]),
757
+ alt=True),
758
+ top_info_row,
759
+ Grid(
760
+ Card(Safe(generate_chart(100)), cls='col-span-4'),
761
+ recent_sales,
762
+ gap=4,cols_xl=7,cols_lg=7,cols_md=1,cols_sm=1,cols_xs=1),
763
+ cls=('space-y-4', ContainerT.xl))
764
+
765
+ serve()</doc><doc title="Forms" desc="FrankenUI Forms Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Forms Example built with MonsterUI (original design by ShadCN)"""
766
+
767
+
768
+ from fasthtml.common import *
769
+ from monsterui.all import *
770
+ from fasthtml.svg import *
771
+
772
+ app, rt = fast_app(hdrs=Theme.blue.headers())
773
+
774
+ def HelpText(c): return P(c,cls=TextPresets.muted_sm)
775
+
776
+ def heading():
777
+ return Div(cls="space-y-5")(
778
+ H2("Settings"),
779
+ Subtitle("Manage your account settings and set e-mail preferences."),
780
+ DividerSplit())
781
+
782
+
783
+ sidebar = NavContainer(
784
+ *map(lambda x: Li(A(x)), ("Profile", "Account", "Appearance", "Notifications", "Display")),
785
+ uk_switcher="connect: #component-nav; animation: uk-animation-fade",
786
+ cls=(NavT.secondary,"space-y-4 p-4 w-1/5"))
787
+
788
+
789
+ def FormSectionDiv(*c, cls='space-y-2', **kwargs): return Div(*c, cls=cls, **kwargs)
790
+
791
+ def FormLayout(title, subtitle, *content, cls='space-y-3 mt-4'): return Container(Div(H3(title), Subtitle(subtitle), DividerLine(), Form(*content, cls=cls)))
792
+
793
+ def profile_form():
794
+ content = (FormSectionDiv(
795
+ LabelInput("Username", placeholder='sveltecult', id='username'),
796
+ HelpText("This is your public display name. It can be your real name or a pseudonym. You can only change this once every 30 days.")),
797
+ FormSectionDiv(
798
+ LabelSelect(
799
+ Option("Select a verified email to display", value="", selected=True, disabled=True),
800
+ *[Option(o, value=o) for o in ('[email protected]', '[email protected]', '[email protected]')],
801
+ label="Email", id="email"),
802
+ HelpText("You can manage verified email addresses in your email settings.")),
803
+ FormSectionDiv(
804
+ LabelTextArea("Bio", id="bio", placeholder="Tell us a little bit about yourself"),
805
+ HelpText("You can @mention other users and organizations to link to them."),
806
+ P("String must contain at least 4 character(s)", cls="text-destructive")),
807
+ FormSectionDiv(
808
+ FormLabel("URLs"),
809
+ HelpText("Add links to your website, blog, or social media profiles."),
810
+ Input(value="https://www.franken-ui.dev"),
811
+ Input(value="https://github.com/sveltecult/franken-ui"),
812
+ Button("Add URL")),
813
+ Button('Update profile', cls=ButtonT.primary))
814
+
815
+ return FormLayout('Profile', 'This is how others will see you on the site.', *content)
816
+
817
+ def account_form():
818
+ content = (
819
+ FormSectionDiv(
820
+ LabelInput("Name", placeholder="Your name", id="name"),
821
+ HelpText("This is the name that will be displayed on your profile and in emails.")),
822
+ FormSectionDiv(
823
+ LabelInput("Date of Birth", type="date", placeholder="Pick a date", id="date_of_birth"),
824
+ HelpText("Your date of birth is used to calculate your age.")),
825
+ FormSectionDiv(
826
+ LabelSelect(*Options("Select a language", "English", "French", "German", "Spanish", "Portuguese", selected_idx=1, disabled_idxs={0}),
827
+ label='Language', id="language"),
828
+ HelpText("This is the language that will be used in the dashboard.")),
829
+ Button('Update profile', cls=ButtonT.primary))
830
+
831
+ return FormLayout('Account', 'Update your account settings. Set your preferred language and timezone.', *content)
832
+
833
+ def appearance_form():
834
+ def theme_item(bg_color, content_bg, text_bg):
835
+ common_content = f"space-y-2 rounded-md {content_bg} p-2 shadow-sm"
836
+ item_row = lambda: Div(cls=f"flex items-center space-x-2 {common_content}")(
837
+ Div(cls=f"h-4 w-4 rounded-full {text_bg}"),
838
+ Div(cls=f"h-2 w-[100px] rounded-lg {text_bg}"))
839
+
840
+ return Div(cls=f"space-y-2 rounded-sm {bg_color} p-2")(
841
+ Div(cls=common_content)(
842
+ Div(cls=f"h-2 w-[80px] rounded-lg {text_bg}"),
843
+ Div(cls=f"h-2 w-[100px] rounded-lg {text_bg}")),
844
+ item_row(),
845
+ item_row())
846
+
847
+ common_toggle_cls = "block cursor-pointer items-center rounded-md border-2 border-muted p-1 ring-ring"
848
+
849
+ content = (
850
+ FormSectionDiv(
851
+ LabelSelect(*Options('Select a font family', 'Inter', 'Geist', 'Open Sans', selected_idx=2, disabled_idxs={0}),
852
+ label='Font Family', id='font_family'),
853
+ HelpText("Set the font you want to use in the dashboard.")),
854
+ FormSectionDiv(
855
+ FormLabel("Theme"),
856
+ HelpText("Select the theme for the dashboard."),
857
+ Grid(
858
+ A(id="theme-toggle-light", cls=common_toggle_cls)(theme_item("bg-[#ecedef]", "bg-white", "bg-[#ecedef]")),
859
+ A(id="theme-toggle-dark", cls=f"{common_toggle_cls} bg-popover")(theme_item("bg-slate-950", "bg-slate-800", "bg-slate-400")),
860
+ cols_max=2,cls=('max-w-md','gap-8'))),
861
+ Button('Update preferences', cls=ButtonT.primary))
862
+
863
+ return FormLayout('Appearance', 'Customize the appearance of the app. Automatically switch between day and night themes.', *content)
864
+
865
+
866
+ notification_items = [
867
+ {"title": "Communication emails", "description": "Receive emails about your account activity.", "checked": False, "disabled": False},
868
+ {"title": "Marketing emails", "description": "Receive emails about new products, features, and more.", "checked": False, "disabled": False},
869
+ {"title": "Social emails", "description": "Receive emails for friend requests, follows, and more.", "checked": True, "disabled": False},
870
+ {"title": "Security emails", "description": "Receive emails about your account activity and security.", "checked": True, "disabled": True}]
871
+
872
+ def notifications_form():
873
+ def RadioLabel(label): return DivLAligned(Radio(name="notification", checked=(label=="Nothing")), FormLabel(label))
874
+
875
+ def NotificationCard(item):
876
+ return Card(
877
+ Div(cls="space-y-0.5")(
878
+ FormLabel(Strong(item['title'], cls=TextT.sm),
879
+ HelpText(item['description']))))
880
+ content = Div(
881
+ FormSectionDiv(
882
+ FormLabel("Notify me about"),
883
+ *map(RadioLabel, ["All new messages", "Direct messages and mentions", "Nothing"])),
884
+ Div(
885
+ H4("Email Notifications", cls="mb-4"),
886
+ Grid(*map(NotificationCard, notification_items), cols=1)),
887
+ LabelCheckboxX("Use different settings for my mobile devices", id="notification_mobile"),
888
+ HelpText("You can manage your mobile notifications in the mobile settings page."),
889
+ Button('Update notifications', cls=ButtonT.primary))
890
+
891
+ return FormLayout('Notifications', 'Configure how you receive notifications.', *content)
892
+
893
+ def display_form():
894
+ content = (
895
+ Div(cls="space-y-2")(
896
+ Div(cls="mb-4")(
897
+ H5("Sidebar"),
898
+ Subtitle("Select the items you want to display in the sidebar.")),
899
+ *[Div(CheckboxX(id=f"display_{i}", checked=i in [0, 1, 2]),FormLabel(label))
900
+ for i, label in enumerate(["Recents", "Home", "Applications", "Desktop", "Downloads", "Documents"])]),
901
+ Button('Update display', cls=ButtonT.primary))
902
+ return FormLayout('Display', 'Turn items on or off to control what\'s displayed in the app.', *content)
903
+
904
+ @rt
905
+ def index():
906
+ return Title("Forms Example"),Container(
907
+ heading(),
908
+ Div(cls="flex gap-x-12")(
909
+ sidebar,
910
+ Ul(id="component-nav", cls="uk-switcher max-w-2xl")(
911
+ Li(cls="uk-active")(profile_form(),
912
+ *map(Li, [account_form(), appearance_form(), notifications_form(), display_form()])))))
913
+
914
+ serve()</doc><doc title="Scrollspy" desc="MonsterUI Scrollspy Example application">"MonsterUI Scrollspy Example application"
915
+
916
+ from fasthtml.common import *
917
+ from monsterui.all import *
918
+ import random
919
+
920
+ # Using the "slate" theme with Highlight.js enabled
921
+ hdrs = Theme.slate.headers(highlightjs=True)
922
+ app, rt = fast_app(hdrs=hdrs)
923
+
924
+ ################################
925
+ ### Example Data and Content ###
926
+ ################################
927
+ products = [
928
+ {"name": "Laptop", "price": "$999"},
929
+ {"name": "Smartphone", "price": "$599"}
930
+ ]
931
+
932
+ code_example = """
933
+ # Python Code Example
934
+ def greet(name):
935
+ return f"Hello, {name}!"
936
+
937
+ print(greet("World"))
938
+ """
939
+ testimonials = [
940
+ {"name": "Alice", "feedback": "Great products and excellent customer service!"},
941
+ {"name": "Bob", "feedback": "Fast shipping and amazing quality!"},
942
+ {"name": "Charlie", "feedback": "Amazing experience! Will definitely buy again."},
943
+ {"name": "Diana", "feedback": "Affordable prices and great variety!"},
944
+ {"name": "Edward", "feedback": "Customer support was very helpful."},
945
+ {"name": "Fiona", "feedback": "Loved the design and quality!"}
946
+ ]
947
+
948
+ # Team members
949
+ team = [
950
+ {"name": "Isaac Flath", "role": "CEO"},
951
+ {"name": "Benjamin Clavié", "role": "AI Researcher"},
952
+ {"name": "Alexis Gallagher", "role": "ML Engineer"},
953
+ {"name": "Hamel Husain", "role": "Data Scientist"},
954
+ {"name": "Austin Huang", "role": "Software Engineer"},
955
+ {"name": "Benjamin Warner", "role": "Product Manager"},
956
+ {"name": "Jonathan Whitaker", "role": "UX Designer"},
957
+ {"name": "Kerem Turgutlu", "role": "DevOps Engineer"},
958
+ {"name": "Curtis Allan", "role": "DevOps Engineer"},
959
+ {"name": "Audrey Roy Greenfeld", "role": "Security Analyst"},
960
+ {"name": "Nathan Cooper", "role": "Full Stack Developer"},
961
+ {"name": "Jeremy Howard", "role": "CTO"},
962
+ {"name": "Wayde Gilliam", "role": "Cloud Architect"},
963
+ {"name": "Daniel Roy Greenfeld", "role": "Blockchain Expert"},
964
+ {"name": "Tommy Collins", "role": "AI Ethics Researcher"}
965
+ ]
966
+
967
+
968
+ def ProductCard(p,img_id=1):
969
+ return Card(
970
+ PicSumImg(w=500, height=100, id=img_id),
971
+ DivFullySpaced(H4(p["name"]), P(Strong(p["price"], cls=TextT.sm))),
972
+ Button("Details", cls=(ButtonT.primary, "w-full")))
973
+
974
+ def TestimonialCard(t,img_id=1):
975
+ return Card(
976
+ DivLAligned(PicSumImg(w=50, h=50, cls='rounded-full', id=img_id), H4(t["name"])),
977
+ P(Q((t["feedback"]))))
978
+
979
+
980
+ def TeamCard(m,img_id=1):
981
+ return Card(
982
+ DivLAligned(
983
+ PicSumImg(w=50, h=50, cls='rounded-full', id=img_id),
984
+ Div(H4(m["name"]), P(m["role"]))),
985
+ DivRAligned(
986
+ UkIcon('twitter', cls='w-5 h-5'),
987
+ UkIcon('linkedin', cls='w-5 h-5'),
988
+ UkIcon('github', cls='w-5 h-5'),
989
+ cls=TextT.gray+'space-x-2'
990
+ ),
991
+ cls='p-3')
992
+
993
+ ################################
994
+ ### Navigation and Scrollspy ###
995
+ ################################
996
+
997
+ scrollspy_links = (
998
+ A("Welcome", href="#welcome-section"),
999
+ A("Products", href="#products-section"),
1000
+ A("Testimonials", href="#testimonials-section"),
1001
+ A("Team", href="#team-section"),
1002
+ A("Code Example", href="#code-section"))
1003
+ @rt
1004
+ def index():
1005
+ def _Section(*c, **kwargs): return Section(*c, cls='space-y-3 my-48',**kwargs)
1006
+ return Container(
1007
+ NavBar(
1008
+ *scrollspy_links,
1009
+ brand=DivLAligned(H3("Scrollspy Demo!"),UkIcon('rocket',height=30,width=30)),
1010
+ sticky=True, uk_scrollspy_nav=True,
1011
+ scrollspy_cls=ScrollspyT.bold),
1012
+ NavContainer(
1013
+ *map(Li, scrollspy_links),
1014
+ uk_scrollspy_nav=True,
1015
+ sticky=True,
1016
+ cls=(NavT.primary,'pt-20 px-5 pr-10')),
1017
+ Container(
1018
+ # Notice the ID of each section corresponds to the `scrollspy_links` dictionary
1019
+ # So in scollspy `NavContainer` the `href` of each `Li` is the ID of the section
1020
+ DivCentered(
1021
+ H1("Welcome to the Store!"),
1022
+ Subtitle("Explore our products and enjoy dynamic code examples."),
1023
+ id="welcome-section"),
1024
+ _Section(H2("Products"),
1025
+ Grid(*[ProductCard(p,img_id=i) for i,p in enumerate(products)], cols_lg=2),
1026
+ id="products-section"),
1027
+ _Section(H2("Testimonials"),
1028
+ Slider(*[TestimonialCard(t,img_id=i) for i,t in enumerate(testimonials)]),
1029
+ id="testimonials-section"),
1030
+ _Section(H2("Our Team"),
1031
+ Grid(*[TeamCard(m,img_id=i) for i,m in enumerate(team)], cols_lg=2, cols_max=3),
1032
+ id="team-section"),
1033
+ _Section(H2("Code Example"),
1034
+ CodeBlock(code_example, lang="python"),
1035
+ id="code-section")),
1036
+ cls=(ContainerT.xl,'uk-container-expand'))
1037
+
1038
+ serve()</doc><doc title="Ticket" desc="MonsterUI Help Desk Example - Professional Dashboard with DaisyUI components">"""MonsterUI Help Desk Example - Professional Dashboard with DaisyUI components"""
1039
+ from fasthtml.common import *
1040
+ from monsterui.all import *
1041
+ from datetime import datetime
1042
+
1043
+ app, rt = fast_app(hdrs=Theme.blue.headers(daisy=True))
1044
+
1045
+ def TicketSteps(step):
1046
+ return Steps(
1047
+ LiStep("Submitted", data_content="📝",
1048
+ cls=StepT.success if step > 0 else StepT.primary if step == 0 else StepT.neutral),
1049
+ LiStep("In Review", data_content="🔎",
1050
+ cls=StepT.success if step > 1 else StepT.primary if step == 1 else StepT.neutral),
1051
+ LiStep("Processing", data_content="⚙️",
1052
+ cls=StepT.success if step > 2 else StepT.primary if step == 2 else StepT.neutral),
1053
+ LiStep("Resolved", data_content="✅",
1054
+ cls=StepT.success if step > 3 else StepT.primary if step == 3 else StepT.neutral),
1055
+ cls="w-full")
1056
+
1057
+ def StatusBadge(status):
1058
+ styles = {'high': AlertT.error, 'medium': AlertT.warning,'low': AlertT.info}
1059
+ alert_type = styles.get(status, AlertT.info)
1060
+ return Alert(f"{status.title()} Priority", cls=(alert_type,"w-32 shadow-sm"))
1061
+
1062
+ def TicketCard(id, title, description, status, step, department):
1063
+ return Card(
1064
+ CardHeader(
1065
+ DivFullySpaced(
1066
+ Div(H3(f"#{id}", cls=TextT.muted),
1067
+ H4(title),
1068
+ cls='space-y-2'),
1069
+ StatusBadge(status))),
1070
+ CardBody(
1071
+ P(description, cls=(TextT.muted, "mb-6")),
1072
+ DividerSplit(cls="my-6"),
1073
+ TicketSteps(step),
1074
+ DividerSplit(cls="my-6"),
1075
+ DivFullySpaced(
1076
+ Div(Strong("Department"),
1077
+ P(department),
1078
+ cls=('space-y-3', TextPresets.muted_sm)),
1079
+ Div(Strong("Last Updated"),
1080
+ P(Time(datetime.now().strftime('%b %d, %H:%M'))),
1081
+ cls=('space-y-3', TextPresets.muted_sm)),
1082
+ Button("View Details", cls=ButtonT.primary),
1083
+ cls='mt-6')),
1084
+ cls=CardT.hover)
1085
+
1086
+ def NewTicketModal():
1087
+ return Modal(
1088
+ ModalHeader(H3("Create New Support Ticket")),
1089
+ ModalBody(
1090
+ Alert(
1091
+ DivLAligned(UkIcon("info"), Span("Please provide as much detail as possible to help us assist you quickly.")),
1092
+ cls=(AlertT.info,"mb-4")),
1093
+ Form(
1094
+ Grid(LabelInput("Title", id="title", placeholder="Brief description of your issue"),
1095
+ LabelSelect(Options("IT Support", "HR", "Facilities", "Finance"), label="Department", id="department")),
1096
+ LabelSelect(Options("Low", "Medium", "High"), label="Priority Level", id="priority"),
1097
+ LabelTextArea("Description", id="description", placeholder="Please provide detailed information about your issue"),
1098
+ DivRAligned(
1099
+ Button("Cancel", cls=ButtonT.ghost, data_uk_toggle="target: #new-ticket"),
1100
+ Button(Loading(cls=LoadingT.spinner), "Submit Ticket", cls=ButtonT.primary, data_uk_toggle="target: #success-toast; target: #new-ticket")),
1101
+ cls='space-y-8')),
1102
+ id="new-ticket")
1103
+
1104
+ @rt
1105
+ def index():
1106
+ tickets = [
1107
+ {'id': "TK-1001", 'title': "Cloud Storage Access Error",
1108
+ 'description': "Unable to access cloud storage with persistent authorization errors. Multiple users affected across marketing department.",
1109
+ 'status': 'high', 'step': 2, 'department': 'IT Support'},
1110
+ {'id': "TK-1002", 'title': "Email Integration Issue",
1111
+ 'description': "Exchange server not syncing with mobile devices. Affecting external client communications.",
1112
+ 'status': 'medium', 'step': 1, 'department': 'IT Support'},
1113
+ {'id': "TK-1003", 'title': "Office Equipment Setup",
1114
+ 'description': "New department printer needs configuration and network integration. Required for upcoming client presentation.",
1115
+ 'status': 'low', 'step': 0, 'department': 'Facilities'}
1116
+ ]
1117
+
1118
+ return Title("Help Desk Dashboard"), Container(
1119
+ Section(
1120
+ DivFullySpaced(
1121
+ H2("Active Tickets"),
1122
+ Button(UkIcon("plus-circle", cls="mr-2"), "New Ticket", cls=ButtonT.primary, data_uk_toggle="target: #new-ticket"),
1123
+ cls='mb-8'),
1124
+ Grid(*[TicketCard(**ticket) for ticket in tickets], cols=1),
1125
+ cls="my-6"),
1126
+ NewTicketModal(),
1127
+ Toast(DivLAligned(UkIcon('check-circle', cls='mr-2'), "Ticket submitted successfully! Our team will review it shortly."), id="success-toast", alert_cls=AlertT.success, cls=(ToastHT.end, ToastVT.bottom)),
1128
+ Loading(htmx_indicator=True, type=LoadingT.dots, cls="fixed top-0 right-0 m-4"),
1129
+ cls="mx-auto max-w-7xl"
1130
+ )
1131
+
1132
+ serve()</doc><doc title="Playground" desc="FrankenUI Playground Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Playground Example built with MonsterUI (original design by ShadCN)"""
1133
+
1134
+ from fasthtml.common import *
1135
+ from monsterui.all import *
1136
+ from fasthtml.svg import *
1137
+
1138
+ app, rt = fast_app(hdrs=Theme.blue.headers())
1139
+
1140
+ preset_options = ["Grammatical Standard English", "Summarize for a 2nd grader",
1141
+ "Text to command","Q&A","English to other languages","Parse unstructured data",
1142
+ "Classification","Natural language to Python","Explain code","Chat","More examples"]
1143
+
1144
+ def playground_navbar():
1145
+ save_modal = Modal(
1146
+ ModalTitle("Save preset"),
1147
+ P("This will save the current playground state as a preset which you can access later or share with others.",cls=("mt-1.5", TextPresets.muted_sm)),
1148
+ LabelInput("Name", id="name"),
1149
+ LabelInput("Description", id="description"),
1150
+ ModalCloseButton("Save", cls=ButtonT.primary),
1151
+ id="save")
1152
+
1153
+ share_dd = Div(cls="space-y-6 p-4")(
1154
+ H3("Share preset"),
1155
+ P("Anyone who has this link and an OpenAI account will be able to view this.", cls=TextPresets.muted_sm),
1156
+ Div(Input(value="https://platform.openai.com/playground/p/7bbKYQvsVkNmVb8NGcdUOLae?model=text-davinci-003", readonly=True),
1157
+ Button(UkIcon('copy'), cls=(ButtonT.primary, "uk-drop-close",'mt-4'))))
1158
+
1159
+ rnav = (
1160
+ Select(*Options(*preset_options), name='preset', optgroup_label="Examples",
1161
+ placeholder='Load a preset', searchable=True, cls='h-9 w-[200px] lg:w-[300px]'),
1162
+ Button("Save", cls=ButtonT.secondary, data_uk_toggle="#save"),save_modal,
1163
+ Button("View Code", cls=ButtonT.secondary),
1164
+ Button("Share", cls=ButtonT.secondary),DropDownNavContainer(share_dd),
1165
+ Button(UkIcon(icon="ellipsis"), cls=ButtonT.secondary),
1166
+ DropDownNavContainer(
1167
+ Li(A("Content filter preferences")),
1168
+ NavDividerLi(),
1169
+ Li(A("Delete preset", cls="text-destructive")),
1170
+ uk_dropdown="mode: click"))
1171
+
1172
+ return NavBar(*rnav, brand=H4('Playground'))
1173
+
1174
+ rsidebar = NavContainer(
1175
+ Select(
1176
+ Optgroup(map(Option,("text-davinci-003", "text-curie-001", "text-babbage-001", "text-ada-001")),label='GPT-3'),
1177
+ Optgroup(map(Option,("code-davinci-002", "code-cushman-001")),label='Codex'),
1178
+ label="Model",
1179
+ searchable=True),
1180
+ LabelRange(label='Temperature', value='12'),
1181
+ LabelRange(label='Maximum Length', value='80'),
1182
+ LabelRange(label='Top P', value='40'),
1183
+ cls='space-y-6 mt-8')
1184
+
1185
+ @rt
1186
+ def index():
1187
+ navbar = playground_navbar()
1188
+ main_content = Div(
1189
+ Div(cls="flex-1")(
1190
+ Textarea(cls="uk-textarea h-full p-4", placeholder="Write a tagline for an ice cream shop")),
1191
+ cls="flex h-[700px] p-8 w-4/5")
1192
+
1193
+ bottom_buttons = Div(
1194
+ Button("Submit", cls=ButtonT.primary),
1195
+ Button(UkIcon(icon="history"), cls=ButtonT.secondary),
1196
+ cls="flex gap-x-2")
1197
+
1198
+ return Title("Playground Example"),Div(navbar, Div(cls="flex w-full")(main_content, rsidebar), bottom_buttons)
1199
+
1200
+ serve()</doc><doc title="Mail" desc="FrankenUI Mail Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Mail Example built with MonsterUI (original design by ShadCN)"""
1201
+
1202
+ from fasthtml.common import *
1203
+ from monsterui.all import *
1204
+ from fasthtml.svg import *
1205
+ import pathlib, json
1206
+ from datetime import datetime
1207
+
1208
+ app, rt = fast_app(hdrs=Theme.blue.headers())
1209
+
1210
+ sidebar_group1 = (('home', 'Inbox', '128'), ('file-text', 'Drafts', '9'), (' arrow-up-right', 'Sent', ''),
1211
+ ('ban', 'Junk', '23'), ('trash', 'Trash', ''), ('folder', 'Archive', ''))
1212
+
1213
+ sidebar_group2 = (('globe','Social','972'),('info','Updates','342'),('messages-square','Forums','128'),
1214
+ ('shopping-cart','Shopping','8'),('shopping-bag','Promotions','21'),)
1215
+
1216
+ def MailSbLi(icon, title, cnt):
1217
+ return Li(A(DivLAligned(Span(UkIcon(icon)),Span(title),P(cnt, cls=TextPresets.muted_sm)),href='#', cls='hover:bg-secondary p-4'))
1218
+
1219
+ sidebar = NavContainer(
1220
+ NavHeaderLi(H3("Email"), cls='p-3'),
1221
+ Li(Select(map(Option, ('[email protected]','[email protected]', '[email protected]')))),
1222
+ *[MailSbLi(i, t, c) for i, t, c in sidebar_group1],
1223
+ Li(Hr()),
1224
+ *[MailSbLi(i, t, c) for i, t, c in sidebar_group2],
1225
+ cls='mt-3')
1226
+
1227
+ mail_data = json.load(open(pathlib.Path('data_/mail.json')))
1228
+
1229
+ def format_date(date_str):
1230
+ date_obj = datetime.fromisoformat(date_str)
1231
+ return date_obj.strftime("%Y-%m-%d %I:%M %p")
1232
+
1233
+ def MailItem(mail):
1234
+ cls_base = 'relative rounded-lg border border-border p-3 text-sm hover:bg-secondary space-y-2'
1235
+ cls = f"{cls_base} {'bg-muted' if mail == mail_data[0] else ''} {'tag-unread' if not mail['read'] else 'tag-mail'}"
1236
+
1237
+ return Li(
1238
+ DivFullySpaced(
1239
+ DivLAligned(
1240
+ Strong(mail['name']),
1241
+ Span(cls='flex h-2 w-2 rounded-full bg-blue-600') if not mail['read'] else ''),
1242
+ Time(format_date(mail['date']), cls='text-xs')),
1243
+ Small(mail['subject'], href=f"#mail-{mail['id']}"),
1244
+ Div(mail['text'][:100] + '...', cls=TextPresets.muted_sm),
1245
+ DivLAligned(
1246
+ *[Label(A(label, href='#'), cls='uk-label-primary' if label == 'work' else '') for label in mail['labels']]),
1247
+ cls=cls)
1248
+
1249
+ def MailList(mails): return Ul(cls='js-filter space-y-2 p-4 pt-0')(*[MailItem(mail) for mail in mails])
1250
+
1251
+ def MailContent():
1252
+ return Div(cls='flex flex-col',uk_filter="target: .js-filter")(
1253
+ Div(cls='flex px-4 py-2 ')(
1254
+ H3('Inbox'),
1255
+ TabContainer(Li(A("All Mail",href='#', role='button'),cls='uk-active', uk_filter_control="filter: .tag-mail"),
1256
+ Li(A("Unread",href='#', role='button'), uk_filter_control="filter: .tag-unread"),
1257
+ alt=True, cls='ml-auto max-w-40', )),
1258
+ Div(cls='flex flex-1 flex-col')(
1259
+ Div(cls='p-4')(
1260
+ Div(cls='uk-inline w-full')(
1261
+ Span(cls='uk-form-icon text-muted-foreground')(UkIcon('search')),
1262
+ Input(placeholder='Search'))),
1263
+ Div(cls='flex-1 overflow-y-auto max-h-[600px]')(MailList(mail_data))))
1264
+
1265
+ def IconNavItem(*d): return [Li(A(UkIcon(o[0],uk_tooltip=o[1]))) for o in d]
1266
+ def IconNav(*c,cls=''): return Ul(cls=f'uk-iconnav {cls}')(*c)
1267
+
1268
+ def MailDetailView(mail):
1269
+ top_icons = [('folder','Archive'), ('ban','Move to junk'), ('trash','Move to trash')]
1270
+ reply_icons = [('reply','Reply'), ('reply','Reply all'), ('forward','Forward')]
1271
+ dropdown_items = ['Mark as unread', 'Star read', 'Add Label', 'Mute Thread']
1272
+
1273
+ return Container(
1274
+ DivFullySpaced(
1275
+ DivLAligned(
1276
+ DivLAligned(*[UkIcon(o[0],uk_tooltip=o[1]) for o in top_icons]),
1277
+ Div(UkIcon('clock', uk_tooltip='Snooze'), cls='pl-2'),
1278
+ cls='space-x-2 divide-x divide-border'),
1279
+ DivLAligned(
1280
+ *[UkIcon(o[0],uk_tooltip=o[1]) for o in reply_icons],
1281
+ Div(UkIcon('ellipsis-vertical',button=True)),
1282
+ DropDownNavContainer(*map(lambda x: Li(A(x)), dropdown_items)))),
1283
+ DivLAligned(
1284
+ Span(mail['name'][:2], cls='flex h-10 w-10 items-center justify-center rounded-full bg-muted'),
1285
+ Div(Strong(mail['name']),
1286
+ Div(mail['subject']),
1287
+ DivLAligned(P('Reply-To:'), A(mail['email'], href=f"mailto:{mail['email']}"), cls='space-x-1'),
1288
+ P(Time(format_date(mail['date']))),
1289
+ cls='space-y-1'+TextT.sm),
1290
+ cls='m-4 space-x-4'),
1291
+ DividerLine(),
1292
+ P(mail['text'], cls=TextT.sm +'p-4'),
1293
+ DividerLine(),
1294
+ Div(TextArea(id='message', placeholder=f"Reply {mail['name']}"),
1295
+ DivFullySpaced(
1296
+ LabelSwitch('Mute this thread',id='mute'),
1297
+ Button('Send', cls=ButtonT.primary)),
1298
+ cls='space-y-4'))
1299
+
1300
+ @rt
1301
+ def index():
1302
+ return Title("Mail Example"),Container(
1303
+ Grid(Div(sidebar, cls='col-span-1'),
1304
+ Div(MailContent(), cls='col-span-2'),
1305
+ Div(MailDetailView(mail_data[0]), cls='col-span-2'),
1306
+ cols_sm=1, cols_md=1, cols_lg=5, cols_xl=5,
1307
+ gap=0, cls='flex-1'),
1308
+ cls=('flex', ContainerT.xl))
1309
+
1310
+ serve()</doc><doc title="Tasks" desc="FrankenUI Tasks Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Tasks Example built with MonsterUI (original design by ShadCN)"""
1311
+
1312
+ from fasthtml.common import *
1313
+ from monsterui.all import *
1314
+ from fasthtml.svg import *
1315
+ import json
1316
+
1317
+ app, rt = fast_app(hdrs=Theme.blue.headers())
1318
+
1319
+ def LAlignedCheckTxt(txt): return DivLAligned(UkIcon(icon='check'), P(txt, cls=TextPresets.muted_sm))
1320
+
1321
+ with open('data_/status_list.json', 'r') as f: data = json.load(f)
1322
+ with open('data_/statuses.json', 'r') as f: statuses = json.load(f)
1323
+
1324
+ def _create_tbl_data(d):
1325
+ return {'Done': d['selected'], 'Task': d['id'], 'Title': d['title'],
1326
+ 'Status' : d['status'], 'Priority': d['priority'] }
1327
+
1328
+ data = [_create_tbl_data(d) for d in data]
1329
+ page_size = 15
1330
+ current_page = 0
1331
+ paginated_data = data[current_page*page_size:(current_page+1)*page_size]
1332
+
1333
+ priority_dd = [{'priority': "low", 'count': 36 }, {'priority': "medium", 'count': 33 }, {'priority': "high", 'count': 31 }]
1334
+
1335
+ status_dd = [{'status': "backlog", 'count': 21 },{'status': "todo", 'count': 21 },{'status': "progress", 'count': 20 },{'status': "done",'count': 19 },{'status': "cancelled", 'count': 19 }]
1336
+
1337
+ def create_hotkey_li(hotkey): return NavCloseLi(A(DivFullySpaced(hotkey[0], Span(hotkey[1], cls=TextPresets.muted_sm))))
1338
+
1339
+ hotkeys_a = (('Profile','⇧⌘P'),('Billing','⌘B'),('Settings','⌘S'),('New Team',''))
1340
+ hotkeys_b = (('Logout',''), )
1341
+
1342
+ avatar_opts = DropDownNavContainer(
1343
+ NavHeaderLi(P('sveltecult'),NavSubtitle('[email protected]')),
1344
+ NavDividerLi(),
1345
+ *map(create_hotkey_li, hotkeys_a),
1346
+ NavDividerLi(),
1347
+ *map(create_hotkey_li, hotkeys_b),)
1348
+
1349
+ def CreateTaskModal():
1350
+ return Modal(
1351
+ Div(cls='p-6')(
1352
+ ModalTitle('Create Task'),
1353
+ P('Fill out the information below to create a new task', cls=TextPresets.muted_sm),
1354
+ Br(),
1355
+ Form(cls='space-y-6')(
1356
+ Grid(Div(Select(*map(Option,('Documentation', 'Bug', 'Feature')), label='Task Type', id='task_type')),
1357
+ Div(Select(*map(Option,('In Progress', 'Backlog', 'Todo', 'Cancelled', 'Done')), label='Status', id='task_status')),
1358
+ Div(Select(*map(Option, ('Low', 'Medium', 'High')), label='Priority', id='task_priority'))),
1359
+ TextArea(label='Title', placeholder='Please describe the task that needs to be completed'),
1360
+ DivRAligned(
1361
+ ModalCloseButton('Cancel', cls=ButtonT.ghost),
1362
+ ModalCloseButton('Submit', cls=ButtonT.primary),
1363
+ cls='space-x-5'))),
1364
+ id='TaskForm')
1365
+
1366
+ page_heading = DivFullySpaced(cls='space-y-2')(
1367
+ Div(cls='space-y-2')(
1368
+ H2('Welcome back!'),P("Here's a list of your tasks for this month!", cls=TextPresets.muted_sm)),
1369
+ Div(DiceBearAvatar("sveltcult",8,8),avatar_opts))
1370
+
1371
+ table_controls =(Input(cls='w-[250px]',placeholder='Filter task'),
1372
+ Button("Status"),
1373
+ DropDownNavContainer(map(NavCloseLi,[A(DivFullySpaced(P(a['status']), P(a['count'])),cls='capitalize') for a in status_dd])),
1374
+ Button("Priority"),
1375
+ DropDownNavContainer(map(NavCloseLi,[A(DivFullySpaced(LAlignedCheckTxt(a['priority']), a['count']),cls='capitalize') for a in priority_dd])),
1376
+ Button("View"),
1377
+ DropDownNavContainer(map(NavCloseLi,[A(LAlignedCheckTxt(o)) for o in ['Title','Status','Priority']])),
1378
+ Button('Create Task',cls=(ButtonT.primary, TextPresets.bold_sm), data_uk_toggle="target: #TaskForm"))
1379
+
1380
+ def task_dropdown():
1381
+ return Div(Button(UkIcon('ellipsis')),
1382
+ DropDownNavContainer(
1383
+ map(NavCloseLi,[
1384
+ *map(A,('Edit', 'Make a copy', 'Favorite')),
1385
+ A(DivFullySpaced(*[P(o, cls=TextPresets.muted_sm) for o in ('Delete', '⌘⌫')]))])))
1386
+ def header_render(col):
1387
+ match col:
1388
+ case "Done": return Th(CheckboxX(), shrink=True)
1389
+ case 'Actions': return Th("", shrink=True)
1390
+ case _: return Th(col, expand=True)
1391
+
1392
+ def cell_render(col, val):
1393
+ def _Td(*args,cls='', **kwargs): return Td(*args, cls=f'p-2 {cls}',**kwargs)
1394
+ match col:
1395
+ case "Done": return _Td(shrink=True)(CheckboxX(selected=val))
1396
+ case "Task": return _Td(val, cls='uk-visible@s') # Hide on small screens
1397
+ case "Title": return _Td(val, cls='font-medium', expand=True)
1398
+ case "Status" | "Priority": return _Td(cls='uk-visible@m uk-text-nowrap capitalize')(Span(val))
1399
+ case "Actions": return _Td(task_dropdown(), shrink=True)
1400
+ case _: raise ValueError(f"Unknown column: {col}")
1401
+
1402
+ task_columns = ["Done", 'Task', 'Title', 'Status', 'Priority', 'Actions']
1403
+
1404
+ tasks_table = Div(cls='mt-4')(
1405
+ TableFromDicts(
1406
+ header_data=task_columns,
1407
+ body_data=paginated_data,
1408
+ body_cell_render=cell_render,
1409
+ header_cell_render=header_render,
1410
+ sortable=True,
1411
+ cls=(TableT.responsive, TableT.sm, TableT.divider)))
1412
+
1413
+
1414
+ def footer():
1415
+ total_pages = (len(data) + page_size - 1) // page_size
1416
+ return DivFullySpaced(
1417
+ Div('1 of 100 row(s) selected.', cls=TextPresets.muted_sm),
1418
+ DivLAligned(
1419
+ DivCentered(f'Page {current_page + 1} of {total_pages}', cls=TextT.sm),
1420
+ DivLAligned(*[UkIconLink(icon=i, button=True) for i in ('chevrons-left', 'chevron-left', 'chevron-right', 'chevrons-right')])))
1421
+
1422
+ tasks_ui = Div(DivFullySpaced(DivLAligned(table_controls), cls='mt-8'), tasks_table, footer())
1423
+
1424
+ @rt
1425
+ def index(): return Container(page_heading, tasks_ui, CreateTaskModal())
1426
+
1427
+ serve()</doc><doc title="Music" desc="FrankenUI Music Example build with MonsterUI (Original design by ShadCN)">"""FrankenUI Music Example build with MonsterUI (Original design by ShadCN)"""
1428
+
1429
+ from fasthtml.common import *
1430
+
1431
+ from monsterui.all import *
1432
+
1433
+ app, rt = fast_app(hdrs=Theme.blue.headers())
1434
+
1435
+ def MusicLi(t,hk=''): return Li(A(DivFullySpaced(t,P(hk,cls=TextPresets.muted_sm))))
1436
+
1437
+ music_items = [("About Music", "" ),
1438
+ ("Preferences", "⌘" ),
1439
+ ("Hide Music" , "⌘H" ),
1440
+ ("Hide Others", "⇧⌘H"),
1441
+ ("Quit Music" , "⌘Q" )]
1442
+
1443
+ file_dd_items = [("New", ""),
1444
+ ("Open Stream URL", "⌘U"),
1445
+ ("Close Window", "⌘W"),
1446
+ ("Library", ""),
1447
+ ("Import", "⌘O"),
1448
+ ("Burn Playlist to Disc", ""),
1449
+ ("Show in Finder", "⇧⌘R"),
1450
+ ("Convert", ""),
1451
+ ("Page Setup", "Print")]
1452
+
1453
+ edit_actions = [("Undo", "⌘Z"),
1454
+ ("Redo", "⇧⌘Z"),
1455
+ ("Cut", "⌘X"),
1456
+ ("Copy", "⌘C"),
1457
+ ("Paste", "⌘V"),
1458
+ ("Select All", "⌘A"),
1459
+ ("Deselect All", "⇧⌘A")]
1460
+
1461
+ view_dd_data = ["Show Playing Next", "Show Lyrics", "Show Status Bar", "Hide Sidebar", "Enter Full Screen"]
1462
+
1463
+
1464
+ music_headers = NavBar(
1465
+ Button("Music", cls=ButtonT.ghost+TextT.gray),DropDownNavContainer(Li(A("Music"),NavContainer(map(lambda x: MusicLi(*x), music_items)))),
1466
+ Button("File", cls=ButtonT.ghost+TextT.gray), DropDownNavContainer(Li(A("File"), NavContainer(map(lambda x: MusicLi(*x), file_dd_items)))),
1467
+ Button("Edit", cls=ButtonT.ghost+TextT.gray), DropDownNavContainer(Li(A("Edit")),NavContainer(
1468
+ *map(lambda x: MusicLi(*x), edit_actions),
1469
+ Li(A(DivFullySpaced("Smart Dictation",UkIcon("mic")))),
1470
+ Li(A(DivFullySpaced("Emojis & Symbols",UkIcon("globe")))))),
1471
+ Button("View", cls=ButtonT.ghost+TextT.gray),DropDownNavContainer(Li(A("View"),NavContainer(map(lambda x: MusicLi(x), view_dd_data)))),
1472
+ brand=DivLAligned(H2("Purrify"))
1473
+ )
1474
+
1475
+
1476
+
1477
+
1478
+ # music_headers = NavBarContainer(
1479
+ # NavBarLSide(
1480
+ # NavBarNav(
1481
+ # Li(A("Music"),NavBarNavContainer(map(lambda x: MusicLi(*x), music_items))),
1482
+ # Li(A("File"), NavBarNavContainer(map(lambda x: MusicLi(*x), file_dd_items))),
1483
+ # Li(A("Edit")),
1484
+ # NavBarNavContainer(
1485
+ # *map(lambda x: MusicLi(*x), edit_actions),
1486
+ # Li(A(DivFullySpaced("Smart Dictation",UkIcon("mic")))),
1487
+ # Li(A(DivFullySpaced("Emojis & Symbols",UkIcon("globe"))))),
1488
+ # Li(A("View"),
1489
+ # NavBarNavContainer(map(lambda x: MusicLi(x), view_dd_data))),
1490
+ # Li(A("Account"),
1491
+ # NavBarNavContainer(
1492
+ # NavHeaderLi("Switch Account"),
1493
+ # *map(MusicLi, ("Andy", "Benoit", "Luis", "Manage Family", "Add Account")))))))
1494
+
1495
+
1496
+ def Album(title,artist):
1497
+ img_url = 'https://ucarecdn.com/e5607eaf-2b2a-43b9-ada9-330824b6afd7/music1.webp'
1498
+ return Div(
1499
+ Div(cls="overflow-hidden rounded-md")(Img(cls="transition-transform duration-200 hover:scale-105", src=img_url)),
1500
+ Div(cls='space-y-1')(Strong(title),P(artist,cls=TextT.muted)))
1501
+
1502
+ listen_now_albums = (("Roar", "Catty Perry"), ("Feline on a Prayer", "Cat Jovi"),("Fur Elise", "Ludwig van Beethovpurr"),("Purrple Rain", "Prince's Cat"))
1503
+
1504
+ made_for_you_albums = [("Like a Feline", "Catdonna"),
1505
+ ("Livin' La Vida Purrda", "Ricky Catin"),
1506
+ ("Meow Meow Rocket", "Elton Cat"),
1507
+ ("Rolling in the Purr", "Catdelle"),
1508
+ ("Purrs of Silence", "Cat Garfunkel"),
1509
+ ("Meow Me Maybe", "Carly Rae Purrsen"),]
1510
+
1511
+ music_content = (Div(H3("Listen Now"), cls="mt-6 space-y-1"),
1512
+ Subtitle("Top picks for you. Updated daily."),
1513
+ DividerLine(),
1514
+ Grid(*[Album(t,a) for t,a in listen_now_albums], cls='gap-8'),
1515
+ Div(H3("Made for You"), cls="mt-6 space-y-1"),
1516
+ Subtitle("Your personal playlists. Updated daily."),
1517
+ DividerLine(),
1518
+ Grid(*[Album(t,a) for t,a in made_for_you_albums], cols_xl=6))
1519
+
1520
+ tabs = TabContainer(
1521
+ Li(A('Music', href='#'), cls='uk-active'),
1522
+ Li(A('Podcasts', href='#')),
1523
+ Li(A('Live', cls='opacity-50'), cls='uk-disabled'),
1524
+ uk_switcher='connect: #component-nav; animation: uk-animation-fade',
1525
+ alt=True)
1526
+
1527
+ def podcast_tab():
1528
+ return Div(
1529
+ Div(cls='space-y-3 mt-6')(
1530
+ H3("New Episodes"),
1531
+ Subtitle("Your favorite podcasts. Updated daily.")),
1532
+ Div(cls="uk-placeholder flex h-[450px] items-center justify-center rounded-md mt-4",uk_placeholder=True)(
1533
+ DivVStacked(cls="space-y-6")(
1534
+ UkIcon("microphone", 3),
1535
+ H4("No episodes added"),
1536
+ Subtitle("You have not added any podcasts. Add one below."),
1537
+ Button("Add Podcast", cls=ButtonT.primary))))
1538
+
1539
+ discoved_data = [("play-circle","Listen Now"), ("binoculars", "Browse"), ("rss","Radio")]
1540
+ library_data = [("play-circle", "Playlists"), ("music", "Songs"), ("user", "Made for You"), ("users", "Artists"), ("bookmark", "Albums")]
1541
+ playlists_data = [("library","Recently Added"), ("library","Recently Played")]
1542
+
1543
+ def MusicSidebarLi(icon, text): return Li(A(DivLAligned(UkIcon(icon), P(text))))
1544
+ sidebar = NavContainer(
1545
+ NavHeaderLi(H3("Discover")), *[MusicSidebarLi(*o) for o in discoved_data],
1546
+ NavHeaderLi(H3("Library")), *[MusicSidebarLi(*o) for o in library_data],
1547
+ NavHeaderLi(H3("Playlists")),*[MusicSidebarLi(*o) for o in playlists_data],
1548
+ cls=(NavT.primary,'space-y-3','pl-8'))
1549
+
1550
+ @rt
1551
+ def index():
1552
+ return Title("Music Example"),Container(music_headers, DividerSplit(),
1553
+ Grid(sidebar,
1554
+ Div(cls="col-span-4 border-l border-border")(
1555
+ Div(cls="px-8 py-6")(
1556
+ DivFullySpaced(
1557
+ Div(cls="max-w-80")(tabs),
1558
+ Button(cls=ButtonT.primary)(DivLAligned(UkIcon('circle-plus')),Div("Add music"))),
1559
+ Ul(id="component-nav", cls="uk-switcher")(
1560
+ Li(*music_content),
1561
+ Li(podcast_tab())))),
1562
+ cols_sm=1, cols_md=1, cols_lg=5, cols_xl=5))
1563
+
1564
+ serve()</doc><doc title="Auth" desc="FrankenUI Auth Example built with MonsterUI (original design by ShadCN)">"""FrankenUI Auth Example built with MonsterUI (original design by ShadCN)"""
1565
+
1566
+ from fasthtml.common import *
1567
+ from monsterui.all import *
1568
+ from fasthtml.svg import *
1569
+
1570
+ app, rt = fast_app(hdrs=Theme.blue.headers())
1571
+
1572
+ @rt
1573
+ def index():
1574
+ left = Div(cls="col-span-1 hidden flex-col justify-between bg-zinc-900 p-8 text-white lg:flex")(
1575
+ Div(cls=(TextT.bold))("Acme Inc"),
1576
+ Blockquote(cls="space-y-2")(
1577
+ P(cls=TextT.lg)('"This library has saved me countless hours of work and helped me deliver stunning designs to my clients faster than ever before."'),
1578
+ Footer(cls=TextT.sm)("Sofia Davis")))
1579
+
1580
+ right = Div(cls="col-span-2 flex flex-col p-8 lg:col-span-1")(
1581
+ DivRAligned(Button("Login", cls=ButtonT.ghost)),
1582
+ DivCentered(cls='flex-1')(
1583
+ Container(
1584
+ DivVStacked(
1585
+ H3("Create an account"),
1586
+ Small("Enter your email below to create your account", cls=TextT.muted)),
1587
+ Form(
1588
+ Input(placeholder="[email protected]"),
1589
+ Button(Span(cls="mr-2", uk_spinner="ratio: 0.54"), "Sign in with Email", cls=(ButtonT.primary, "w-full"), disabled=True),
1590
+ DividerSplit(Small("Or continue with"),cls=TextT.muted),
1591
+ Button(UkIcon('github',cls='mr-2'), "Github", cls=(ButtonT.default, "w-full")),
1592
+ cls='space-y-6'),
1593
+ DivVStacked(Small(
1594
+ "By clicking continue, you agree to our ",
1595
+ A(cls=AT.muted, href="#demo")("Terms of Service")," and ",
1596
+ A(cls=AT.muted, href="#demo")("Privacy Policy"),".",
1597
+ cls=(TextT.muted,"text-center"))),
1598
+ cls="space-y-6")))
1599
+
1600
+ return Title("Auth Example"),Grid(left,right,cols=2, gap=0,cls='h-screen')
1601
+
1602
+
1603
+ serve()</doc></examples></project>
MonsterUI/docs/llms.txt ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MonsterUI Documentation
2
+
3
+ > MonsterUI is a python library which brings styling to python for FastHTML apps.
4
+
5
+ ## API Reference
6
+ - [API List](https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/apilist.txt): Complete API Reference
7
+
8
+ ## Examples
9
+ - [Cards](https://monsterui.answer.ai/cards/md): FrankenUI Cards Example built with MonsterUI (original design by ShadCN)
10
+ - [Dashboard](https://monsterui.answer.ai/dashboard/md): FrankenUI Dashboard Example built with MonsterUI (original design by ShadCN)
11
+ - [Forms](https://monsterui.answer.ai/forms/md): FrankenUI Forms Example built with MonsterUI (original design by ShadCN)
12
+ - [Scrollspy](https://monsterui.answer.ai/scrollspy/md): MonsterUI Scrollspy Example application
13
+ - [Ticket](https://monsterui.answer.ai/ticket/md): MonsterUI Help Desk Example - Professional Dashboard with DaisyUI components
14
+ - [Playground](https://monsterui.answer.ai/playground/md): FrankenUI Playground Example built with MonsterUI (original design by ShadCN)
15
+ - [Mail](https://monsterui.answer.ai/mail/md): FrankenUI Mail Example built with MonsterUI (original design by ShadCN)
16
+ - [Tasks](https://monsterui.answer.ai/tasks/md): FrankenUI Tasks Example built with MonsterUI (original design by ShadCN)
17
+ - [Music](https://monsterui.answer.ai/music/md): FrankenUI Music Example build with MonsterUI (Original design by ShadCN)
18
+ - [Auth](https://monsterui.answer.ai/auth/md): FrankenUI Auth Example built with MonsterUI (original design by ShadCN)
19
+
20
+ ## Optional
21
+ - [Accordion | Link](https://monsterui.answer.ai/api_ref/docs_accordion_link/md): Accordion API Reference
22
+ - [Button | Link](https://monsterui.answer.ai/api_ref/docs_button_link/md): Buttons & Links API Reference
23
+ - [Cards](https://monsterui.answer.ai/api_ref/docs_cards/md): Cards API Reference
24
+ - [Charts](https://monsterui.answer.ai/api_ref/docs_charts/md): Charts API Reference
25
+ - [Containers](https://monsterui.answer.ai/api_ref/docs_containers/md): Articles, Containers & Sections API Reference
26
+ - [Dividers](https://monsterui.answer.ai/api_ref/docs_dividers/md): Dividers API Reference
27
+ - [Forms](https://monsterui.answer.ai/api_ref/docs_forms/md): Forms and User Inputs API Reference
28
+ - [Html](https://monsterui.answer.ai/api_ref/docs_html/md): HTML Styling API Reference
29
+ - [Icons | Images](https://monsterui.answer.ai/api_ref/docs_icons_images/md): Icons & Images API Reference
30
+ - [Layout](https://monsterui.answer.ai/api_ref/docs_layout/md): Layout (Flex and Grid) API Reference
31
+ - [Lightbox](https://monsterui.answer.ai/api_ref/docs_lightbox/md): Lightbox API Reference
32
+ - [Lists](https://monsterui.answer.ai/api_ref/docs_lists/md): Lists API Reference
33
+ - [Loading](https://monsterui.answer.ai/api_ref/docs_loading/md): Loading Indicators API Reference
34
+ - [Markdown](https://monsterui.answer.ai/api_ref/docs_markdown/md): Markdown + automated HTML styling API Reference
35
+ - [Modals](https://monsterui.answer.ai/api_ref/docs_modals/md): Modals API Reference
36
+ - [Navigation](https://monsterui.answer.ai/api_ref/docs_navigation/md): Navigation (Nav, NavBar, Tabs, etc.) API Reference
37
+ - [Notifications](https://monsterui.answer.ai/api_ref/docs_notifications/md): Alerts & Toasts API Reference
38
+ - [Sliders](https://monsterui.answer.ai/api_ref/docs_sliders/md): Carousel Sliders API Reference
39
+ - [Steps](https://monsterui.answer.ai/api_ref/docs_steps/md): Steps API Reference
40
+ - [Tables](https://monsterui.answer.ai/api_ref/docs_tables/md): Tables API Reference
41
+ - [Theme | Headers](https://monsterui.answer.ai/api_ref/docs_theme_headers/md): Theme and Headers API Reference
42
+ - [Typography](https://monsterui.answer.ai/api_ref/docs_typography/md): Typography API Reference
43
+ - [Layout](https://monsterui.answer.ai/tutorial_layout/md): MonsterUI Page Layout Guide
44
+ - [Spacing](https://monsterui.answer.ai/tutorial_spacing/md): Padding & Margin & Spacing, Oh my! (MonsterUI Spacing Guide)
MonsterUI/docs/main.py ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fasthtml.common import *
2
+ from functools import partial
3
+ from monsterui.all import *
4
+ from fasthtml.components import Uk_theme_switcher
5
+ from utils import render_nb
6
+ from pathlib import Path
7
+ from toolslm.download import read_html,html2md
8
+ from starlette.responses import PlainTextResponse
9
+ import httpx
10
+
11
+ def _not_found(req, exc):
12
+ _path = req.url.path.rstrip('/')
13
+ if _path.endswith('.md') or _path.endswith('.rmd'):
14
+ url = f'https://monsterui.answer.ai{_path[:-3].rstrip("/").rstrip(".")}'.rstrip("/").rstrip(".")
15
+ try:
16
+ r = httpx.head(url, follow_redirects=True, timeout=1.0)
17
+ if r.status_code < 400: # Accept 2xx and 3xx status codes
18
+ if _path.endswith('.rmd') or _path.endswith('/rmd'): return Container(render_md(read_html(url, sel='#content')))
19
+ elif _path.endswith('.md') or _path.endswith('/md'): return PlainTextResponse(read_html(url, sel='#content'))
20
+ except (httpx.TimeoutException, httpx.NetworkError): pass
21
+ return _create_page(
22
+ Container(Card(CardBody(H1("404 - Page Not Found"), P("The page you're looking for doesn't exist.")))),
23
+ req,
24
+ None)
25
+
26
+
27
+ app,rt = fast_app(exception_handlers={404:_not_found}, pico=False,
28
+ hdrs=(*Theme.blue.headers(highlightjs=True,apex_charts=True), Link(rel="icon", type="image/x-icon", href="/favicon.ico"),
29
+ Link(rel="stylesheet", href="/custom_theme.css", type="text/css")),
30
+ )
31
+
32
+ def is_htmx(request=None):
33
+ "Check if the request is an HTMX request"
34
+ return request and 'hx-request' in request.headers
35
+
36
+ def _create_page(content, # The content to display (without the layout/sidebar)
37
+ request, # Request object to determine if HTMX request
38
+ sidebar_section, # The open section on the sidebar
39
+ ):
40
+ "Makes page load sidebar if direct request, otherwise loads content only via HTMX"
41
+ if is_htmx(request): return content
42
+ else: return with_layout(sidebar_section, content)
43
+
44
+ def with_layout(sidebar_section, content):
45
+ "Puts the sidebar and content into a layout"
46
+ return Title(f"MonsterUI"), Div(cls="flex flex-col md:flex-row w-full")(
47
+ Button(UkIcon("menu",50,50,cls='mt-4'), cls="md:hidden mb-4", data_uk_toggle="target: #mobile-sidebar"),
48
+ Div(sidebar(sidebar_section), id='mobile-sidebar', hidden=True),
49
+ Div(cls="md:flex w-full")(
50
+ Div(sidebar(sidebar_section), cls="hidden md:block w-1/5 max-w-52"),
51
+ Div(content, cls='md:w-4/5 w-full mr-5', id="content", )))
52
+
53
+
54
+ ###
55
+ # Build the Example Pages
56
+ ###
57
+
58
+ from examples.tasks import index as tasks_homepage
59
+ from examples.cards import index as cards_homepage
60
+ from examples.dashboard import index as dashboard_homepage
61
+ from examples.forms import index as forms_homepage
62
+ from examples.music import index as music_homepage
63
+ from examples.auth import index as auth_homepage
64
+ from examples.playground import index as playground_homepage
65
+ from examples.mail import index as mail_homepage
66
+ from examples.scrollspy import index as scrollspy_homepage
67
+ from examples.ticket import index as ticket_homepage
68
+ def _example_route(name, homepage, o:str, request=None):
69
+ match o:
70
+ case 'code' | 'rmd': return Div(render_md(f'''```python\n\n{open(f'examples/{name}.py').read()}\n\n```'''))
71
+ case 'md': return PlainTextResponse(open(f'examples/{name}.py').read())
72
+ case _: return _create_example_page(homepage, request)
73
+
74
+ _create_example_page = partial(_create_page, sidebar_section='Examples')
75
+
76
+ @rt('/scrollspy')
77
+ @rt('/scrollspy/{o}')
78
+ def scrollspy(o:str='', request=None): return _example_route('scrollspy', Div(DivRAligned(A("See Code",href='/scrollspy/code',cls='m-4 uk-btn'+ButtonT.default)),scrollspy_homepage()), o, request)
79
+
80
+ @rt('/ticket')
81
+ @rt('/ticket/{o}')
82
+ def ticket(o:str='', request=None): return _example_route('ticket', Div(DivRAligned(A("See Code",href='/ticket/code',cls='m-4 uk-btn'+ButtonT.default)),ticket_homepage()), o, request)
83
+
84
+ @rt('/tasks')
85
+ @rt('/tasks/{o}')
86
+ def tasks(o:str='', request=None): return _example_route('tasks', Div(DivRAligned(A("See Code",href='/tasks/code',cls='m-4 uk-btn'+ButtonT.default)),tasks_homepage()), o, request)
87
+
88
+ @rt('/cards')
89
+ @rt('/cards/{o}')
90
+ def cards(o:str, request=None): return _example_route('cards', Div(DivRAligned(A("See Code",href='/cards/code',cls='m-4 uk-btn'+ButtonT.default)),cards_homepage()), o, request)
91
+
92
+ @rt('/dashboard')
93
+ @rt('/dashboard/{o}')
94
+ def dashboard(o:str, request=None): return _example_route('dashboard', Div(DivRAligned(A("See Code",href='/dashboard/code',cls='m-4 uk-btn'+ButtonT.default)),dashboard_homepage()), o, request)
95
+
96
+ @rt('/forms')
97
+ @rt('/forms/{o}')
98
+ def forms(o:str, request=None): return _example_route('forms', Div(DivRAligned(A("See Code",href='/forms/code',cls='m-4 uk-btn'+ButtonT.default)),forms_homepage()), o, request)
99
+
100
+ @rt('/music')
101
+ @rt('/music/{o}')
102
+ def music(o:str, request=None): return _example_route('music', Div(DivRAligned(A("See Code",href='/music/code',cls='m-4 uk-btn'+ButtonT.default)),music_homepage()), o, request)
103
+
104
+ @rt('/auth')
105
+ @rt('/auth/{o}')
106
+ def auth(o:str, request=None): return _example_route('auth', Div(DivRAligned(A("See Code",href='/auth/code',cls='m-4 uk-btn'+ButtonT.default)),auth_homepage()), o, request)
107
+
108
+ @rt('/playground')
109
+ @rt('/playground/{o}')
110
+ def playground(o:str, request=None): return _example_route('playground', Div(DivRAligned(A("See Code",href='/playground/code',cls='m-4 uk-btn'+ButtonT.default)),playground_homepage()), o, request)
111
+
112
+ @rt('/mail')
113
+ @rt('/mail/{o}')
114
+ def mail(o:str, request=None): return _example_route('mail', Div(DivRAligned(A("See Code",href='/mail/code',cls='m-4 uk-btn'+ButtonT.default)),mail_homepage()), o, request)
115
+
116
+ ###
117
+ # Build the API Reference Pages
118
+ ###
119
+
120
+ import api_reference.api_reference as api_reference
121
+ def fname2title(ref_fn_name): return ref_fn_name[5:].replace('_',' | ').title()
122
+
123
+ reference_fns = L([o for o in dir(api_reference) if o.startswith('docs_')])
124
+ @rt('/api_ref/{o}')
125
+ def api_route(request, o:str):
126
+ if o not in reference_fns: raise HTTPException(404)
127
+ content = getattr(api_reference, o)()
128
+ return _create_page(Container(content), request=request, sidebar_section='API Reference')
129
+
130
+ @rt('/api_ref/{o}/md')
131
+ def api_route_md(request, o:str):
132
+ if o not in reference_fns: raise HTTPException(404)
133
+ content = getattr(api_reference, o)()
134
+ return PlainTextResponse(html2md(to_xml(content)))
135
+
136
+ @rt('/api_ref/{o}rmd')
137
+ def api_route_md(request, o:str):
138
+ if o not in reference_fns: raise HTTPException(404)
139
+ content = getattr(api_reference, o)()
140
+ return Div(render_md(html2md(to_xml(content))))
141
+
142
+ ###
143
+ # Build the Guides Pages
144
+ ###
145
+ @rt('/tutorial_spacing')
146
+ @rt('/tutorial_spacing/{o}')
147
+ def tutorial_spacing(o:str='', request=None):
148
+ if o=='md': return PlainTextResponse(read_html(f'https://monsterui.answer.ai/tutorial_spacing', sel='#content'))
149
+ if o=='rmd': return Div(render_md(read_html(f'https://monsterui.answer.ai/tutorial_spacing', sel='#content')))
150
+ return _create_page(render_nb('guides/Spacing.ipynb'), request, 'Guides')
151
+ @rt('/tutorial_layout')
152
+ @rt('/tutorial_layout/{o}')
153
+ def tutorial_layout(o:str='', request=None):
154
+ if o=='md': return PlainTextResponse(read_html(f'https://monsterui.answer.ai/tutorial_layout', sel='#content'))
155
+ if o=='rmd': return Div(render_md(read_html(f'https://monsterui.answer.ai/tutorial_layout', sel='#content')))
156
+ return _create_page(render_nb('guides/Layout.ipynb'), request, 'Guides',)
157
+
158
+ ###
159
+ # Build the Theme Switcher Page
160
+ ###
161
+
162
+ @rt
163
+ def theme_switcher(request):
164
+ return _create_page(Div(ThemePicker(custom_themes=[("Grass", "#10b981")]),cls="p-12"), request, None)
165
+
166
+ ###
167
+ # Build the Getting Started Pages
168
+ ###
169
+
170
+ gs_path = Path('getting_started')
171
+
172
+ @rt('/tutorial_app')
173
+ @rt('/tutorial_app/{o}')
174
+ def tutorial_app(o:str='', request=None):
175
+ pass
176
+ if o=='md': return PlainTextResponse(read_html(f'https://monsterui.answer.ai/tutorial_app', sel='#content'))
177
+ if o=='rmd': return Div(render_md(read_html(f'https://monsterui.answer.ai/tutorial_app', sel='#content')))
178
+ app_code = open(gs_path/'app_product_gallery.py').read()
179
+ app_rendered = Div(Pre(Code(app_code)))
180
+ content = Container(cls='space-y-4')(
181
+ H1("Tutorial App"),
182
+ render_md("""This is a heavily commented example of a product gallery app built with MonsterUI for those that like to learn by example. \
183
+ This tutorial app assumes you have some familiarity with fasthtml apps already, so focuses on what MonsterUI adds on top of fasthtml.
184
+ To make the most out of this tutorial, you should follow these steps:"""),
185
+ Ol(
186
+ Li("Briefly read through this to get an overview of what is happening, without focusing on any details"),
187
+ Li("Install fasthtml and MonsterUI"),
188
+ Li("Copy the code into your own project locally and run it using `python app.py`"),
189
+ Li("Go through the code in detail to understand how it works by experimenting with changing things"),
190
+ cls=ListT.decimal+TextT.lg
191
+ ),
192
+ render_md("""> Tip: Try adding `import fasthtml.common as fh`, so you can replace things with the base fasthtml components to see what happens!
193
+ For example, try replacing `H4` with `fh.H4` or `Button` with `fh.Button`."""),
194
+ Divider(),
195
+ app_rendered)
196
+ return _create_page(content, request, 'Getting Started')
197
+
198
+ @rt('/')
199
+ @rt('/{o}')
200
+ def index(o:str='', request=None):
201
+ if o=='md': return PlainTextResponse(read_html(f'https://monsterui.answer.ai/getting_started', sel='#content'))
202
+ if o=='rmd': return Div(render_md(read_html(f'https://monsterui.answer.ai/getting_started', sel='#content')))
203
+ content = Container(render_md(open(gs_path/'GettingStarted.md').read()))
204
+ return _create_page(content, request, 'Getting Started')
205
+
206
+ ###
207
+ # Build the Sidebar
208
+ ###
209
+
210
+ def sidebar(open_section):
211
+ def create_li(title, href):
212
+ return Li(A(title,hx_target="#content", hx_get=href, hx_push_url='true'))
213
+
214
+ return NavContainer(
215
+ NavParentLi(
216
+ A(DivFullySpaced("Getting Started", )),
217
+ NavContainer(create_li("Getting Started", index),
218
+ create_li("Tutorial App", tutorial_app),
219
+ parent=False),
220
+ cls='uk-open' if open_section=='Getting Started' else ''
221
+ ),
222
+ NavParentLi(
223
+ A(DivFullySpaced("API Reference", )),
224
+ NavContainer(
225
+ *[create_li(fname2title(o), f"/api_ref/{o}") for o in reference_fns],
226
+ parent=False,
227
+ ),
228
+ cls='uk-open' if open_section=='API Reference' else ''
229
+ ),
230
+ NavParentLi(
231
+ A(DivFullySpaced('Guides', )),
232
+ NavContainer(
233
+ *[create_li(title, href) for title, href in [
234
+ ('Spacing', tutorial_spacing),
235
+ ('Layout', tutorial_layout),
236
+ ]],
237
+ parent=False
238
+ ),
239
+ cls='uk-open' if open_section=='Guides' else ''
240
+ ),
241
+
242
+ NavParentLi(
243
+ A(DivFullySpaced('Examples', )),
244
+ NavContainer(
245
+ *[create_li(title, href) for title, href in [
246
+ ('Task', '/tasks/'),
247
+ ('Card', '/cards/'),
248
+ ('Dashboard', '/dashboard/'),
249
+ ('Form', '/forms/'),
250
+ ('Music', '/music/'),
251
+ ('Auth', '/auth/'),
252
+ ('Playground', '/playground/'),
253
+ ('Mail', '/mail/'),
254
+ ('Ticket', '/ticket/'),
255
+ ('Scrollspy', '/scrollspy/'),
256
+ ]],
257
+ parent=False
258
+ ),
259
+ cls='uk-open' if open_section=='Examples' else ''
260
+ ),
261
+ create_li("Theme", theme_switcher),
262
+ uk_nav=True,
263
+ cls=(NavT.primary, "space-y-4 p-4 w-full md:w-full")
264
+ )
265
+
266
+ serve()
MonsterUI/docs/requirements.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ toolslm
2
+ python-fasthtml
3
+ pandas
4
+ plotly
5
+ monsterui @ git+https://github.com/AnswerDotAI/monsterui
6
+ fastcore
7
+ fh_matplotlib
8
+ numpy
9
+ matplotlib
10
+ pysymbol_llm @ git+https://github.com/AnswerDotAI/pysymbol-llm.git
11
+ mistletoe
12
+ lxml
13
+ html2text
MonsterUI/docs/updatellms.sh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ ./createllms.sh
3
+ pysym2md --output_file apilist.txt monsterui
4
+ llms_txt2ctx llms.txt >llms-ctx.txt
5
+ llms_txt2ctx llms.txt --optional True > llms-ctx-full.txt
MonsterUI/docs/utils.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Utilities for building the docs page that don't belong anywhere else"""
2
+
3
+
4
+ __all__ = ['hjs', 'HShow', 'create_server']
5
+
6
+ from fasthtml.common import *
7
+ from monsterui.all import *
8
+ from fasthtml.jupyter import *
9
+ from collections.abc import Callable
10
+ import inspect
11
+ import ast
12
+ def get_last_statement(code): return ast.unparse(ast.parse(code).body[-1])
13
+ import json
14
+ from pathlib import Path
15
+
16
+
17
+ def create_flippable_card(content, source_code, extra_cls=None):
18
+ "Creates a card that flips between content and source code"
19
+ _id = 'f'+str(unqid())
20
+ _card = Card(
21
+ Button(
22
+ DivFullySpaced(UkIcon('corner-down-right', 20, 20, 3),"See Source"),
23
+ data_uk_toggle=f"target: #{_id}", id=_id, cls=ButtonT.primary),
24
+ Button(
25
+ DivFullySpaced(UkIcon('corner-down-right', 20, 20, 3),"See Output"),
26
+ data_uk_toggle=f"target: #{_id}", id=_id, cls=ButtonT.primary, hidden=True),
27
+ Div(content, id=_id),
28
+ Div(Pre(Code(source_code, cls="hljs language-python")), id=_id, hidden=True),
29
+ cls='my-8')
30
+ return Div(_card, cls=extra_cls) if extra_cls else _card
31
+
32
+ def fn2code_string(fn: Callable) -> tuple: return fn(), inspect.getsource(fn)
33
+
34
+
35
+ def render_nb(path):
36
+ "Renders a Jupyter notebook with markdown cells and flippable code cards"
37
+ namespace = globals().copy()
38
+ # Read and parse the notebook
39
+ nb_content = json.loads(Path(path).read_text())
40
+ cells = nb_content['cells']
41
+
42
+ # Convert cells to appropriate HTML elements
43
+ rendered_cells = []
44
+ for cell in cells:
45
+ if cell['cell_type'] == 'markdown':
46
+ # Combine all markdown lines and render
47
+ md_content = ''.join(cell['source'])
48
+ rendered_cells.append(render_md(md_content))
49
+ elif cell['cell_type'] == 'code':
50
+ # Skip empty code cells
51
+ if not ''.join(cell['source']).strip(): continue
52
+ # Create flippable card for code
53
+ code_content = ''.join(cell['source'])
54
+ exec(code_content, namespace)
55
+ result = eval(get_last_statement(code_content), namespace)
56
+
57
+ rendered_cells.append(create_flippable_card(result, code_content))
58
+
59
+ # Return all cells wrapped in a container with vertical spacing
60
+ return Container(cls='space-y-4')(*rendered_cells)