instaui 0.1.4__py3-none-any.whl → 0.1.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. instaui/arco/__init__.py +191 -0
  2. instaui/arco/_settings.py +25 -0
  3. instaui/arco/_use_tools/locale.py +50 -0
  4. instaui/arco/component_types.py +1019 -0
  5. instaui/arco/components/_utils.py +22 -0
  6. instaui/arco/components/affix.py +29 -0
  7. instaui/arco/components/alert.py +42 -0
  8. instaui/arco/components/anchor.py +42 -0
  9. instaui/arco/components/auto_complete.py +96 -0
  10. instaui/arco/components/avatar.py +55 -0
  11. instaui/arco/components/back_top.py +14 -0
  12. instaui/arco/components/badge.py +14 -0
  13. instaui/arco/components/breadcrumb.py +14 -0
  14. instaui/arco/components/button.py +43 -0
  15. instaui/arco/components/calendar.py +47 -0
  16. instaui/arco/components/card.py +14 -0
  17. instaui/arco/components/carousel.py +33 -0
  18. instaui/arco/components/cascader.py +111 -0
  19. instaui/arco/components/checkbox.py +32 -0
  20. instaui/arco/components/collapse.py +31 -0
  21. instaui/arco/components/color_picker.py +45 -0
  22. instaui/arco/components/comment.py +14 -0
  23. instaui/arco/components/config_provider.py +13 -0
  24. instaui/arco/components/date_picker.py +111 -0
  25. instaui/arco/components/descriptions.py +14 -0
  26. instaui/arco/components/divider.py +13 -0
  27. instaui/arco/components/drawer.py +98 -0
  28. instaui/arco/components/dropdown.py +45 -0
  29. instaui/arco/components/empty.py +14 -0
  30. instaui/arco/components/form.py +55 -0
  31. instaui/arco/components/icon.py +17 -0
  32. instaui/arco/components/image.py +33 -0
  33. instaui/arco/components/input.py +102 -0
  34. instaui/arco/components/input_number.py +97 -0
  35. instaui/arco/components/input_password.py +38 -0
  36. instaui/arco/components/input_search.py +37 -0
  37. instaui/arco/components/input_tag.py +110 -0
  38. instaui/arco/components/layout.py +13 -0
  39. instaui/arco/components/layout_content.py +6 -0
  40. instaui/arco/components/layout_footer.py +6 -0
  41. instaui/arco/components/layout_header.py +6 -0
  42. instaui/arco/components/layout_sider.py +53 -0
  43. instaui/arco/components/link.py +36 -0
  44. instaui/arco/components/list.py +68 -0
  45. instaui/arco/components/mention.py +97 -0
  46. instaui/arco/components/menu.py +88 -0
  47. instaui/arco/components/modal.py +97 -0
  48. instaui/arco/components/overflow_list.py +29 -0
  49. instaui/arco/components/page_header.py +29 -0
  50. instaui/arco/components/pagination.py +45 -0
  51. instaui/arco/components/pop_confirm.py +58 -0
  52. instaui/arco/components/popover.py +32 -0
  53. instaui/arco/components/progress.py +14 -0
  54. instaui/arco/components/radio.py +40 -0
  55. instaui/arco/components/radio_group.py +42 -0
  56. instaui/arco/components/rate.py +45 -0
  57. instaui/arco/components/resize_box.py +62 -0
  58. instaui/arco/components/result.py +14 -0
  59. instaui/arco/components/select.py +179 -0
  60. instaui/arco/components/skeleton.py +14 -0
  61. instaui/arco/components/slider.py +38 -0
  62. instaui/arco/components/space.py +14 -0
  63. instaui/arco/components/spin.py +14 -0
  64. instaui/arco/components/split.py +76 -0
  65. instaui/arco/components/statistic.py +14 -0
  66. instaui/arco/components/steps.py +32 -0
  67. instaui/arco/components/switch.py +57 -0
  68. instaui/arco/components/tab_pane.py +12 -0
  69. instaui/arco/components/table.py +276 -0
  70. instaui/arco/components/tabs.py +101 -0
  71. instaui/arco/components/tag.py +42 -0
  72. instaui/arco/components/textarea.py +84 -0
  73. instaui/arco/components/time_picker.py +76 -0
  74. instaui/arco/components/timeline.py +14 -0
  75. instaui/arco/components/tooltip.py +29 -0
  76. instaui/arco/components/transfer.py +58 -0
  77. instaui/arco/components/tree.py +120 -0
  78. instaui/arco/components/tree_select.py +86 -0
  79. instaui/arco/components/trigger.py +58 -0
  80. instaui/arco/components/typography.py +142 -0
  81. instaui/arco/components/upload.py +71 -0
  82. instaui/arco/components/verification_code.py +58 -0
  83. instaui/arco/components/watermark.py +14 -0
  84. instaui/arco/locales/__init__.py +4 -0
  85. instaui/arco/locales/_index.py +31 -0
  86. instaui/arco/locales/en_us.py +227 -0
  87. instaui/arco/locales/zh_cn.py +224 -0
  88. instaui/arco/setup.py +36 -0
  89. instaui/arco/static/instaui-arco.css +1 -0
  90. instaui/arco/static/instaui-arco.js +55771 -0
  91. instaui/arco/types.py +24 -0
  92. instaui/components/column.py +10 -2
  93. instaui/components/echarts/echarts.js +128 -0
  94. instaui/components/echarts/echarts.py +194 -0
  95. instaui/components/echarts/static/echarts.esm.min.js +45 -0
  96. instaui/components/element.py +50 -6
  97. instaui/components/grid.py +81 -0
  98. instaui/components/html/__init__.py +30 -19
  99. instaui/components/html/_preset.py +4 -0
  100. instaui/components/html/heading.py +51 -0
  101. instaui/components/html/range.py +3 -0
  102. instaui/components/html/select.py +13 -31
  103. instaui/components/html/table.py +36 -0
  104. instaui/components/markdown/static/github-markdown.css +1 -1
  105. instaui/components/markdown/static/marked.esm.js +0 -1
  106. instaui/components/row.py +8 -7
  107. instaui/components/shiki_code/shiki_code.js +126 -0
  108. instaui/components/shiki_code/shiki_code.py +99 -0
  109. instaui/components/shiki_code/static/langs/css.mjs +5 -0
  110. instaui/components/shiki_code/static/langs/markdown.mjs +5 -0
  111. instaui/components/shiki_code/static/langs/python.mjs +5 -0
  112. instaui/components/shiki_code/static/langs/shell.mjs +2 -0
  113. instaui/components/shiki_code/static/langs/shellscript.mjs +5 -0
  114. instaui/components/shiki_code/static/shiki-core.js +5784 -0
  115. instaui/components/shiki_code/static/shiki-style.css +179 -0
  116. instaui/components/shiki_code/static/shiki-transformers.js +461 -0
  117. instaui/components/shiki_code/static/themes/vitesse-dark.mjs +2 -0
  118. instaui/components/shiki_code/static/themes/vitesse-light.mjs +2 -0
  119. instaui/components/value_element.py +7 -3
  120. instaui/consts.py +2 -1
  121. instaui/event/js_event.py +1 -0
  122. instaui/event/web_event.py +6 -7
  123. instaui/experimental/link_sql/__init__.py +3 -0
  124. instaui/experimental/link_sql/_base.py +23 -0
  125. instaui/experimental/link_sql/_duckdb.py +221 -0
  126. instaui/experimental/link_sql/_types.py +15 -0
  127. instaui/experimental/link_sql/data_source.js +50 -0
  128. instaui/fastapi_server/debug_mode_router.py +1 -1
  129. instaui/fastapi_server/server.py +4 -12
  130. instaui/handlers/event_handler.py +3 -1
  131. instaui/handlers/watch_handler.py +4 -0
  132. instaui/html_tools.py +41 -4
  133. instaui/runtime/_app.py +37 -3
  134. instaui/runtime/_link_manager.py +89 -0
  135. instaui/runtime/resource.py +19 -9
  136. instaui/runtime/scope.py +28 -7
  137. instaui/shadcn_classless/_index.py +42 -0
  138. instaui/shadcn_classless/static/shadcn-classless.css +403 -0
  139. instaui/static/insta-ui.css +1 -1
  140. instaui/static/insta-ui.esm-browser.prod.js +3663 -3658
  141. instaui/static/insta-ui.js.map +1 -1
  142. instaui/static/instaui-tools-browser.js +511 -0
  143. instaui/static/templates/debug/sse.html +1 -1
  144. instaui/static/templates/webview.html +78 -0
  145. instaui/tailwind/__init__.py +6 -0
  146. instaui/tailwind/_index.py +24 -0
  147. instaui/{static/tailwindcss.min.js → tailwind/static/tailwindcss-v3.min.js} +62 -62
  148. instaui/tailwind/static/tailwindcss-v4.min.js +8 -0
  149. instaui/template/_utils.py +23 -0
  150. instaui/template/webview_template.py +50 -0
  151. instaui/ui/__init__.py +8 -2
  152. instaui/ui/__init__.pyi +7 -1
  153. instaui/ui_functions/ui_page.py +1 -1
  154. instaui/vars/data.py +7 -7
  155. instaui/vars/element_ref.py +2 -4
  156. instaui/vars/event_context.py +4 -0
  157. instaui/vars/js_computed.py +6 -8
  158. instaui/vars/ref.py +6 -6
  159. instaui/vars/vue_computed.py +6 -7
  160. instaui/vars/web_computed.py +31 -32
  161. instaui/watch/vue_watch.py +23 -7
  162. instaui/watch/web_watch.py +5 -6
  163. instaui/webview/__init__.py +1 -0
  164. instaui/webview/_utils.py +8 -0
  165. instaui/webview/api.py +72 -0
  166. instaui/webview/func.py +114 -0
  167. instaui/webview/index.py +162 -0
  168. instaui/webview/resource.py +172 -0
  169. instaui/zero/func.py +19 -12
  170. instaui/zero/scope.py +29 -28
  171. {instaui-0.1.4.dist-info → instaui-0.1.6.dist-info}/METADATA +6 -2
  172. instaui-0.1.6.dist-info/RECORD +286 -0
  173. instaui/components/highlight_code/code.js +0 -63
  174. instaui/components/highlight_code/code.py +0 -117
  175. instaui/components/highlight_code/static/core.min.js +0 -307
  176. instaui/components/highlight_code/static/languages/css.min.js +0 -31
  177. instaui/components/highlight_code/static/languages/javascript.min.js +0 -81
  178. instaui/components/highlight_code/static/languages/json.min.js +0 -8
  179. instaui/components/highlight_code/static/languages/python-repl.min.js +0 -5
  180. instaui/components/highlight_code/static/languages/python.min.js +0 -42
  181. instaui/components/highlight_code/static/languages/shell.min.js +0 -5
  182. instaui/components/highlight_code/static/styles/default.min.css +0 -9
  183. instaui/components/highlight_code/static/styles/github-dark-dimmed.min.css +0 -9
  184. instaui/components/highlight_code/static/styles/github-dark.min.css +0 -10
  185. instaui/components/highlight_code/static/styles/github.min.css +0 -10
  186. instaui/daisyui/__init__.py +0 -20
  187. instaui/daisyui/_index.py +0 -15
  188. instaui/daisyui/button.py +0 -38
  189. instaui/daisyui/checkbox.py +0 -17
  190. instaui/daisyui/static/daisyui.css +0 -1
  191. instaui/daisyui/static/themes.css +0 -1
  192. instaui/handlers/computed_handler.py +0 -42
  193. instaui/handlers/config_handler.py +0 -13
  194. instaui/ui/__build_init.py +0 -73
  195. instaui/vars/_utils.py +0 -12
  196. instaui-0.1.4.dist-info/RECORD +0 -179
  197. {instaui-0.1.4.dist-info → instaui-0.1.6.dist-info}/LICENSE +0 -0
  198. {instaui-0.1.4.dist-info → instaui-0.1.6.dist-info}/WHEEL +0 -0
