instaui 0.1.15__py2.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 (283) hide show
  1. instaui/__init__.py +9 -0
  2. instaui/_helper/observable_helper.py +45 -0
  3. instaui/arco/__init__.py +191 -0
  4. instaui/arco/_settings.py +25 -0
  5. instaui/arco/_use_tools/locale.py +50 -0
  6. instaui/arco/component_types.py +1019 -0
  7. instaui/arco/components/_utils.py +22 -0
  8. instaui/arco/components/affix.py +29 -0
  9. instaui/arco/components/alert.py +42 -0
  10. instaui/arco/components/anchor.py +42 -0
  11. instaui/arco/components/auto_complete.py +96 -0
  12. instaui/arco/components/avatar.py +55 -0
  13. instaui/arco/components/back_top.py +14 -0
  14. instaui/arco/components/badge.py +14 -0
  15. instaui/arco/components/breadcrumb.py +14 -0
  16. instaui/arco/components/button.py +43 -0
  17. instaui/arco/components/calendar.py +47 -0
  18. instaui/arco/components/card.py +14 -0
  19. instaui/arco/components/carousel.py +33 -0
  20. instaui/arco/components/cascader.py +111 -0
  21. instaui/arco/components/checkbox.py +32 -0
  22. instaui/arco/components/collapse.py +31 -0
  23. instaui/arco/components/color_picker.py +45 -0
  24. instaui/arco/components/comment.py +14 -0
  25. instaui/arco/components/config_provider.py +13 -0
  26. instaui/arco/components/date_picker.py +111 -0
  27. instaui/arco/components/descriptions.py +14 -0
  28. instaui/arco/components/divider.py +13 -0
  29. instaui/arco/components/drawer.py +98 -0
  30. instaui/arco/components/dropdown.py +45 -0
  31. instaui/arco/components/empty.py +14 -0
  32. instaui/arco/components/form.py +55 -0
  33. instaui/arco/components/icon.py +17 -0
  34. instaui/arco/components/image.py +33 -0
  35. instaui/arco/components/input.py +102 -0
  36. instaui/arco/components/input_number.py +97 -0
  37. instaui/arco/components/input_password.py +38 -0
  38. instaui/arco/components/input_search.py +37 -0
  39. instaui/arco/components/input_tag.py +110 -0
  40. instaui/arco/components/layout.py +13 -0
  41. instaui/arco/components/layout_content.py +6 -0
  42. instaui/arco/components/layout_footer.py +6 -0
  43. instaui/arco/components/layout_header.py +6 -0
  44. instaui/arco/components/layout_sider.py +53 -0
  45. instaui/arco/components/link.py +36 -0
  46. instaui/arco/components/list.py +68 -0
  47. instaui/arco/components/mention.py +97 -0
  48. instaui/arco/components/menu.py +88 -0
  49. instaui/arco/components/modal.py +97 -0
  50. instaui/arco/components/overflow_list.py +29 -0
  51. instaui/arco/components/page_header.py +29 -0
  52. instaui/arco/components/pagination.py +45 -0
  53. instaui/arco/components/pop_confirm.py +58 -0
  54. instaui/arco/components/popover.py +32 -0
  55. instaui/arco/components/progress.py +14 -0
  56. instaui/arco/components/radio.py +40 -0
  57. instaui/arco/components/radio_group.py +42 -0
  58. instaui/arco/components/rate.py +45 -0
  59. instaui/arco/components/resize_box.py +62 -0
  60. instaui/arco/components/result.py +14 -0
  61. instaui/arco/components/select.py +182 -0
  62. instaui/arco/components/skeleton.py +14 -0
  63. instaui/arco/components/slider.py +38 -0
  64. instaui/arco/components/space.py +14 -0
  65. instaui/arco/components/spin.py +14 -0
  66. instaui/arco/components/split.py +76 -0
  67. instaui/arco/components/statistic.py +14 -0
  68. instaui/arco/components/steps.py +32 -0
  69. instaui/arco/components/switch.py +57 -0
  70. instaui/arco/components/tab_pane.py +12 -0
  71. instaui/arco/components/table.py +276 -0
  72. instaui/arco/components/tabs.py +101 -0
  73. instaui/arco/components/tag.py +42 -0
  74. instaui/arco/components/textarea.py +84 -0
  75. instaui/arco/components/time_picker.py +76 -0
  76. instaui/arco/components/timeline.py +14 -0
  77. instaui/arco/components/tooltip.py +29 -0
  78. instaui/arco/components/transfer.py +58 -0
  79. instaui/arco/components/tree.py +120 -0
  80. instaui/arco/components/tree_select.py +86 -0
  81. instaui/arco/components/trigger.py +58 -0
  82. instaui/arco/components/typography.py +142 -0
  83. instaui/arco/components/upload.py +71 -0
  84. instaui/arco/components/verification_code.py +58 -0
  85. instaui/arco/components/watermark.py +14 -0
  86. instaui/arco/locales/__init__.py +4 -0
  87. instaui/arco/locales/_index.py +31 -0
  88. instaui/arco/locales/en_us.py +227 -0
  89. instaui/arco/locales/zh_cn.py +224 -0
  90. instaui/arco/setup.py +36 -0
  91. instaui/arco/static/instaui-arco.css +1 -0
  92. instaui/arco/static/instaui-arco.js +55771 -0
  93. instaui/arco/types.py +24 -0
  94. instaui/boot_info.py +43 -0
  95. instaui/common/jsonable.py +37 -0
  96. instaui/components/__init__.py +0 -0
  97. instaui/components/column.py +26 -0
  98. instaui/components/component.py +47 -0
  99. instaui/components/content.py +34 -0
  100. instaui/components/directive.py +55 -0
  101. instaui/components/element.py +573 -0
  102. instaui/components/grid.py +213 -0
  103. instaui/components/html/__init__.py +49 -0
  104. instaui/components/html/_mixins.py +34 -0
  105. instaui/components/html/_preset.py +4 -0
  106. instaui/components/html/button.py +38 -0
  107. instaui/components/html/checkbox.py +35 -0
  108. instaui/components/html/date.py +28 -0
  109. instaui/components/html/div.py +7 -0
  110. instaui/components/html/form.py +7 -0
  111. instaui/components/html/heading.py +51 -0
  112. instaui/components/html/input.py +28 -0
  113. instaui/components/html/label.py +21 -0
  114. instaui/components/html/li.py +17 -0
  115. instaui/components/html/link.py +31 -0
  116. instaui/components/html/number.py +34 -0
  117. instaui/components/html/paragraph.py +29 -0
  118. instaui/components/html/range.py +48 -0
  119. instaui/components/html/select.py +69 -0
  120. instaui/components/html/span.py +19 -0
  121. instaui/components/html/table.py +36 -0
  122. instaui/components/html/textarea.py +28 -0
  123. instaui/components/html/ul.py +20 -0
  124. instaui/components/label.py +5 -0
  125. instaui/components/markdown/markdown.js +33 -0
  126. instaui/components/markdown/markdown.py +41 -0
  127. instaui/components/markdown/static/github-markdown.css +12 -0
  128. instaui/components/markdown/static/marked.esm.js +2579 -0
  129. instaui/components/match.py +108 -0
  130. instaui/components/row.py +17 -0
  131. instaui/components/shiki_code/shiki_code.js +126 -0
  132. instaui/components/shiki_code/shiki_code.py +99 -0
  133. instaui/components/shiki_code/static/langs/css.mjs +5 -0
  134. instaui/components/shiki_code/static/langs/markdown.mjs +5 -0
  135. instaui/components/shiki_code/static/langs/python.mjs +5 -0
  136. instaui/components/shiki_code/static/langs/shell.mjs +2 -0
  137. instaui/components/shiki_code/static/langs/shellscript.mjs +5 -0
  138. instaui/components/shiki_code/static/shiki-core.js +5784 -0
  139. instaui/components/shiki_code/static/shiki-style.css +179 -0
  140. instaui/components/shiki_code/static/shiki-transformers.js +461 -0
  141. instaui/components/shiki_code/static/themes/vitesse-dark.mjs +2 -0
  142. instaui/components/shiki_code/static/themes/vitesse-light.mjs +2 -0
  143. instaui/components/slot.py +81 -0
  144. instaui/components/transition_group.py +9 -0
  145. instaui/components/value_element.py +52 -0
  146. instaui/components/vfor.py +142 -0
  147. instaui/components/vif.py +42 -0
  148. instaui/consts.py +23 -0
  149. instaui/dependencies/component_dependency.py +22 -0
  150. instaui/dependencies/plugin_dependency.py +28 -0
  151. instaui/event/event_mixin.py +12 -0
  152. instaui/event/js_event.py +82 -0
  153. instaui/event/vue_event.py +66 -0
  154. instaui/event/web_event.py +123 -0
  155. instaui/experimental/__init__.py +3 -0
  156. instaui/experimental/debug.py +48 -0
  157. instaui/extra_libs/_echarts.py +3 -0
  158. instaui/extra_libs/_import_error.py +9 -0
  159. instaui/extra_libs/_mermaid.py +3 -0
  160. instaui/extra_libs/_shiki_code.py +3 -0
  161. instaui/fastapi_server/_utils.py +42 -0
  162. instaui/fastapi_server/_uvicorn.py +37 -0
  163. instaui/fastapi_server/debug_mode_router.py +60 -0
  164. instaui/fastapi_server/dependency_router.py +28 -0
  165. instaui/fastapi_server/event_router.py +58 -0
  166. instaui/fastapi_server/middlewares.py +19 -0
  167. instaui/fastapi_server/request_context.py +19 -0
  168. instaui/fastapi_server/resource.py +30 -0
  169. instaui/fastapi_server/server.py +308 -0
  170. instaui/fastapi_server/watch_router.py +53 -0
  171. instaui/handlers/_utils.py +88 -0
  172. instaui/handlers/event_handler.py +60 -0
  173. instaui/handlers/watch_handler.py +61 -0
  174. instaui/html_tools.py +94 -0
  175. instaui/inject.py +33 -0
  176. instaui/js/__init__.py +4 -0
  177. instaui/js/js_output.py +15 -0
  178. instaui/js/lambda_func.py +35 -0
  179. instaui/launch_collector.py +52 -0
  180. instaui/page_info.py +13 -0
  181. instaui/runtime/__init__.py +29 -0
  182. instaui/runtime/_app.py +234 -0
  183. instaui/runtime/_inner_helper.py +9 -0
  184. instaui/runtime/_link_manager.py +89 -0
  185. instaui/runtime/context.py +47 -0
  186. instaui/runtime/dataclass.py +30 -0
  187. instaui/runtime/resource.py +65 -0
  188. instaui/runtime/scope.py +133 -0
  189. instaui/runtime/ui_state_scope.py +15 -0
  190. instaui/settings/__init__.py +4 -0
  191. instaui/settings/__settings.py +13 -0
  192. instaui/shadcn_classless/_index.py +42 -0
  193. instaui/shadcn_classless/static/shadcn-classless.css +403 -0
  194. instaui/skip.py +12 -0
  195. instaui/spa_router/__init__.py +26 -0
  196. instaui/spa_router/_components.py +35 -0
  197. instaui/spa_router/_file_base_utils.py +273 -0
  198. instaui/spa_router/_functions.py +122 -0
  199. instaui/spa_router/_install.py +11 -0
  200. instaui/spa_router/_route_model.py +117 -0
  201. instaui/spa_router/_router_box.py +40 -0
  202. instaui/spa_router/_router_output.py +22 -0
  203. instaui/spa_router/_router_param_var.py +51 -0
  204. instaui/spa_router/_types.py +4 -0
  205. instaui/spa_router/templates/page_routes +60 -0
  206. instaui/static/insta-ui.css +1 -0
  207. instaui/static/insta-ui.esm-browser.prod.js +3717 -0
  208. instaui/static/insta-ui.ico +0 -0
  209. instaui/static/insta-ui.js.map +1 -0
  210. instaui/static/instaui-tools-browser.js +511 -0
  211. instaui/static/templates/debug/sse.html +117 -0
  212. instaui/static/templates/web.html +74 -0
  213. instaui/static/templates/webview.html +78 -0
  214. instaui/static/templates/zero.html +71 -0
  215. instaui/static/vue.esm-browser.prod.js +9 -0
  216. instaui/static/vue.global.prod.js +9 -0
  217. instaui/static/vue.runtime.esm-browser.prod.js +5 -0
  218. instaui/systems/file_system.py +6 -0
  219. instaui/systems/func_system.py +119 -0
  220. instaui/systems/js_system.py +22 -0
  221. instaui/systems/module_system.py +46 -0
  222. instaui/systems/pydantic_system.py +27 -0
  223. instaui/systems/string_system.py +10 -0
  224. instaui/tailwind/__init__.py +6 -0
  225. instaui/tailwind/_index.py +24 -0
  226. instaui/tailwind/static/tailwindcss-v3.min.js +62 -0
  227. instaui/tailwind/static/tailwindcss-v4.min.js +8 -0
  228. instaui/template/__init__.py +4 -0
  229. instaui/template/_utils.py +23 -0
  230. instaui/template/env.py +7 -0
  231. instaui/template/web_template.py +49 -0
  232. instaui/template/webview_template.py +48 -0
  233. instaui/template/zero_template.py +105 -0
  234. instaui/ui/__init__.py +144 -0
  235. instaui/ui/__init__.pyi +149 -0
  236. instaui/ui/events.py +25 -0
  237. instaui/ui_functions/input_slient_data.py +16 -0
  238. instaui/ui_functions/server.py +15 -0
  239. instaui/ui_functions/str_format.py +36 -0
  240. instaui/ui_functions/ui_page.py +16 -0
  241. instaui/ui_functions/ui_types.py +13 -0
  242. instaui/ui_functions/url_location.py +33 -0
  243. instaui/vars/_types.py +8 -0
  244. instaui/vars/data.py +68 -0
  245. instaui/vars/element_ref.py +40 -0
  246. instaui/vars/event_context.py +49 -0
  247. instaui/vars/event_extend.py +0 -0
  248. instaui/vars/js_computed.py +117 -0
  249. instaui/vars/mixin_types/common_type.py +5 -0
  250. instaui/vars/mixin_types/element_binding.py +16 -0
  251. instaui/vars/mixin_types/observable.py +7 -0
  252. instaui/vars/mixin_types/pathable.py +14 -0
  253. instaui/vars/mixin_types/py_binding.py +13 -0
  254. instaui/vars/mixin_types/str_format_binding.py +8 -0
  255. instaui/vars/mixin_types/var_type.py +5 -0
  256. instaui/vars/path_var.py +90 -0
  257. instaui/vars/ref.py +103 -0
  258. instaui/vars/slot_prop.py +46 -0
  259. instaui/vars/state.py +97 -0
  260. instaui/vars/types.py +24 -0
  261. instaui/vars/vfor_item.py +204 -0
  262. instaui/vars/vue_computed.py +81 -0
  263. instaui/vars/web_computed.py +209 -0
  264. instaui/vars/web_view_computed.py +1 -0
  265. instaui/version.py +3 -0
  266. instaui/watch/_types.py +4 -0
  267. instaui/watch/_utils.py +3 -0
  268. instaui/watch/js_watch.py +110 -0
  269. instaui/watch/vue_watch.py +77 -0
  270. instaui/watch/web_watch.py +181 -0
  271. instaui/webview/__init__.py +2 -0
  272. instaui/webview/_utils.py +8 -0
  273. instaui/webview/api.py +72 -0
  274. instaui/webview/func.py +114 -0
  275. instaui/webview/index.py +161 -0
  276. instaui/webview/resource.py +172 -0
  277. instaui/zero/__init__.py +3 -0
  278. instaui/zero/func.py +123 -0
  279. instaui/zero/scope.py +109 -0
  280. instaui-0.1.15.dist-info/METADATA +152 -0
  281. instaui-0.1.15.dist-info/RECORD +283 -0
  282. instaui-0.1.15.dist-info/WHEEL +5 -0
  283. instaui-0.1.15.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,161 @@
