many small improvements
This commit is contained in:
		
							
								
								
									
										2
									
								
								build.sh
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								build.sh
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| rm -rf ./dist/ | ||||
| #rm -rf ./dist/ | ||||
| python setup.py bdist_wheel | ||||
|  | ||||
| wheel_files=( dist/*whl ) | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								dist/pyscript_bootstrap_templates-0.2.0-py3-none-any.whl
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/pyscript_bootstrap_templates-0.2.0-py3-none-any.whl
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -20,6 +20,8 @@ toast_container.position_end = 0 | ||||
|  | ||||
|  | ||||
| def onclick(_): | ||||
|     # NOTE: you can also use app.toast(...) and app.alert_success(...) to show toasts | ||||
|     # and alerts at the default bottom right position | ||||
|     alert = bHTML.AlertSuccess("You clicked me!", parent=app.main) | ||||
|     alert.w = 25 | ||||
|     toast = bHTML.Toast("You clicked me!", parent=toast_container) | ||||
| @ -27,4 +29,3 @@ def onclick(_): | ||||
|     toast.show() | ||||
|  | ||||
| btn.onclick = onclick | ||||
|      | ||||
										
											Binary file not shown.
										
									
								
							| @ -1,5 +1,5 @@ | ||||
|  | ||||
| const pwa_version = "01_hello_world_202306031006" | ||||
| const pwa_version = "01_hello_world_202306041650" | ||||
| const assets = ["./index.html", | ||||
|     "./main.py", | ||||
|     "./resources/bootstrap.css", | ||||
| @ -48,4 +48,15 @@ self.addEventListener('fetch', event => { | ||||
|         return response; | ||||
|     })()); | ||||
| }); | ||||
| self.addEventListener('activate', (event) => { | ||||
|     event.waitUntil( | ||||
|         caches.keys().then((keyList) => { | ||||
|             return Promise.all(keyList.map((key) => { | ||||
|                 if(key !== pwa_version) { | ||||
|                     return caches.delete(key); | ||||
|                 } | ||||
|             })); | ||||
|         }) | ||||
|     ); | ||||
| }); | ||||
|      | ||||
										
											Binary file not shown.
										
									
								
							| @ -1,5 +1,5 @@ | ||||
|  | ||||
| const pwa_version = "02_image_filter_202306031006" | ||||
| const pwa_version = "02_image_filter_202306041650" | ||||
| const assets = ["./index.html", | ||||
|     "./main.py", | ||||
|     "./resources/bootstrap.css", | ||||
| @ -48,4 +48,15 @@ self.addEventListener('fetch', event => { | ||||
|         return response; | ||||
|     })()); | ||||
| }); | ||||
| self.addEventListener('activate', (event) => { | ||||
|     event.waitUntil( | ||||
|         caches.keys().then((keyList) => { | ||||
|             return Promise.all(keyList.map((key) => { | ||||
|                 if(key !== pwa_version) { | ||||
|                     return caches.delete(key); | ||||
|                 } | ||||
|             })); | ||||
|         }) | ||||
|     ); | ||||
| }); | ||||
|      | ||||
										
											Binary file not shown.
										
									
								
							| @ -1,5 +1,5 @@ | ||||
|  | ||||
| const pwa_version = "03_numpy_grid_demo_202306031006" | ||||
| const pwa_version = "03_numpy_grid_demo_202306041650" | ||||
| const assets = ["./index.html", | ||||
|     "./main.py", | ||||
|     "./resources/bootstrap.css", | ||||
| @ -48,4 +48,15 @@ self.addEventListener('fetch', event => { | ||||
|         return response; | ||||
|     })()); | ||||
| }); | ||||
| self.addEventListener('activate', (event) => { | ||||
|     event.waitUntil( | ||||
|         caches.keys().then((keyList) => { | ||||
|             return Promise.all(keyList.map((key) => { | ||||
|                 if(key !== pwa_version) { | ||||
|                     return caches.delete(key); | ||||
|                 } | ||||
|             })); | ||||
|         }) | ||||
|     ); | ||||
| }); | ||||
|      | ||||
| @ -9,13 +9,13 @@ import numpy as np | ||||
| from PIL import Image | ||||
| import cv2 | ||||
|  | ||||
| loaded_img = None | ||||
| loaded_img:np.ndarray = None | ||||
|  | ||||
| app = bootstrap_templates.PyScriptBootstrapDashboard(parent_element="pyscript_app", brand_name="Pyscript Cell Detector") | ||||
| app = bootstrap_templates.PyScriptBootstrapDashboard(parent_element="pyscript_app", brand_name="Pyscript Cell Colony Detector") | ||||
|  | ||||
| main_div = bHTML.BootstrapContainer(parent=app.main) | ||||
| main_div.w = 100 | ||||
| result_div = bHTML.BootstrapContainer(parent=main_div) | ||||
| result_div = bHTML.BootstrapContainer (parent=main_div) | ||||
|  | ||||
|  | ||||
| def process_image(image, | ||||
| @ -24,13 +24,20 @@ def process_image(image, | ||||
|                   hough_param2 = 500, | ||||
|                   minRadius = 100, | ||||
|                   maxRadius=500, | ||||
|                   inner_hough_circles=True): | ||||
|                   inner_hough_param1 = 25, | ||||
|                   inner_hough_param2 = 50, | ||||
|                   inner_hough_circles=True, | ||||
|                   cell_colony_color_channel:int = None): | ||||
|      | ||||
|     for child in result_div.children: | ||||
|         child.destroy() | ||||
|     #image = cv2.imread(str(test_img_path), cv2.IMREAD_COLOR) | ||||
|  | ||||
|     # Convert the image to grayscale | ||||
|     gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | ||||
|     if cell_colony_color_channel is None: | ||||
|         gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | ||||
|     else: | ||||
|         gray = image.astype(float)[...,cell_colony_color_channel] | ||||
|         gray = (255 * gray / gray.max()).astype(np.uint8) | ||||
|  | ||||
|     # Use median blur to reduce noise | ||||
|     gray = cv2.medianBlur(gray, 5) | ||||
| @ -46,7 +53,7 @@ def process_image(image, | ||||
|                                maxRadius=maxRadius) | ||||
|  | ||||
|     if circles is None: | ||||
|         bHTML.AlertDanger("No cell areas detected in image", parent=app.main) | ||||
|         app.alert_danger("No cell areas detected in image") | ||||
|         return False | ||||
|      | ||||
|     # Convert to integers | ||||
| @ -84,7 +91,14 @@ def process_image(image, | ||||
|  | ||||
|         for well, well_gray in zip(first_wells, first_wells_gray): | ||||
|              | ||||
|             circles = cv2.HoughCircles(well_gray, cv2.HOUGH_GRADIENT, 1, minDist=hough_min_dist, param1=50, param2=50, minRadius=(well.shape[0] // 2) - 50, maxRadius=(well.shape[0] // 2) - 10) | ||||
|             circles = cv2.HoughCircles(well_gray, | ||||
|                                        cv2.HOUGH_GRADIENT, | ||||
|                                        1, | ||||
|                                        minDist=hough_min_dist, | ||||
|                                        param1=inner_hough_param1, | ||||
|                                        param2=inner_hough_param2, | ||||
|                                        minRadius=int((min(well.shape[0],well.shape[1]) // 2)*0.79), | ||||
|                                        maxRadius=int((min(well.shape[0],well.shape[1]) // 2)*0.95)) | ||||
|             if circles is not None: | ||||
|                 circles = np.uint16(np.around(circles)) | ||||
|                 i = circles[0,:][0] | ||||
| @ -109,9 +123,11 @@ def process_image(image, | ||||
|         second_wells = first_wells | ||||
|         second_wells_gray = first_wells_gray | ||||
|      | ||||
|     tabs = {} | ||||
|  | ||||
|     for well, well_gray in zip(second_wells, second_wells_gray): | ||||
|     for well in second_wells: | ||||
|          | ||||
|         well_gray = cv2.cvtColor(well, cv2.COLOR_BGR2GRAY) | ||||
|         _, binary = cv2.threshold(255 - well_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) | ||||
|      | ||||
|  | ||||
| @ -120,29 +136,37 @@ def process_image(image, | ||||
|         cleaned = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) | ||||
|          | ||||
|  | ||||
|         radius = well.shape[0] // 2 -1 | ||||
|         radius = min(well.shape[0], well.shape[1]) // 2 -1 | ||||
|         # Now clear all pixels outside the circular well. | ||||
|         # We do this by creating a mask for the well and applying it to the image. | ||||
|         well_mask = np.zeros_like(cleaned, dtype=np.uint8) | ||||
|         cv2.circle(well_mask, (radius, radius), radius, 1, thickness=-1) | ||||
|         cv2.circle(well_mask, (well.shape[1] // 2, well.shape[0] // 2), radius, 1, thickness=-1) | ||||
|         cleaned = cleaned * well_mask | ||||
|  | ||||
|         circle = well_mask > 0 | ||||
|  | ||||
|         # now create an image overlay to display | ||||
|         ratio = np.sum((cleaned > 0).astype(int)) / np.sum(circle.astype(int)) | ||||
|         div_result = bHTML.BootstrapContainer(f"ratio: {ratio * 100}%", parent=result_div) | ||||
|         div_result = bHTML.BootstrapContainer(f"ratio: {ratio * 100}%") | ||||
|         div_result.shadow = bHTML.Shadow.LARGE | ||||
|         div_result.rounded = True | ||||
|         div_result.w = 50 | ||||
|         div_result.w = 75 | ||||
|         div_result.h = 75 | ||||
|         div_result.rounded_size = 50 | ||||
|         div_result.p = 3 | ||||
|  | ||||
|         well = well.copy() | ||||
|         well[cleaned > 0,0] = 255 | ||||
|         final_img = bHTML.Image.from_numpy_array(well, parent=div_result) | ||||
|         final_img.rounded = True | ||||
|         final_img.rounded_size = 10 | ||||
|         final_img.rounded_size = 50 | ||||
|         final_img.shadow = bHTML.Shadow.LARGE | ||||
|         final_img.w = 100 | ||||
|  | ||||
|         tabs[f"Well #{len(tabs) + 1}"] = div_result | ||||
|      | ||||
|     tabs = bHTML.Tabs(tabs, parent=result_div) | ||||
|     tabs.w = 100 | ||||
|  | ||||
|  | ||||
| div = bHTML.BootstrapContainer("Controls", parent=app.sidebar) | ||||
| @ -150,64 +174,135 @@ div.font_size = 4 | ||||
|  | ||||
| image_input = bInputs.InputFile(label_text="choose image file", parent=app.sidebar) | ||||
|  | ||||
| i_hough_min_dist = bInputs.InputInt("hough min distance [px]", parent=app.sidebar) | ||||
| i_hough_min_dist.value = 500 | ||||
|  | ||||
| i_hough_param1 = bInputs.InputInt("hough param1", parent=app.sidebar) | ||||
| i_hough_param1.value = 80 | ||||
|  | ||||
| i_hough_param2 = bInputs.InputInt("hough param2", parent=app.sidebar) | ||||
| i_hough_param2.value = 500 | ||||
|  | ||||
| i_hough_min_radius = bInputs.InputInt("hough min radius [px]", parent=app.sidebar) | ||||
| i_hough_min_radius.value = 100 | ||||
|  | ||||
| i_hough_max_radius = bInputs.InputInt("hough max radius [px]", parent=app.sidebar) | ||||
| i_hough_max_radius.value = 500 | ||||
|  | ||||
|  | ||||
|  | ||||
| btn = bHTML.ButtonPrimary("Process", parent=app.sidebar) | ||||
| btn.w = 100 | ||||
| btn.mt = 3 | ||||
| btn.mb = 3 | ||||
| btn.ml = 4 | ||||
| btn.mr = 4 | ||||
|  | ||||
| i_hough_min_dist = bInputs.InputInt("hough min distance [px]", | ||||
|                                     parent=app.sidebar, | ||||
|                                     help_text="minimal distance between wells in pixels") | ||||
| i_hough_min_dist.value = 500 | ||||
|  | ||||
| i_hough_param1 = bInputs.InputInt("hough param1", | ||||
|                                   parent=app.sidebar, | ||||
|                                   help_text="parameter for canny edge detector") | ||||
| i_hough_param1.value = 80 | ||||
|  | ||||
| i_hough_param2 = bInputs.InputInt("hough param2", | ||||
|                                   parent=app.sidebar, | ||||
|                                   help_text="increase this value to prevent false circle detection") | ||||
| i_hough_param2.value = 500 | ||||
|  | ||||
| i_hough_min_radius = bInputs.InputInt("hough min radius [px]", | ||||
|                                        parent=app.sidebar, | ||||
|                                        help_text="min radius for circle detection") | ||||
| i_hough_min_radius.value = 100 | ||||
|  | ||||
| i_hough_max_radius = bInputs.InputInt("hough max radius [px]", | ||||
|                                        parent=app.sidebar, | ||||
|                                        help_text="max radius for circle detection") | ||||
| i_hough_max_radius.value = 500 | ||||
|  | ||||
| i_inner_hough = bInputs.InputCheckboxSingle("nested hough transform?", | ||||
|                                              parent=app.sidebar, | ||||
|                                              help_text="if set, circle detection will be applied twice on detected wells") | ||||
| i_inner_hough.value = True | ||||
| i_inner_hough.m = 3 | ||||
|  | ||||
| i_inner_hough_param1 = bInputs.InputInt("inner hough param1", parent=app.sidebar) | ||||
| i_inner_hough_param1.value = 25 | ||||
|  | ||||
| i_inner_hough_param2 = bInputs.InputInt("inner hough param2", parent=app.sidebar) | ||||
| i_inner_hough_param2.value = 50 | ||||
|  | ||||
| i_use_color_channel = bInputs.InputSelect(["all", | ||||
|                                             "red", | ||||
|                                             "green", | ||||
|                                             "blue"], | ||||
|                                             label_text="cell colony color channel", | ||||
|                                             parent=app.sidebar, | ||||
|                                             help_text="if cells are more present in a specific channel, select it here") | ||||
| i_use_color_channel.value = "blue" | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| def on_image_change(f, *args): | ||||
|     global loaded_img | ||||
|     f.seek(0) | ||||
|     img = np.array(Image.open(f)) | ||||
|     for child in result_div.children: | ||||
|         child.destroy() | ||||
|      | ||||
|     output = bHTML.Image.from_numpy_array(img, parent=result_div) | ||||
|     output.rounded = True | ||||
|     output.rounded_size = 10 | ||||
|     output.shadow = bHTML.Shadow.LARGE | ||||
|     output.w=50 | ||||
|      | ||||
|     loaded_img = img | ||||
|  | ||||
|     try: | ||||
|         global loaded_img | ||||
|         f.seek(0) | ||||
|         img = np.array(Image.open(f)) | ||||
|         for child in result_div.children: | ||||
|             child.destroy() | ||||
|  | ||||
|         bHTML.BootstrapContainer("input image:", parent=result_div) | ||||
|         output = bHTML.Image.from_numpy_array(img, parent=result_div) | ||||
|         output.rounded = True | ||||
|         output.rounded_size = 10 | ||||
|         output.shadow = bHTML.Shadow.LARGE | ||||
|         output.width = "100%" | ||||
|         output.height = "100%" | ||||
|          | ||||
|         loaded_img = img | ||||
|  | ||||
|         app.toast("successfully loaded image", "info") | ||||
|         #toast = bHTML.Toast("successfully loaded image", title="info", parent=toast_container) | ||||
|         #toast.animation = True | ||||
|         #toast.show() | ||||
|     except Exception as e: | ||||
|         for child in result_div.children: | ||||
|             child.destroy() | ||||
|         bHTML.AlertDanger(f"error while loading image: {str(e)}", parent=alert_container) | ||||
|  | ||||
|  | ||||
| image_input.onchange = on_image_change     | ||||
|  | ||||
| def on_click(*args, **kwargs): | ||||
|     if loaded_img is None: | ||||
|         bHTML.AlertDanger("No image loaded", parent=app.main) | ||||
|         app.alert_danger("No image loaded") | ||||
|         return | ||||
|      | ||||
|     h_min_dist = int(i_hough_min_dist.value) | ||||
|     h_param1 = int(i_hough_param1.value) | ||||
|     h_param2 = int(i_hough_param2.value) | ||||
|     h_min_radius = int(i_hough_min_radius.value) | ||||
|     h_max_radius = int(i_hough_max_radius.value) | ||||
|     for child in result_div.children: | ||||
|         child.destroy() | ||||
|  | ||||
|     try: | ||||
|         h_min_dist = int(i_hough_min_dist.value) | ||||
|         h_param1 = int(i_hough_param1.value) | ||||
|         h_param2 = int(i_hough_param2.value) | ||||
|         h_inner_param1 = int(i_inner_hough_param1.value) | ||||
|         h_inner_param2 = int(i_inner_hough_param2.value) | ||||
|         h_min_radius = int(i_hough_min_radius.value) | ||||
|         h_max_radius = int(i_hough_max_radius.value) | ||||
|         inner_hough = bool(i_inner_hough.value) | ||||
|         color_channel = { | ||||
|             "all": None, | ||||
|             "red": 0, | ||||
|             "green": 1, | ||||
|             "blue": 2 | ||||
|         }[i_use_color_channel.value] | ||||
|  | ||||
|  | ||||
|     process_image(loaded_img, | ||||
|                   hough_min_dist=h_min_dist, | ||||
|                   hough_param1=h_param1, | ||||
|                   hough_param2=h_param2, | ||||
|                   minRadius=h_min_radius, | ||||
|                   maxRadius=h_max_radius, | ||||
|                   inner_hough_circles=True) | ||||
|  | ||||
|         process_image(loaded_img, | ||||
|                     hough_min_dist=h_min_dist, | ||||
|                     hough_param1=h_param1, | ||||
|                     hough_param2=h_param2, | ||||
|                     minRadius=h_min_radius, | ||||
|                     maxRadius=h_max_radius, | ||||
|                     inner_hough_param1=h_inner_param1, | ||||
|                     inner_hough_param2=h_inner_param2, | ||||
|                     inner_hough_circles=inner_hough, | ||||
|                     cell_colony_color_channel=color_channel) | ||||
|         app.toast("successfully processed image", title="info") | ||||
|  | ||||
|     except Exception as e: | ||||
|         for child in result_div.children: | ||||
|             child.destroy() | ||||
|         app.alert_danger(f"error while processing image: {str(e)}") | ||||
|  | ||||
| btn.onclick = on_click | ||||
|  | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| @ -1,5 +1,5 @@ | ||||
|  | ||||
| const pwa_version = "04_cell_detector_202306031006" | ||||
| const pwa_version = "04_cell_detector_202306041650" | ||||
| const assets = ["./index.html", | ||||
|     "./main.py", | ||||
|     "./resources/bootstrap.css", | ||||
| @ -48,4 +48,15 @@ self.addEventListener('fetch', event => { | ||||
|         return response; | ||||
|     })()); | ||||
| }); | ||||
| self.addEventListener('activate', (event) => { | ||||
|     event.waitUntil( | ||||
|         caches.keys().then((keyList) => { | ||||
|             return Promise.all(keyList.map((key) => { | ||||
|                 if(key !== pwa_version) { | ||||
|                     return caches.delete(key); | ||||
|                 } | ||||
|             })); | ||||
|         }) | ||||
|     ); | ||||
| }); | ||||
|      | ||||
| @ -68,6 +68,7 @@ class Element(object): | ||||
|         self._display = self.element.style.display | ||||
|         self.element.style.display = "none" | ||||
|  | ||||
|  | ||||
|     def show(self) -> None: | ||||
|         if self._display is None: | ||||
|             return | ||||
| @ -209,6 +210,27 @@ class Element(object): | ||||
|      | ||||
|     def write(self, object): | ||||
|         self.element.write(self.id, object) # type: ignore | ||||
|      | ||||
|     def set_style(self, property_name: str, value: str) -> None: | ||||
|         """Set a CSS style property on this element.""" | ||||
|         setattr(self._element.style, property_name, value) | ||||
|  | ||||
|     def get_style(self, property_name: str) -> str: | ||||
|         """Get the value of a CSS style property on this element.""" | ||||
|         try: | ||||
|             return getattr(self._element.style, property_name) | ||||
|         except AttributeError: | ||||
|             return None | ||||
|  | ||||
|     def remove_style(self, property_name: str) -> None: | ||||
|         """Remove a CSS style property from this element.""" | ||||
|         setattr(self._element.style, property_name, None) | ||||
|      | ||||
|     def set_styles(self, **styles) -> None: | ||||
|         """Set multiple CSS style properties on this element.""" | ||||
|         for property_name, value in styles.items(): | ||||
|             self.set_style(property_name, value) | ||||
|  | ||||
|  | ||||
|  | ||||
| class A(Element): | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -796,16 +796,22 @@ class Col(BootstrapContainer): | ||||
|                  class_name: str = None, | ||||
|                  parent: HTML.Element = None, | ||||
|                  col: int = None, | ||||
|                  col_xs: int = None, | ||||
|                  col_sm: int = None, | ||||
|                  col_md: int = None, | ||||
|                  col_lg: int = None, | ||||
|                  col_xl: int = None, | ||||
|                  col_xxl: int = None) -> None: | ||||
|  | ||||
|  | ||||
|         super().__init__(inner_html, id, class_name, parent) | ||||
|  | ||||
|  | ||||
|         if col is not None: | ||||
|             self.col = col | ||||
|  | ||||
|         super().__init__(inner_html, id, class_name, parent) | ||||
|         if col_xs is not None: | ||||
|             self.col_xs = col_xs | ||||
|  | ||||
|         if col_sm is not None: | ||||
|             self.col_sm = col_sm | ||||
| @ -1110,6 +1116,9 @@ class NavbarBrand(HTML.A, BootstrapContainer): | ||||
|                          parent=parent) | ||||
|  | ||||
|         self.set_attribute("href", href) | ||||
|         self.ms = 3 | ||||
|         self.me = 3 | ||||
|  | ||||
|  | ||||
|  | ||||
| class Navbar(BootstrapContainer): | ||||
|  | ||||
| @ -314,6 +314,15 @@ class BootstrapContainer(HTML.Div): | ||||
|     def text_align(self, value: Union[TextAlign, None]): | ||||
|         self._set_enum_property( | ||||
|             value=value, prefix="text-", enum_class=TextAlign, enum_values=_TEXT_ALIGNS) | ||||
|      | ||||
|     @property | ||||
|     def text_align_xs(self) -> Union[TextAlign, None]: | ||||
|         return self._get_enum_property(prefix="text-", enum_class=TextAlign, enum_values=_TEXT_ALIGNS, breakpoint="xs") | ||||
|  | ||||
|     @text_align_xs.setter | ||||
|     def text_align_xs(self, value: Union[TextAlign, None]): | ||||
|         self._set_enum_property(value=value, prefix="text-", | ||||
|                                 enum_class=TextAlign, enum_values=_TEXT_ALIGNS, breakpoint="xs") | ||||
|  | ||||
|     @property | ||||
|     def text_align_sm(self) -> Union[TextAlign, None]: | ||||
| @ -558,6 +567,15 @@ class BootstrapContainer(HTML.Div): | ||||
|     def display_property(self, value: Union[DisplayProperty, None]): | ||||
|         self._set_enum_property( | ||||
|             value=value, prefix="d-", enum_class=DisplayProperty, enum_values=_DISPLAY_PROPERTIES) | ||||
|      | ||||
|     @property | ||||
|     def display_property_xs(self) -> Union[DisplayProperty, None]: | ||||
|         return self._get_enum_property(prefix="d-", enum_class=DisplayProperty, enum_values=_DISPLAY_PROPERTIES, breakpoint="xs") | ||||
|  | ||||
|     @display_property_xs.setter | ||||
|     def display_property_xs(self, value: Union[DisplayProperty, None]): | ||||
|         self._set_enum_property(value=value, prefix="d-", enum_class=DisplayProperty, | ||||
|                                 enum_values=_DISPLAY_PROPERTIES, breakpoint="xs") | ||||
|  | ||||
|     @property | ||||
|     def display_property_sm(self) -> Union[DisplayProperty, None]: | ||||
| @ -1112,6 +1130,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @p.setter | ||||
|     def p(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("p-", value) | ||||
|      | ||||
|     @property | ||||
|     def p_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's padding for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("p-", "xs") | ||||
|  | ||||
|     @p_xs.setter | ||||
|     def p_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("p-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def p_sm(self) -> Union[int, str, None]: | ||||
| @ -1178,6 +1207,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @px.setter | ||||
|     def px(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("px-", value) | ||||
|      | ||||
|     @property | ||||
|     def px_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's horizontal padding for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("px-", "xs") | ||||
|  | ||||
|     @px_xs.setter | ||||
|     def px_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("px-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def px_sm(self) -> Union[int, str, None]: | ||||
| @ -1245,6 +1285,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     def py(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("py-", value) | ||||
|  | ||||
|     @property | ||||
|     def py_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's vertical padding for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("py-", "xs") | ||||
|  | ||||
|     @py_xs.setter | ||||
|     def py_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("py-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def py_sm(self) -> Union[int, str, None]: | ||||
|         """ | ||||
| @ -1311,6 +1362,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     def pt(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("pt-", value) | ||||
|  | ||||
|     @property | ||||
|     def pt_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's top padding for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("pt-", "xs") | ||||
|  | ||||
|     @pt_xs.setter | ||||
|     def pt_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("pt-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def pt_sm(self) -> Union[int, str, None]: | ||||
|         """ | ||||
| @ -1376,6 +1438,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @pb.setter | ||||
|     def pb(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("pb-", value) | ||||
|      | ||||
|     @property | ||||
|     def pb_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's bottom padding for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("pb-", "xs") | ||||
|  | ||||
|     @pb_xs.setter | ||||
|     def pb_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("pb-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def pb_sm(self) -> Union[int, str, None]: | ||||
| @ -1442,6 +1515,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @ps.setter | ||||
|     def ps(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("ps-", value) | ||||
|      | ||||
|     @property | ||||
|     def ps_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's start padding (left for LTR languages) for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("ps-", "xs") | ||||
|  | ||||
|     @ps_xs.setter | ||||
|     def ps_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("ps-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def ps_sm(self) -> Union[int, str, None]: | ||||
| @ -1508,6 +1592,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @pe.setter | ||||
|     def pe(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("pe-", value) | ||||
|      | ||||
|     @property | ||||
|     def pe_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's end padding (right for LTR languages) for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("pe-", "xs") | ||||
|  | ||||
|     @pe_xs.setter | ||||
|     def pe_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("pe-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def pe_sm(self) -> Union[int, str, None]: | ||||
| @ -1576,6 +1671,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @m.setter | ||||
|     def m(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("m-", value) | ||||
|      | ||||
|     @property | ||||
|     def m_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's margin for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("m-", "xs") | ||||
|  | ||||
|     @m_xs.setter | ||||
|     def m_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("m-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def m_sm(self) -> Union[int, str, None]: | ||||
| @ -1642,6 +1748,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @mx.setter | ||||
|     def mx(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("mx-", value) | ||||
|      | ||||
|     @property | ||||
|     def mx_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's margin-left and margin-right for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("mx-", "xs") | ||||
|  | ||||
|     @mx_xs.setter | ||||
|     def mx_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("mx-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def mx_sm(self) -> Union[int, str, None]: | ||||
| @ -1708,6 +1825,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @my.setter | ||||
|     def my(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("my-", value) | ||||
|      | ||||
|     @property | ||||
|     def my_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's margin-top and margin-bottom for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("my-", "xs") | ||||
|  | ||||
|     @my_xs.setter | ||||
|     def my_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("my-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def my_sm(self) -> Union[int, str, None]: | ||||
| @ -1774,6 +1902,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @mt.setter | ||||
|     def mt(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("mt-", value) | ||||
|      | ||||
|     @property | ||||
|     def mt_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's margin-top for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("mt-", "xs") | ||||
|  | ||||
|     @mt_xs.setter | ||||
|     def mt_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("mt-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def mt_sm(self) -> Union[int, str, None]: | ||||
| @ -1840,6 +1979,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @mb.setter | ||||
|     def mb(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("mb-", value) | ||||
|      | ||||
|     @property | ||||
|     def mb_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's margin-bottom for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("mb-", "xs") | ||||
|  | ||||
|     @mb_xs.setter | ||||
|     def mb_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("mb-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def mb_sm(self) -> Union[int, str, None]: | ||||
| @ -1907,6 +2057,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     def ms(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("ms-", value) | ||||
|  | ||||
|     @property | ||||
|     def ms_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's start margin (left for LTR languages) for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("ms-", "xs") | ||||
|  | ||||
|     @ms_xs.setter | ||||
|     def ms_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("ms-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def ms_sm(self) -> Union[int, str, None]: | ||||
|         """ | ||||
| @ -1972,6 +2133,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @me.setter | ||||
|     def me(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("me-", value) | ||||
|      | ||||
|     @property | ||||
|     def me_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         element's end margin (right for LTR languages) for small screens. By default, bootstrap defines the values 0,1,2,3,4,5,auto | ||||
|         """ | ||||
|         return self._get_css_param_number("me-", "xs") | ||||
|  | ||||
|     @me_xs.setter | ||||
|     def me_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("me-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def me_sm(self) -> Union[int, str, None]: | ||||
| @ -2041,6 +2213,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     def g(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("g-", value) | ||||
|  | ||||
|     @property | ||||
|     def g_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         gutter (gutters are the space between the element and its content) for small screens. By default, bootstrap defines the values 0,1,2,3,4,5 | ||||
|         """ | ||||
|         return self._get_css_param_number("g-", "xs") | ||||
|  | ||||
|     @g_xs.setter | ||||
|     def g_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("g-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def g_sm(self) -> Union[int, str, None]: | ||||
|         """ | ||||
| @ -2107,6 +2290,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     def gx(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("gx-", value) | ||||
|  | ||||
|     @property | ||||
|     def gx_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         horizontal gutter (gutters are the space between the element and its content) for small screens. By default, bootstrap defines the values 0,1,2,3,4,5 | ||||
|         """ | ||||
|         return self._get_css_param_number("gx-", "xs") | ||||
|  | ||||
|     @gx_xs.setter | ||||
|     def gx_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("gx-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def gx_sm(self) -> Union[int, str, None]: | ||||
|         """ | ||||
| @ -2173,6 +2367,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     def gy(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("gy-", value) | ||||
|  | ||||
|     @property | ||||
|     def gy_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         vertical gutter (gutters are the space between the element and its content) for small screens. By default, bootstrap defines the values 0,1,2,3,4,5 | ||||
|         """ | ||||
|         return self._get_css_param_number("gy-", "xs") | ||||
|  | ||||
|     @gy_xs.setter | ||||
|     def gy_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("gy-", value, "xs") | ||||
|  | ||||
|     @property | ||||
|     def gy_sm(self) -> Union[int, str, None]: | ||||
|         """ | ||||
| @ -2240,6 +2445,17 @@ class BootstrapContainer(HTML.Div): | ||||
|     @col.setter | ||||
|     def col(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("col-", value) | ||||
|  | ||||
|     @property | ||||
|     def col_xs(self) -> Union[int, str, None]: | ||||
|         """ | ||||
|         column class for very small screens. By default, bootstrap defines the values 1,2,3,4,5,6,7,8,9,10,11,12 | ||||
|         """ | ||||
|         return self._get_css_param_number("col-", "xs") | ||||
|      | ||||
|     @col_xs.setter | ||||
|     def col_xs(self, value: Union[int, str, None]): | ||||
|         self._set_css_param_number("col-", value, "xs") | ||||
|      | ||||
|     @property | ||||
|     def col_sm(self) -> Union[int, str, None]: | ||||
|  | ||||
| @ -10,20 +10,112 @@ class PyScriptBootstrapApp(object): | ||||
|         self._main_div.vh_100 = True | ||||
|  | ||||
|         self._main_div.p = 0 | ||||
|         self._main_div.m = 0 | ||||
|  | ||||
|         self._main_div.col_xs = 12 | ||||
|         self._main_div.col = 12 | ||||
|  | ||||
|  | ||||
|  | ||||
|         self._parent_element = document.getElementById(parent_element) | ||||
|         self._parent_element.appendChild(self._main_div.element) | ||||
|  | ||||
|         self._toast_container = bHTML.ToastContainer(parent=self._main_div) | ||||
|         self._toast_container.position_end = 0 | ||||
|         self._toast_container.position_bottom = 0 | ||||
|  | ||||
|         self._alert_container = bHTML.BootstrapContainer(parent=self._main_div) | ||||
|         self._alert_container.position_end = 0 | ||||
|         self._alert_container.position_bottom = 0 | ||||
|         self._alert_container.position = bHTML.Position.ABSOLUTE | ||||
|      | ||||
|     def _alert(self, message: str, alert_class: type): | ||||
|         return alert_class(message, parent=self._alert_container) | ||||
|         bHTML.Al | ||||
|  | ||||
|     @property | ||||
|     def main(self) -> HTML.Div: | ||||
|         return self._main_div | ||||
|      | ||||
|     @property | ||||
|     def toast_container(self) -> bHTML.ToastContainer: | ||||
|         return self._toast_container | ||||
|      | ||||
|     @property | ||||
|     def alert_container(self) -> bHTML.BootstrapContainer: | ||||
|         return self._alert_container | ||||
|      | ||||
|     def toast(self, message: str, title: str, animation: bool = True, show: bool = True) -> bHTML.Toast: | ||||
|         """ | ||||
|         show a toast on the default toast location (bottom right) | ||||
|         """ | ||||
|         toast = bHTML.Toast(inner_html=message, title=title, parent=self._toast_container) | ||||
|         toast.animation = animation | ||||
|         if show: | ||||
|             toast.show() | ||||
|         return toast | ||||
|      | ||||
|     def alert(self, message:str) -> bHTML.Alert: | ||||
|         """ | ||||
|         show an alert on the default alert location (bottom right) | ||||
|         """ | ||||
|         return self._alert(message, bHTML.Alert) | ||||
|      | ||||
|     def alert_success(self, message:str) -> bHTML.AlertSuccess: | ||||
|         """ | ||||
|         show an alert on the default alert location (bottom right) | ||||
|         """ | ||||
|         return self._alert(message, bHTML.AlertSuccess) | ||||
|      | ||||
|     def alert_info(self, message:str) -> bHTML.AlertInfo: | ||||
|         """ | ||||
|         show an alert on the default alert location (bottom right) | ||||
|         """ | ||||
|         return self._alert(message, bHTML.AlertInfo) | ||||
|  | ||||
|     def alert_warning(self, message:str) -> bHTML.AlertWarning: | ||||
|         """ | ||||
|         show an alert on the default alert location (bottom right) | ||||
|         """ | ||||
|         return self._alert(message, bHTML.AlertWarning) | ||||
|      | ||||
|     def alert_danger(self, message:str) -> bHTML.AlertDanger: | ||||
|         """ | ||||
|         show an alert on the default alert location (bottom right) | ||||
|         """ | ||||
|         return self._alert(message, bHTML.AlertDanger) | ||||
|  | ||||
|     def alert_primary(self, message:str) -> bHTML.AlertPrimary: | ||||
|         """ | ||||
|         show an alert on the default alert location (bottom right) | ||||
|         """ | ||||
|         return self._alert(message, bHTML.AlertPrimary) | ||||
|  | ||||
|     def alert_secondary(self, message:str) -> bHTML.AlertSecondary: | ||||
|         """ | ||||
|         show an alert on the default alert location (bottom right) | ||||
|         """ | ||||
|         return self._alert(message, bHTML.AlertSecondary) | ||||
|  | ||||
|     def alert_light(self, message:str) -> bHTML.AlertLight: | ||||
|         """ | ||||
|         show an alert on the default alert location (bottom right) | ||||
|         """ | ||||
|         return self._alert(message, bHTML.AlertLight) | ||||
|      | ||||
|     def alert_dark(self, message:str) -> bHTML.AlertDark: | ||||
|         """ | ||||
|         show an alert on the default alert location (bottom right) | ||||
|         """ | ||||
|         return self._alert(message, bHTML.AlertDark) | ||||
|  | ||||
| class PyScriptBootstrapDashboard(PyScriptBootstrapApp): | ||||
|     def __init__(self, parent_element:str = "pyscript_app", brand_name = "Dashboard"): | ||||
|  | ||||
|         super().__init__(parent_element) | ||||
|  | ||||
|         self._sidebar = bHTML.Col(id="sidebar", col_sm=5, col_md=4, col_lg=3, col_xl=3) | ||||
|         self._sidebar = bHTML.Col(id="sidebar", col=12, col_sm=12, col_md=4, col_lg=3, col_xl=3) | ||||
|         self._sidebar.style = {"height": "100vh", "overflow": "auto"} | ||||
|  | ||||
|         self._navbar = bHTML.NavbarDark( | ||||
|             parent=self._main_div, | ||||
| @ -32,13 +124,30 @@ class PyScriptBootstrapDashboard(PyScriptBootstrapApp): | ||||
|             toggle_button_for_target=self.sidebar | ||||
|         ) | ||||
|  | ||||
|         self._navbar.position = bHTML.Position.STICKY_TOP | ||||
|         self._navbar.w = 100 | ||||
|         self._navbar.position = bHTML.Position.FIXED_TOP | ||||
|         self._navbar.height = "4em" | ||||
|         self._navbar.ps = 5 | ||||
|         self._navbar.pe = 5 | ||||
|         self._navbar.col = 12 | ||||
|  | ||||
|          | ||||
|         top_margin_dummy = bHTML.BootstrapContainer(id="top_margin_dummy", parent=self._main_div) | ||||
|         top_margin_dummy.height = "3.5em" # have it slightly less high than navbar | ||||
|         top_margin_dummy.width = "100vw" | ||||
|         top_margin_dummy.m = 0 | ||||
|         top_margin_dummy.p = 0 | ||||
|  | ||||
|  | ||||
|         row = bHTML.Row(parent=self._main_div) | ||||
|         row.h = 100 | ||||
|         row.w = 100 | ||||
|  | ||||
|         row.height = "calc(100vh - 4em)" | ||||
|         row.p = 0 | ||||
|         row.m = 0 | ||||
|         row.col_xs = 12 | ||||
|         row.col = 12 | ||||
|  | ||||
|  | ||||
|         row.display_property = bHTML.DisplayProperty.INLINE_FLEX | ||||
|  | ||||
|         row.append_child(self.sidebar) | ||||
| @ -49,17 +158,19 @@ class PyScriptBootstrapDashboard(PyScriptBootstrapApp): | ||||
|         self._sidebar.position = bHTML.Position.STATIC | ||||
|         self._sidebar.collapsable = True | ||||
|         self._sidebar.mw = 100 | ||||
|         self._sidebar.height = "calc(100vh - 4em)" | ||||
|         self._sidebar.shadow = bHTML.Shadow.LARGE | ||||
|         self._sidebar.overflow = bHTML.Overflow.HIDDEN | ||||
|         self._sidebar.overflow = bHTML.Overflow.SCROLL | ||||
|          | ||||
|  | ||||
|  | ||||
|         self._modal = bHTML.Modal(parent=self._main_div, title="Modal") | ||||
|  | ||||
|         self._main_area = bHTML.Col(id="main_area", parent=row, col_lg=9, col_xl=9) | ||||
|         self._main_area = bHTML.Col(id="main_area", parent=row, col=12, col_sm=12, col_md=8, col_lg=9, col_xl=9) | ||||
|          | ||||
|         self._main_area.p = 4 | ||||
|         self._main_area.overflow = bHTML.Overflow.HIDDEN | ||||
|         #self._main_area.vh_100 = True | ||||
|         self._main_area.overflow = bHTML.Overflow.SCROLL | ||||
|         self._main_area.height = "calc(100vh - 4em)" | ||||
|         self._main_area.mw = 100 | ||||
|      | ||||
|     def show_modal(self): | ||||
|  | ||||
| @ -106,6 +106,17 @@ self.addEventListener('fetch', event => {{ | ||||
|  | ||||
|         return response; | ||||
|     }})()); | ||||
| }}); | ||||
| self.addEventListener('activate', (event) => {{ | ||||
|     event.waitUntil( | ||||
|         caches.keys().then((keyList) => {{ | ||||
|             return Promise.all(keyList.map((key) => {{ | ||||
|                 if(key !== pwa_version) {{ | ||||
|                     return caches.delete(key); | ||||
|                 }} | ||||
|             }})); | ||||
|         }}) | ||||
|     ); | ||||
| }}); | ||||
|     """ | ||||
|  | ||||
| @ -306,7 +317,7 @@ def main(): | ||||
|     argument_parser.add_argument("--bootstrap-js-url", type=str, | ||||
|                                     help="the url of the bootstrap js file", default="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js") | ||||
|     argument_parser.add_argument("--pyscript-bootstrap-templates-wheel-url", type=str, | ||||
|                                     help="the url of the pyscript bootstrap templates wheel file", default="https://the-cake-is-a-lie.net/gogs/jonas/pyscript-bootstrap-templates/raw/branch/main/dist/pyscript_bootstrap_templates-0.1.0-py3-none-any.whl") | ||||
|                                     help="the url of the pyscript bootstrap templates wheel file", default="https://the-cake-is-a-lie.net/gogs/jonas/pyscript-bootstrap-templates/raw/branch/main/dist/pyscript_bootstrap_templates-0.2.0-py3-none-any.whl") | ||||
|     argument_parser.add_argument("--pwa-bg-color", type=str, help="background color for pwa configuration", default="#000000") | ||||
|     argument_parser.add_argument("--pwa-theme-color", type=str, help="theme color for pwa configuration", default="#ffffff") | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user