@@ -0,0 +1,114 @@
1
+ from __future__ import annotations
2
+ import itertools
3
+ from pathlib import Path
4
+ import instaui.consts as consts
5
+ from instaui.runtime._app import get_app_slot, get_default_app_slot
6
+ from instaui.template import render_zero_html
7
+ from instaui.template import zero_template
8
+ from instaui.html_tools import to_config_data
9
+ from instaui.runtime.dataclass import JsLink
10
+ from instaui.runtime.resource import HtmlResource
11
+
12
+
13
+ def get_template_model():
14
+ system_slot = get_app_slot()
15
+
16
+ merge_global_resources = (system_slot.meta or {}).get(
17
+ "merge_global_resources", True
18
+ )
19
+
20
+ default_app_slot = get_default_app_slot()
21
+ html_resource = system_slot._html_resource
22
+ default_html_resource = (
23
+ default_app_slot._html_resource
24
+ if merge_global_resources
25
+ else _empty_html_resource()
26
+ )
27
+
28
+ config_data = to_config_data()
29
+
30
+ model = zero_template.ZeroTemplateModel(
31
+ vue_js_code=consts.VUE_ES_JS_PATH,
32
+ instaui_js_code=consts.APP_ES_JS_PATH,
33
+ css_links=[
34
+ consts.APP_CSS_PATH,
35
+ ],
36
+ config_dict=config_data,
37
+ favicon=html_resource.favicon
38
+ or default_html_resource.favicon
39
+ or consts.FAVICON_PATH,
40
+ title=html_resource.title or default_html_resource.title or consts.PAGE_TITLE,
41
+ )
42
+
43
+ # register custom components
44
+ for component in system_slot._component_dependencies:
45
+ if not component.esm:
46
+ continue
47
+
48
+ model.vue_app_component.append(
49
+ zero_template.ZeroVueAppComponent(
50
+ name=component.tag_name,
51
+ url=component.esm,
52
+ )
53
+ )
54
+
55
+ if component.css:
56
+ for css_link in component.css:
57
+ model.css_links.append(css_link)
58
+
59
+ if component.externals:
60
+ for name, url in component.externals.items():
61
+ if url.is_file():
62
+ model.add_extra_import_map(name, url)
63
+
64
+ # register custom plugins
65
+ for plugin in set(
66
+ itertools.chain(
67
+ system_slot._plugin_dependencies, default_app_slot._plugin_dependencies
68
+ )
69
+ ):
70
+ if not plugin.esm:
71
+ continue
72
+
73
+ model.vue_app_use.append(plugin.name)
74
+
75
+ model.add_extra_import_map(plugin.name, plugin.esm)
76
+
77
+ if plugin.css:
78
+ for css_link in plugin.css:
79
+ model.css_links.append(css_link)
80
+
81
+ # css file link to web static link
82
+ for link in html_resource.get_valid_css_links(
83
+ default_html_resource._css_links_manager
84
+ ):
85
+ if isinstance(link, Path):
86
+ model.css_links.append(link)
87
+
88
+ # js file link to web static link
89
+ for info in html_resource.get_valid_js_links(
90
+ default_html_resource._js_links_manager
91
+ ):
92
+ if isinstance(info.link, Path):
93
+ model.js_links.append(JsLink(info.link))
94
+
95
+ for js_code in itertools.chain(
96
+ html_resource._script_tags, default_html_resource._script_tags
97
+ ):
98
+ model.script_tags.append(js_code)
99
+
100
+ for sylte_code in itertools.chain(
101
+ html_resource._style_tags, default_html_resource._style_tags
102
+ ):
103
+ model.style_tags.append(sylte_code)
104
+
105
+ return model
106
+
107
+
108
+ def to_html_str():
109
+ model = get_template_model()
110
+ return render_zero_html(model)
111
+
112
+
113
+ def _empty_html_resource():
114
+ return HtmlResource()
@@ -0,0 +1,162 @@
1
+ from __future__ import annotations
2
+ from contextlib import contextmanager
3
+ from pathlib import Path
4
+ import shutil
5
+ from typing import Any, Callable, Dict, Iterable, List, Optional, Union
6
+ from typing_extensions import TypedDict, Unpack
7
+ import webview
8
+ import webview.http as http
9
+ from webview.guilib import GUIType
10
+
11
+ from instaui.runtime._app import get_app_slot, new_app_slot, reset_app_slot
12
+ from instaui.launch_collector import get_launch_collector
13
+
14
+ from . import resource
15
+ from . import api
16
+ from . import _utils
17
+
18
+
19
+ class WebviewWrapper:
20
+ """Example usage:
21
+ .. code-block:: python
22
+ from instaui import ui
23
+
24
+ @ui.page("/")
25
+ def index_page():
26
+ ui.content("Hello, world!")
27
+
28
+ ui.webview().run()
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ *,
34
+ assets_path: Union[str, Path] = "./webview_assets",
35
+ debug: bool = False,
36
+ auto_create_window: Union[bool, str] = "/",
37
+ on_app_mounted: Optional[Callable] = None,
38
+ ) -> None:
39
+ """Create a new webview wrapper.
40
+
41
+ Args:
42
+ assets_path (Union[str, Path], optional): Path to store assets. Defaults to "./webview_assets".
43
+ debug (bool, optional): Whether to run in debug mode. Defaults to False.
44
+ auto_create_window (Union[bool, str], optional): Whether to create a window automatically. If a string is provided, it will be used as the initial page URL. Defaults to "/".
45
+ testing (bool, optional): Whether to run in testing mode. Defaults to False.
46
+ """
47
+
48
+ self.assets_path = (
49
+ Path(self._get_assets_path(assets_path))
50
+ if isinstance(assets_path, str)
51
+ else assets_path
52
+ )
53
+ _utils.reset_dir(self.assets_path)
54
+ self.debug = debug
55
+ self.on_app_mounted = on_app_mounted
56
+
57
+ self._auto_create_window = auto_create_window
58
+
59
+ def create_window(
60
+ self,
61
+ page_url: str = "/",
62
+ ):
63
+ """Create a new window. Returns the window object of pywebview.
64
+
65
+ Args:
66
+ page_url (str, optional): Page URL to load. Defaults to "/".
67
+
68
+ """
69
+ launch_collector = get_launch_collector()
70
+ with _scope():
71
+ app = get_app_slot()
72
+ app._page_path = page_url
73
+ page_info = launch_collector._page_router[page_url]
74
+ page_info.func()
75
+
76
+ resource_info = resource.resource_to_assets(
77
+ page_url=page_url,
78
+ assets_path=self.assets_path,
79
+ on_app_mounted=self.on_app_mounted,
80
+ )
81
+
82
+ window = webview.create_window(
83
+ resource_info.title, resource_info.index_html_url, js_api=api.Api()
84
+ )
85
+
86
+ if self.on_app_mounted:
87
+
88
+ def on_app_mounted():
89
+ self.on_app_mounted(window) # type: ignore
90
+
91
+ window.expose(on_app_mounted)
92
+
93
+ return window
94
+
95
+ def run(self, **webview_start_args: Unpack[WebviewStartArgs]):
96
+ """Run the webview.
97
+
98
+ Args:
99
+ :param func: Function to invoke upon starting the GUI loop.
100
+ :param args: Function arguments. Can be either a single value or a tuple of
101
+ values.
102
+ :param localization: A dictionary with localized strings. Default strings
103
+ and their keys are defined in localization.py.
104
+ :param gui: Force a specific GUI. Allowed values are ``cef``, ``qt``,
105
+ ``gtk``, ``mshtml`` or ``edgechromium`` depending on a platform.
106
+ :param http_server: Enable built-in HTTP server. If enabled, local files
107
+ will be served using a local HTTP server on a random port. For each
108
+ window, a separate HTTP server is spawned. This option is ignored for
109
+ non-local URLs.
110
+ :param user_agent: Change user agent string.
111
+ :param private_mode: Enable private mode. In private mode, cookies and local storage are not preserved.
112
+ Default is True.
113
+ :param storage_path: Custom location for cookies and other website data
114
+ :param menu: List of menus to be included in the app menu
115
+ :param server: Server class. Defaults to BottleServer
116
+ :param server_args: Dictionary of arguments to pass through to the server instantiation
117
+ :param ssl: Enable SSL for local HTTP server. Default is False.
118
+ :param icon: Path to the icon file. Supported only on GTK/QT.
119
+ """
120
+
121
+ if self._auto_create_window:
122
+ self.create_window(
123
+ "/" if self._auto_create_window is True else self._auto_create_window
124
+ )
125
+
126
+ webview.start(**webview_start_args, debug=self.debug)
127
+
128
+ @staticmethod
129
+ def _get_assets_path(file: Union[str, Path]) -> Path:
130
+ if isinstance(file, str):
131
+ import inspect
132
+
133
+ frame = inspect.currentframe().f_back.f_back.f_back # type: ignore
134
+ assert frame is not None
135
+ script_file = inspect.getfile(frame)
136
+ file = Path(script_file).parent.joinpath(file)
137
+
138
+ return file
139
+
140
+
141
+ @contextmanager
142
+ def _scope():
143
+ token = new_app_slot("webview")
144
+ yield
145
+ reset_app_slot(token)
146
+
147
+
148
+ class WebviewStartArgs(TypedDict, total=False):
149
+ func: Union[Callable[..., None], None]
150
+ args: Union[Iterable[Any], None]
151
+ localization: Dict[str, str]
152
+ gui: Union[GUIType, None]
153
+ http_server: bool
154
+ http_port: Union[int, None]
155
+ user_agent: Union[str, None]
156
+ private_mode: bool
157
+ storage_path: Union[str, None]
158
+ menu: List[Any]
159
+ server: type[http.ServerType] # type: ignore
160
+ server_args: Dict[Any, Any]
161
+ ssl: bool
162
+ icon: Union[str, None]
@@ -0,0 +1,172 @@
1
+ from dataclasses import dataclass
2
+ import itertools
3
+ from pathlib import Path
4
+ import shutil
5
+ from typing import Callable, Optional
6
+ from urllib.parse import quote
7
+
8
+ from instaui.html_tools import to_config_data
9
+ from instaui.runtime._app import get_app_slot, get_default_app_slot
10
+ from instaui.systems import file_system
11
+ from instaui.template import webview_template
12
+ from instaui import consts
13
+
14
+ from . import _utils
15
+
16
+
17
+ _INDEX_HTML_NAME = "index.html"
18
+
19
+
20
+ @dataclass
21
+ class ResourceInfo:
22
+ title: str
23
+ index_html_url: str
24
+
25
+
26
+ def resource_to_assets(
27
+ page_url: str, assets_path: Path, on_app_mounted: Optional[Callable] = None
28
+ ):
29
+ page_dir = assets_path.joinpath(quote(page_url, safe=""))
30
+ _utils.reset_dir(page_dir)
31
+
32
+ relative_to_assets = _get_relative_to_assets(page_dir)
33
+ file_to_assets = _get_file_to_assets(page_dir)
34
+
35
+ config_data = to_config_data()
36
+
37
+ system_slot = get_app_slot()
38
+ default_app_slot = get_default_app_slot()
39
+ html_resource = system_slot._html_resource
40
+ default_html_resource = default_app_slot._html_resource
41
+
42
+ if html_resource.favicon:
43
+ favicon_url = file_to_assets(html_resource.favicon)
44
+ else:
45
+ if default_html_resource.favicon:
46
+ favicon_url = file_to_assets(default_html_resource.favicon)
47
+ else:
48
+ favicon_url = file_to_assets(consts.FAVICON_PATH)
49
+
50
+ model = webview_template.WebViewTemplateModel(
51
+ vue_js_code=file_to_assets(consts.VUE_ES_JS_PATH),
52
+ instaui_js_code=file_to_assets(consts.APP_ES_JS_PATH),
53
+ css_links=[
54
+ file_to_assets(consts.APP_CSS_PATH),
55
+ ],
56
+ config_dict=config_data,
57
+ favicon_url=favicon_url,
58
+ title=html_resource.title or default_html_resource.title or consts.PAGE_TITLE,
59
+ on_app_mounted=on_app_mounted,
60
+ )
61
+
62
+ # register custom components
63
+ for component in system_slot._component_dependencies:
64
+ if not component.esm:
65
+ continue
66
+
67
+ component_url = file_to_assets(component.esm)
68
+ model.add_extra_import_map(component_url, file_to_assets(component.esm))
69
+
70
+ model.vue_app_component.append(
71
+ webview_template.WebViewVueAppComponent(
72
+ name=component.tag_name,
73
+ url=component_url,
74
+ )
75
+ )
76
+
77
+ if component.css:
78
+ for css_link in component.css:
79
+ css_resource = file_to_assets(css_link)
80
+ if css_link.is_file():
81
+ model.css_links.append(css_resource)
82
+
83
+ if component.externals:
84
+ for name, file in component.externals.items():
85
+ model.add_extra_import_map(name, file_to_assets(file))
86
+
87
+ # register custom plugins
88
+ for plugin in set(
89
+ itertools.chain(
90
+ system_slot._plugin_dependencies, default_app_slot._plugin_dependencies
91
+ )
92
+ ):
93
+ if not plugin.esm:
94
+ continue
95
+
96
+ model.vue_app_use.append(plugin.name)
97
+
98
+ model.add_extra_import_map(plugin.name, file_to_assets(plugin.esm))
99
+
100
+ if plugin.css:
101
+ for css_link in plugin.css:
102
+ model.css_links.append(file_to_assets(css_link))
103
+
104
+ # css file link to web static link
105
+ for link in html_resource.get_valid_css_links(
106
+ default_html_resource._css_links_manager
107
+ ):
108
+ if isinstance(link, Path):
109
+ model.css_links.append(file_to_assets(link))
110
+ else:
111
+ model.css_links.append(link)
112
+
113
+ # js file link to web static link
114
+ for info in html_resource.get_valid_js_links(
115
+ default_html_resource._js_links_manager
116
+ ):
117
+ link = file_to_assets(info.link) if isinstance(info.link, Path) else info.link
118
+ model.js_links.append(link)
119
+
120
+ for js_code in itertools.chain(
121
+ html_resource._script_tags, default_html_resource._script_tags
122
+ ):
123
+ model.script_tags.append(js_code)
124
+
125
+ for sylte_code in itertools.chain(
126
+ html_resource._style_tags, default_html_resource._style_tags
127
+ ):
128
+ model.style_tags.append(sylte_code)
129
+
130
+ html_str = webview_template.render_wbeview_html(model)
131
+
132
+ index_html_path = page_dir / _INDEX_HTML_NAME
133
+ index_html_path.write_text(html_str, encoding="utf-8")
134
+ relative_to_assets(index_html_path)
135
+ index_html_url = str(index_html_path.absolute())
136
+ return ResourceInfo(
137
+ title="test",
138
+ index_html_url=index_html_url,
139
+ )
140
+
141
+
142
+ def _get_relative_to_assets(assets_path: Path):
143
+ def wrapper(file_path: Path, relative_parent=False):
144
+ return str(
145
+ file_path.relative_to(
146
+ assets_path.parent if relative_parent else assets_path
147
+ )
148
+ ).replace("\\", "/")
149
+
150
+ return wrapper
151
+
152
+
153
+ def _get_file_to_assets(assets_path: Path):
154
+ relative_to_assets = _get_relative_to_assets(assets_path)
155
+
156
+ def wrapper(file_path: Path):
157
+ hash_part = file_system.generate_hash_name_from_path(file_path.parent)
158
+ new_folder_path = assets_path.joinpath(hash_part)
159
+
160
+ if not new_folder_path.exists():
161
+ new_folder_path.mkdir(parents=True)
162
+
163
+ new_path = new_folder_path.joinpath(file_path.name)
164
+
165
+ if file_path.is_file():
166
+ shutil.copyfile(file_path, new_path)
167
+ return "./" + relative_to_assets(new_path)
168
+ else:
169
+ shutil.copytree(file_path, new_path, dirs_exist_ok=True)
170
+ return "./" + relative_to_assets(new_path) + "/"
171
+
172
+ return wrapper
instaui/zero/func.py CHANGED
@@ -7,6 +7,7 @@ from instaui.template import render_zero_html
7
7
  from instaui.template import zero_template
8
8
  from instaui.html_tools import to_config_data
9
9
  from instaui.runtime.dataclass import JsLink
10
+ from instaui.runtime.resource import HtmlResource
10
11
 
11
12
 
12
13
  def to_html(file: Path):
@@ -20,9 +21,18 @@ def to_html(file: Path):
20
21
 
21
22
  def get_template_model():
22
23
  system_slot = get_app_slot()
24
+
25
+ merge_global_resources = (system_slot.meta or {}).get(
26
+ "merge_global_resources", True
27
+ )
28
+
23
29
  default_app_slot = get_default_app_slot()
24
30
  html_resource = system_slot._html_resource
25
- default_html_resource = default_app_slot._html_resource
31
+ default_html_resource = (
32
+ default_app_slot._html_resource
33
+ if merge_global_resources
34
+ else _empty_html_resource()
35
+ )
26
36
 
27
37
  config_data = to_config_data()
28
38
 
@@ -39,13 +49,6 @@ def get_template_model():
39
49
  title=html_resource.title or default_html_resource.title or consts.PAGE_TITLE,
40
50
  )
41
51
 
42
- if html_resource.use_tailwind is None:
43
- if default_html_resource.use_tailwind:
44
- model.js_links.append(JsLink(consts.TAILWIND_JS_PATH))
45
- else:
46
- if html_resource.use_tailwind:
47
- model.js_links.append(JsLink(consts.TAILWIND_JS_PATH))
48
-
49
52
  # register custom components
50
53
  for component in system_slot._component_dependencies:
51
54
  if not component.esm:
@@ -85,15 +88,15 @@ def get_template_model():
85
88
  model.css_links.append(css_link)
86
89
 
87
90
  # css file link to web static link
88
- for link, attrs in itertools.chain(
89
- html_resource._css_links.items(), default_html_resource._css_links.items()
91
+ for link in html_resource.get_valid_css_links(
92
+ default_html_resource._css_links_manager
90
93
  ):
91
94
  if isinstance(link, Path):
92
95
  model.css_links.append(link)
93
96
 
94
97
  # js file link to web static link
95
- for info in itertools.chain(
96
- html_resource._js_links, default_html_resource._js_links
98
+ for info in html_resource.get_valid_js_links(
99
+ default_html_resource._js_links_manager
97
100
  ):
98
101
  if isinstance(info.link, Path):
99
102
  model.js_links.append(JsLink(info.link))
@@ -114,3 +117,7 @@ def get_template_model():
114
117
  def to_html_str():
115
118
  model = get_template_model()
116
119
  return render_zero_html(model)
120
+
121
+
122
+ def _empty_html_resource():
123
+ return HtmlResource()
instaui/zero/scope.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from pathlib import Path
2
- from typing import Union
2
+ from typing import Dict, Optional, Union
3
3
  from instaui.runtime import new_app_slot, reset_app_slot
4
4
  from contextlib import contextmanager
5
5
  from .func import to_html, to_html_str, get_template_model
@@ -7,8 +7,8 @@ from instaui.template.zero_template import ZeroTemplateModel
7
7
 
8
8
 
9
9
  @contextmanager
10
- def scope():
11
- token = new_app_slot("zero")
10
+ def scope(app_meta: Optional[Dict] = None):
11
+ token = new_app_slot("zero", app_meta)
12
12
  yield Wrapper()
13
13
  reset_app_slot(token)
14
14
 
@@ -25,10 +25,10 @@ class Wrapper:
25
25
  file = self._get_caller_path(file)
26
26
 
27
27
  # Custom component dependencies must be recorded only during actual execution
28
- to_html_str()
28
+ result_html_str = to_html_str()
29
29
  model = get_template_model()
30
- with scope() as s:
31
- _create_debug_report(model)
30
+ with scope(app_meta={"merge_global_resources": False}) as s:
31
+ _create_debug_report(model, result_html_str)
32
32
  s.to_html(file.resolve().absolute())
33
33
 
34
34
  @staticmethod
@@ -44,8 +44,8 @@ class Wrapper:
44
44
  return file
45
45
 
46
46
 
47
- def _create_debug_report(model: ZeroTemplateModel):
48
- from instaui import ui, html
47
+ def _create_debug_report(model: ZeroTemplateModel, result_html_str: str):
48
+ from instaui import ui, html, arco
49
49
 
50
50
  no_exists_path_class = "ex-no-exists-path"
51
51
 
@@ -53,49 +53,50 @@ def _create_debug_report(model: ZeroTemplateModel):
53
53
  return "" if path.exists() else no_exists_path_class
54
54
 
55
55
  ui.use_tailwind()
56
+
56
57
  ui.add_style(rf".{no_exists_path_class} {{background-color: red;color: white;}}")
57
58
 
59
+ html_size = len(result_html_str.encode("utf-8")) / 1024 / 1024
60
+
61
+ box_style = "border-2 border-gray-200 p-4 place-center gap-x-2"
62
+
58
63
  with ui.column().classes("gap-2"):
64
+ # base info
65
+ with ui.grid(columns="auto 1fr").classes(box_style):
66
+ html.span("file size:")
67
+ html.span(f"{html_size:.2f} MB")
68
+
59
69
  # import maps
60
70
  html.paragraph("import maps")
61
- with ui.grid(columns="auto 1fr").classes(
62
- "gap-4 border-2 border-gray-200 p-4 place-center"
63
- ):
64
- html.span("name")
65
- html.span("path")
66
71
 
67
- html.span("vue")
68
- html.span(str(model.vue_js_code))
72
+ rows = [
73
+ ["vue", str(model.vue_js_code)],
74
+ ["instaui", str(model.instaui_js_code)],
75
+ ]
69
76
 
70
- html.span("instaui")
71
- html.span(str(model.instaui_js_code))
77
+ for name, url in model.extra_import_maps.items():
78
+ if isinstance(url, Path) and url.is_file():
79
+ rows.append([name, str(url)])
72
80
 
73
- for name, url in model.extra_import_maps.items():
74
- if isinstance(url, Path) and url.is_file():
75
- html.span(name)
76
- html.span(str(url.resolve().absolute())).classes(
77
- _path_exists_class(url)
78
- )
81
+ arco.table(columns=["name", "path"], data=rows)
79
82
 
80
83
  # css links
81
84
  html.paragraph("css links")
82
- with ui.column().classes("gap-4 border-2 border-gray-200 p-4 place-center"):
85
+ with ui.column().classes(box_style):
83
86
  for link in model.css_links:
84
87
  if isinstance(link, Path) and link.is_file():
85
88
  html.span(str(link)).classes(_path_exists_class(link))
86
89
 
87
90
  # js links
88
91
  html.paragraph("js links")
89
- with ui.column().classes("gap-4 border-2 border-gray-200 p-4 place-center"):
92
+ with ui.column().classes(box_style):
90
93
  for info in model.js_links:
91
94
  if isinstance(info.link, Path) and info.link.is_file():
92
95
  html.span(str(info.link)).classes(_path_exists_class(info.link))
93
96
 
94
97
  # custom components
95
98
  html.paragraph("custom components")
96
- with ui.grid(columns="auto 1fr").classes(
97
- "gap-4 border-2 border-gray-200 p-4 place-center"
98
- ):
99
+ with ui.grid(columns="auto 1fr").classes(box_style):
99
100
  html.span("name")
100
101
  html.span("js file path")
101
102
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: instaui
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: insta-ui is a Python-based UI library for rapidly building user interfaces.
5
5
  License: MIT
6
6
  Author: CrystalWindSnake
@@ -13,14 +13,18 @@ Classifier: Programming Language :: Python :: 3.9
13
13
  Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
+ Provides-Extra: all
16
17
  Provides-Extra: web
17
18
  Provides-Extra: webview
18
- Requires-Dist: fastapi ; extra == "web"
19
+ Requires-Dist: fastapi[standard] ; extra == "all"
20
+ Requires-Dist: fastapi[standard] ; extra == "web"
19
21
  Requires-Dist: jinja2 (>=3.1.4,<4.0.0)
20
22
  Requires-Dist: orjson (>=3.10.15,<4.0.0)
21
23
  Requires-Dist: pydantic (>=2.10.6,<3.0.0)
24
+ Requires-Dist: pywebview ; extra == "all"
22
25
  Requires-Dist: pywebview ; extra == "webview"
23
26
  Requires-Dist: typing-extensions (>=4.12.2,<5.0.0)
27
+ Requires-Dist: uvicorn ; extra == "all"
24
28
  Requires-Dist: uvicorn ; extra == "web"
25
29
  Description-Content-Type: text/markdown
26
30