1
+ from __future__ import annotations
2
+ from contextlib import contextmanager
3
+ from pathlib import Path
4
+ from typing import Any, Callable, Dict, Iterable, List, Optional, Union
5
+ from typing_extensions import TypedDict, Unpack
6
+ import webview
7
+ import webview.http as http
8
+ from webview.guilib import GUIType
9
+
10
+ from instaui.runtime._app import get_app_slot, new_app_slot, reset_app_slot
11
+ from instaui.launch_collector import get_launch_collector
12
+
13
+ from . import resource
14
+ from . import api
15
+ from . import _utils
16
+
17
+
18
+ class WebviewWrapper:
19
+ """Example usage:
20
+ .. code-block:: python
21
+ from instaui import ui
22
+
23
+ @ui.page("/")
24
+ def index_page():
25
+ ui.content("Hello, world!")
26
+
27
+ ui.webview().run()
28
+ """
29
+
30
+ def __init__(
31
+ self,
32
+ *,
33
+ assets_path: Union[str, Path] = "./webview_assets",
34
+ debug: bool = False,
35
+ auto_create_window: Union[bool, str] = "/",
36
+ on_app_mounted: Optional[Callable] = None,
37
+ ) -> None:
38
+ """Create a new webview wrapper.
39
+
40
+ Args:
41
+ assets_path (Union[str, Path], optional): Path to store assets. Defaults to "./webview_assets".
42
+ debug (bool, optional): Whether to run in debug mode. Defaults to False.
43
+ 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 "/".
44
+ testing (bool, optional): Whether to run in testing mode. Defaults to False.
45
+ """
46
+
47
+ self.assets_path = (
48
+ Path(self._get_assets_path(assets_path))
49
+ if isinstance(assets_path, str)
50
+ else assets_path
51
+ )
52
+ _utils.reset_dir(self.assets_path)
53
+ self.debug = debug
54
+ self.on_app_mounted = on_app_mounted
55
+
56
+ self._auto_create_window = auto_create_window
57
+
58
+ def create_window(
59
+ self,
60
+ page_url: str = "/",
61
+ ):
62
+ """Create a new window. Returns the window object of pywebview.
63
+
64
+ Args:
65
+ page_url (str, optional): Page URL to load. Defaults to "/".
66
+
67
+ """
68
+ launch_collector = get_launch_collector()
69
+ with _scope():
70
+ app = get_app_slot()
71
+ app._page_path = page_url
72
+ page_info = launch_collector._page_router[page_url]
73
+ page_info.func()
74
+
75
+ resource_info = resource.resource_to_assets(
76
+ page_url=page_url,
77
+ assets_path=self.assets_path,
78
+ on_app_mounted=self.on_app_mounted,
79
+ )
80
+
81
+ window = webview.create_window(
82
+ resource_info.title, resource_info.index_html_url, js_api=api.Api()
83
+ )
84
+
85
+ if self.on_app_mounted:
86
+
87
+ def on_app_mounted():
88
+ self.on_app_mounted(window) # type: ignore
89
+
90
+ window.expose(on_app_mounted)
91
+
92
+ return window
93
+
94
+ def run(self, **webview_start_args: Unpack[WebviewStartArgs]):
95
+ """Run the webview.
96
+
97
+ Args:
98
+ :param func: Function to invoke upon starting the GUI loop.
99
+ :param args: Function arguments. Can be either a single value or a tuple of
100
+ values.
101
+ :param localization: A dictionary with localized strings. Default strings
102
+ and their keys are defined in localization.py.
103
+ :param gui: Force a specific GUI. Allowed values are ``cef``, ``qt``,
104
+ ``gtk``, ``mshtml`` or ``edgechromium`` depending on a platform.
105
+ :param http_server: Enable built-in HTTP server. If enabled, local files
106
+ will be served using a local HTTP server on a random port. For each
107
+ window, a separate HTTP server is spawned. This option is ignored for
108
+ non-local URLs.
109
+ :param user_agent: Change user agent string.
110
+ :param private_mode: Enable private mode. In private mode, cookies and local storage are not preserved.
111
+ Default is True.
112
+ :param storage_path: Custom location for cookies and other website data
113
+ :param menu: List of menus to be included in the app menu
114
+ :param server: Server class. Defaults to BottleServer
115
+ :param server_args: Dictionary of arguments to pass through to the server instantiation
116
+ :param ssl: Enable SSL for local HTTP server. Default is False.
117
+ :param icon: Path to the icon file. Supported only on GTK/QT.
118
+ """
119
+
120
+ if self._auto_create_window:
121
+ self.create_window(
122
+ "/" if self._auto_create_window is True else self._auto_create_window
123
+ )
124
+
125
+ webview.start(**webview_start_args, debug=self.debug)
126
+
127
+ @staticmethod
128
+ def _get_assets_path(file: Union[str, Path]) -> Path:
129
+ if isinstance(file, str):
130
+ import inspect
131
+
132
+ frame = inspect.currentframe().f_back.f_back.f_back.f_back.f_back # type: ignore
133
+ assert frame is not None
134
+ script_file = inspect.getfile(frame)
135
+ file = Path(script_file).parent.joinpath(file)
136
+
137
+ return file
138
+
139
+
140
+ @contextmanager
141
+ def _scope():
142
+ token = new_app_slot("webview")
143
+ yield
144
+ reset_app_slot(token)
145
+
146
+
147
+ class WebviewStartArgs(TypedDict, total=False):
148
+ func: Union[Callable[..., None], None]
149
+ args: Union[Iterable[Any], None]
150
+ localization: Dict[str, str]
151
+ gui: Union[GUIType, None]
152
+ http_server: bool
153
+ http_port: Union[int, None]
154
+ user_agent: Union[str, None]
155
+ private_mode: bool
156
+ storage_path: Union[str, None]
157
+ menu: List[Any]
158
+ server: type[http.ServerType] # type: ignore
159
+ server_args: Dict[Any, Any]
160
+ ssl: bool
161
+ 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
@@ -0,0 +1,3 @@
1
+ from .scope import scope
2
+
3
+ __all__ = ["scope"]
instaui/zero/func.py ADDED
@@ -0,0 +1,123 @@
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 to_html(file: Path):
14
+ file = Path(file)
15
+
16
+ raw = to_html_str()
17
+ file.write_text(raw, "utf8")
18
+
19
+ return file.resolve().absolute()
20
+
21
+
22
+ def get_template_model():
23
+ system_slot = get_app_slot()
24
+
25
+ merge_global_resources = (system_slot.meta or {}).get(
26
+ "merge_global_resources", True
27
+ )
28
+
29
+ default_app_slot = get_default_app_slot()
30
+ html_resource = system_slot._html_resource
31
+ default_html_resource = (
32
+ default_app_slot._html_resource
33
+ if merge_global_resources
34
+ else _empty_html_resource()
35
+ )
36
+
37
+ config_data = to_config_data()
38
+
39
+ model = zero_template.ZeroTemplateModel(
40
+ vue_js_code=consts.VUE_ES_JS_PATH,
41
+ instaui_js_code=consts.APP_ES_JS_PATH,
42
+ css_links=[
43
+ consts.APP_CSS_PATH,
44
+ ],
45
+ config_dict=config_data,
46
+ favicon=html_resource.favicon
47
+ or default_html_resource.favicon
48
+ or consts.FAVICON_PATH,
49
+ title=html_resource.title or default_html_resource.title or consts.PAGE_TITLE,
50
+ )
51
+
52
+ # register custom components
53
+ for component in system_slot._component_dependencies:
54
+ if not component.esm:
55
+ continue
56
+
57
+ model.vue_app_component.append(
58
+ zero_template.ZeroVueAppComponent(
59
+ name=component.tag_name,
60
+ url=component.esm,
61
+ )
62
+ )
63
+
64
+ if component.css:
65
+ for css_link in component.css:
66
+ model.css_links.append(css_link)
67
+
68
+ if component.externals:
69
+ for name, url in component.externals.items():
70
+ if url.is_file():
71
+ model.add_extra_import_map(name, url)
72
+
73
+ # register custom plugins
74
+ for plugin in set(
75
+ itertools.chain(
76
+ system_slot._plugin_dependencies, default_app_slot._plugin_dependencies
77
+ )
78
+ ):
79
+ if not plugin.esm:
80
+ continue
81
+
82
+ model.vue_app_use.append(plugin.name)
83
+
84
+ model.add_extra_import_map(plugin.name, plugin.esm)
85
+
86
+ if plugin.css:
87
+ for css_link in plugin.css:
88
+ model.css_links.append(css_link)
89
+
90
+ # css file link to web static link
91
+ for link in html_resource.get_valid_css_links(
92
+ default_html_resource._css_links_manager
93
+ ):
94
+ if isinstance(link, Path):
95
+ model.css_links.append(link)
96
+
97
+ # js file link to web static link
98
+ for info in html_resource.get_valid_js_links(
99
+ default_html_resource._js_links_manager
100
+ ):
101
+ if isinstance(info.link, Path):
102
+ model.js_links.append(JsLink(info.link))
103
+
104
+ for js_code in itertools.chain(
105
+ html_resource._script_tags, default_html_resource._script_tags
106
+ ):
107
+ model.script_tags.append(js_code)
108
+
109
+ for sylte_code in itertools.chain(
110
+ html_resource._style_tags, default_html_resource._style_tags
111
+ ):
112
+ model.style_tags.append(sylte_code)
113
+
114
+ return model
115
+
116
+
117
+ def to_html_str():
118
+ model = get_template_model()
119
+ return render_zero_html(model)
120
+
121
+
122
+ def _empty_html_resource():
123
+ return HtmlResource()
instaui/zero/scope.py ADDED
@@ -0,0 +1,109 @@
1
+ from pathlib import Path
2
+ from typing import Dict, Optional, Union
3
+ from instaui.runtime import new_app_slot, reset_app_slot
4
+ from contextlib import contextmanager
5
+ from .func import to_html, to_html_str, get_template_model
6
+ from instaui.template.zero_template import ZeroTemplateModel
7
+
8
+
9
+ @contextmanager
10
+ def scope(app_meta: Optional[Dict] = None):
11
+ token = new_app_slot("zero", app_meta)
12
+ yield Wrapper()
13
+ reset_app_slot(token)
14
+
15
+
16
+ class Wrapper:
17
+ def to_html(self, file: Union[str, Path]):
18
+ file = self._get_caller_path(file)
19
+ return to_html(file)
20
+
21
+ def to_html_str(self):
22
+ return to_html_str()
23
+
24
+ def to_debug_report(self, file: Union[str, Path]):
25
+ file = self._get_caller_path(file)
26
+
27
+ # Custom component dependencies must be recorded only during actual execution
28
+ result_html_str = to_html_str()
29
+ model = get_template_model()
30
+ with scope(app_meta={"merge_global_resources": False}) as s:
31
+ _create_debug_report(model, result_html_str)
32
+ s.to_html(file.resolve().absolute())
33
+
34
+ @staticmethod
35
+ def _get_caller_path(file: Union[str, Path]) -> Path:
36
+ if isinstance(file, str):
37
+ import inspect
38
+
39
+ frame = inspect.currentframe().f_back.f_back # type: ignore
40
+ assert frame is not None
41
+ script_file = inspect.getfile(frame)
42
+ file = Path(script_file).parent.joinpath(file)
43
+
44
+ return file
45
+
46
+
47
+ def _create_debug_report(model: ZeroTemplateModel, result_html_str: str):
48
+ from instaui import ui, html, arco
49
+
50
+ no_exists_path_class = "ex-no-exists-path"
51
+
52
+ def _path_exists_class(path: Path):
53
+ return "" if path.exists() else no_exists_path_class
54
+
55
+ ui.use_tailwind()
56
+
57
+ ui.add_style(rf".{no_exists_path_class} {{background-color: red;color: white;}}")
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
+
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
+
69
+ # import maps
70
+ html.paragraph("import maps")
71
+
72
+ rows = [
73
+ ["vue", str(model.vue_js_code)],
74
+ ["instaui", str(model.instaui_js_code)],
75
+ ]
76
+
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)])
80
+
81
+ arco.table(columns=["name", "path"], data=rows)
82
+
83
+ # css links
84
+ html.paragraph("css links")
85
+ with ui.column().classes(box_style):
86
+ for link in model.css_links:
87
+ if isinstance(link, Path) and link.is_file():
88
+ html.span(str(link)).classes(_path_exists_class(link))
89
+
90
+ # js links
91
+ html.paragraph("js links")
92
+ with ui.column().classes(box_style):
93
+ for info in model.js_links:
94
+ if isinstance(info.link, Path) and info.link.is_file():
95
+ html.span(str(info.link)).classes(_path_exists_class(info.link))
96
+
97
+ # custom components
98
+ html.paragraph("custom components")
99
+ with ui.grid(columns="auto 1fr").classes(box_style):
100
+ html.span("name")
101
+ html.span("js file path")
102
+
103
+ for info in model.vue_app_component:
104
+ html.span(info.name)
105
+
106
+ if isinstance(info.url, Path) and info.url.is_file():
107
+ html.span(str(info.url)).classes(_path_exists_class(info.url))
108
+ else:
109
+ html.span("not file")