bootstack 0.1.0a1__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 (419) hide show
  1. bootstack/__init__.py +249 -0
  2. bootstack/__main__.py +5 -0
  3. bootstack/api/__init__.py +127 -0
  4. bootstack/api/app.py +30 -0
  5. bootstack/api/constants.py +3 -0
  6. bootstack/api/data.py +23 -0
  7. bootstack/api/dialogs.py +44 -0
  8. bootstack/api/i18n.py +17 -0
  9. bootstack/api/localization.py +16 -0
  10. bootstack/api/menu.py +7 -0
  11. bootstack/api/style.py +23 -0
  12. bootstack/api/utils.py +24 -0
  13. bootstack/api/widgets.py +137 -0
  14. bootstack/assets/__init__.py +24 -0
  15. bootstack/assets/bootstack-transparent.png +0 -0
  16. bootstack/assets/bootstack.ico +0 -0
  17. bootstack/assets/bootstack.png +0 -0
  18. bootstack/assets/elements/__init__.py +0 -0
  19. bootstack/assets/elements/badge-pill.png +0 -0
  20. bootstack/assets/elements/badge-square.png +0 -0
  21. bootstack/assets/elements/border.png +0 -0
  22. bootstack/assets/elements/button-compact.png +0 -0
  23. bootstack/assets/elements/button-default.png +0 -0
  24. bootstack/assets/elements/button-group-horizontal-after-compact.png +0 -0
  25. bootstack/assets/elements/button-group-horizontal-after-default.png +0 -0
  26. bootstack/assets/elements/button-group-horizontal-before-compact.png +0 -0
  27. bootstack/assets/elements/button-group-horizontal-before-default.png +0 -0
  28. bootstack/assets/elements/button-group-horizontal-center-compact.png +0 -0
  29. bootstack/assets/elements/button-group-horizontal-center-default.png +0 -0
  30. bootstack/assets/elements/button-group-vertical-after-compact.png +0 -0
  31. bootstack/assets/elements/button-group-vertical-after-default.png +0 -0
  32. bootstack/assets/elements/button-group-vertical-before-compact.png +0 -0
  33. bootstack/assets/elements/button-group-vertical-before-default.png +0 -0
  34. bootstack/assets/elements/button-group-vertical-center-compact.png +0 -0
  35. bootstack/assets/elements/button-group-vertical-center-default.png +0 -0
  36. bootstack/assets/elements/checkbox-checked.png +0 -0
  37. bootstack/assets/elements/checkbox-indeterminate.png +0 -0
  38. bootstack/assets/elements/checkbox-unchecked.png +0 -0
  39. bootstack/assets/elements/field.png +0 -0
  40. bootstack/assets/elements/input-after-compact.png +0 -0
  41. bootstack/assets/elements/input-after-default.png +0 -0
  42. bootstack/assets/elements/input-before-compact.png +0 -0
  43. bootstack/assets/elements/input-before-default.png +0 -0
  44. bootstack/assets/elements/input-compact.png +0 -0
  45. bootstack/assets/elements/input-default.png +0 -0
  46. bootstack/assets/elements/list-item-separated.png +0 -0
  47. bootstack/assets/elements/list-item.png +0 -0
  48. bootstack/assets/elements/manifest.toml +480 -0
  49. bootstack/assets/elements/menu-item.png +0 -0
  50. bootstack/assets/elements/nav-button-compact.png +0 -0
  51. bootstack/assets/elements/nav-button-default.png +0 -0
  52. bootstack/assets/elements/nav-icon-button-compact.png +0 -0
  53. bootstack/assets/elements/nav-icon-button-default.png +0 -0
  54. bootstack/assets/elements/notebook-client-border.png +0 -0
  55. bootstack/assets/elements/notebook-tab-active.png +0 -0
  56. bootstack/assets/elements/notebook-tab-bar.png +0 -0
  57. bootstack/assets/elements/notebook-tab-normal.png +0 -0
  58. bootstack/assets/elements/notebook-tab-pill.png +0 -0
  59. bootstack/assets/elements/progress-bar-horizontal-striped.png +0 -0
  60. bootstack/assets/elements/progress-bar-solid.png +0 -0
  61. bootstack/assets/elements/progress-bar-thin.png +0 -0
  62. bootstack/assets/elements/progress-bar-vertical-striped.png +0 -0
  63. bootstack/assets/elements/radio-selected.png +0 -0
  64. bootstack/assets/elements/radio-unselected.png +0 -0
  65. bootstack/assets/elements/scrollbar-horizontal.png +0 -0
  66. bootstack/assets/elements/scrollbar-vertical.png +0 -0
  67. bootstack/assets/elements/slider-handle-focus.png +0 -0
  68. bootstack/assets/elements/slider-handle.png +0 -0
  69. bootstack/assets/elements/slider-track-horizontal.png +0 -0
  70. bootstack/assets/elements/slider-track-vertical.png +0 -0
  71. bootstack/assets/elements/switch-off.png +0 -0
  72. bootstack/assets/elements/switch-on.png +0 -0
  73. bootstack/assets/elements/tabs-bar-horizontal.png +0 -0
  74. bootstack/assets/elements/tabs-bar-vertical.png +0 -0
  75. bootstack/assets/elements/tabs-pill.png +0 -0
  76. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
  77. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +853 -0
  78. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +875 -0
  79. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
  80. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +853 -0
  81. bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
  82. bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +853 -0
  83. bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
  84. bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +853 -0
  85. bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
  86. bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +875 -0
  87. bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
  88. bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +853 -0
  89. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
  90. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +853 -0
  91. bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
  92. bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +851 -0
  93. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
  94. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +842 -0
  95. bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
  96. bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +841 -0
  97. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
  98. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +914 -0
  99. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
  100. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +842 -0
  101. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
  102. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +841 -0
  103. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
  104. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +841 -0
  105. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
  106. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +842 -0
  107. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
  108. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +842 -0
  109. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
  110. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +842 -0
  111. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
  112. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +842 -0
  113. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
  114. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +842 -0
  115. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
  116. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +842 -0
  117. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
  118. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +842 -0
  119. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
  120. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +842 -0
  121. bootstack/assets/themes/__init__.py +0 -0
  122. bootstack/assets/themes/amber-dark.json +32 -0
  123. bootstack/assets/themes/amber-light.json +32 -0
  124. bootstack/assets/themes/aurora-dark.json +32 -0
  125. bootstack/assets/themes/aurora-light.json +32 -0
  126. bootstack/assets/themes/bootstrap-dark.json +32 -0
  127. bootstack/assets/themes/bootstrap-light.json +32 -0
  128. bootstack/assets/themes/classic-dark.json +32 -0
  129. bootstack/assets/themes/classic-light.json +32 -0
  130. bootstack/assets/themes/docs-dark.json +32 -0
  131. bootstack/assets/themes/docs-light.json +32 -0
  132. bootstack/assets/themes/forest-dark.json +32 -0
  133. bootstack/assets/themes/forest-light.json +32 -0
  134. bootstack/assets/themes/ocean-dark.json +32 -0
  135. bootstack/assets/themes/ocean-light.json +32 -0
  136. bootstack/assets/themes/rose-dark.json +32 -0
  137. bootstack/assets/themes/rose-light.json +32 -0
  138. bootstack/assets/widgets/__init__.py +0 -0
  139. bootstack/assets/widgets/badge-default.png +0 -0
  140. bootstack/assets/widgets/badge-pill.png +0 -0
  141. bootstack/assets/widgets/border.png +0 -0
  142. bootstack/assets/widgets/button-group-horizontal-after.png +0 -0
  143. bootstack/assets/widgets/button-group-horizontal-before.png +0 -0
  144. bootstack/assets/widgets/button-group-horizontal-center.png +0 -0
  145. bootstack/assets/widgets/button-group-vertical-after.png +0 -0
  146. bootstack/assets/widgets/button-group-vertical-before.png +0 -0
  147. bootstack/assets/widgets/button-group-vertical-center.png +0 -0
  148. bootstack/assets/widgets/button.png +0 -0
  149. bootstack/assets/widgets/checkbox-checked.png +0 -0
  150. bootstack/assets/widgets/checkbox-indeterminate.png +0 -0
  151. bootstack/assets/widgets/checkbox-unchecked.png +0 -0
  152. bootstack/assets/widgets/field.png +0 -0
  153. bootstack/assets/widgets/icon-button.png +0 -0
  154. bootstack/assets/widgets/input-inner.png +0 -0
  155. bootstack/assets/widgets/input-prefix.png +0 -0
  156. bootstack/assets/widgets/input-suffix.png +0 -0
  157. bootstack/assets/widgets/input.png +0 -0
  158. bootstack/assets/widgets/list-item-focus.png +0 -0
  159. bootstack/assets/widgets/list-item-separated.png +0 -0
  160. bootstack/assets/widgets/menu-item-separated.png +0 -0
  161. bootstack/assets/widgets/notebook-client-border.png +0 -0
  162. bootstack/assets/widgets/notebook-pill-active.png +0 -0
  163. bootstack/assets/widgets/notebook-pill-inactive.png +0 -0
  164. bootstack/assets/widgets/notebook-tab-active.png +0 -0
  165. bootstack/assets/widgets/notebook-tab-border.png +0 -0
  166. bootstack/assets/widgets/notebook-tab-normal.png +0 -0
  167. bootstack/assets/widgets/notebook-underline.png +0 -0
  168. bootstack/assets/widgets/progress-bar-horizontal-default.png +0 -0
  169. bootstack/assets/widgets/progress-bar-horizontal-striped.png +0 -0
  170. bootstack/assets/widgets/progress-bar-vertical-default.png +0 -0
  171. bootstack/assets/widgets/progress-bar-vertical-striped.png +0 -0
  172. bootstack/assets/widgets/progress-trough-horizontal.png +0 -0
  173. bootstack/assets/widgets/progress-trough-vertical.png +0 -0
  174. bootstack/assets/widgets/radio-selected.png +0 -0
  175. bootstack/assets/widgets/radio-unselected.png +0 -0
  176. bootstack/assets/widgets/scrollbar-horizontal-rounded.png +0 -0
  177. bootstack/assets/widgets/scrollbar-vertical-rounded.png +0 -0
  178. bootstack/assets/widgets/separator-horizontal.png +0 -0
  179. bootstack/assets/widgets/separator-vertical.png +0 -0
  180. bootstack/assets/widgets/slider-handle-focus.png +0 -0
  181. bootstack/assets/widgets/slider-handle.png +0 -0
  182. bootstack/assets/widgets/slider-track-horizontal.png +0 -0
  183. bootstack/assets/widgets/slider-track-vertical.png +0 -0
  184. bootstack/assets/widgets/switch-off.png +0 -0
  185. bootstack/assets/widgets/switch-on.png +0 -0
  186. bootstack/assets/widgets/tabs-bar-horizontal.png +0 -0
  187. bootstack/assets/widgets/tabs-bar-vertical.png +0 -0
  188. bootstack/assets/widgets/tabs-pill.png +0 -0
  189. bootstack/cli/__init__.py +124 -0
  190. bootstack/cli/__main__.py +6 -0
  191. bootstack/cli/add.py +439 -0
  192. bootstack/cli/build.py +115 -0
  193. bootstack/cli/config.py +287 -0
  194. bootstack/cli/demo.py +1267 -0
  195. bootstack/cli/doctor.py +195 -0
  196. bootstack/cli/list_cmd.py +71 -0
  197. bootstack/cli/promote.py +120 -0
  198. bootstack/cli/pyinstaller.py +246 -0
  199. bootstack/cli/run.py +99 -0
  200. bootstack/cli/start.py +105 -0
  201. bootstack/cli/templates/__init__.py +861 -0
  202. bootstack/constants.py +325 -0
  203. bootstack/core/__init__.py +34 -0
  204. bootstack/core/capabilities/__init__.py +45 -0
  205. bootstack/core/capabilities/after.py +103 -0
  206. bootstack/core/capabilities/bind.py +154 -0
  207. bootstack/core/capabilities/bindtags.py +112 -0
  208. bootstack/core/capabilities/busy.py +61 -0
  209. bootstack/core/capabilities/clipboard.py +88 -0
  210. bootstack/core/capabilities/focus.py +118 -0
  211. bootstack/core/capabilities/grab.py +65 -0
  212. bootstack/core/capabilities/grid.py +188 -0
  213. bootstack/core/capabilities/localization.py +231 -0
  214. bootstack/core/capabilities/pack.py +119 -0
  215. bootstack/core/capabilities/place.py +92 -0
  216. bootstack/core/capabilities/selection.py +136 -0
  217. bootstack/core/capabilities/signals.py +242 -0
  218. bootstack/core/capabilities/winfo.py +315 -0
  219. bootstack/core/colorutils.py +234 -0
  220. bootstack/core/exceptions.py +95 -0
  221. bootstack/core/images.py +283 -0
  222. bootstack/core/localization/README.md +90 -0
  223. bootstack/core/localization/__init__.py +13 -0
  224. bootstack/core/localization/intl_format.py +580 -0
  225. bootstack/core/localization/msgcat.py +425 -0
  226. bootstack/core/localization/specs.py +143 -0
  227. bootstack/core/mixins/__init__.py +1 -0
  228. bootstack/core/mixins/ttk_state.py +35 -0
  229. bootstack/core/mixins/widget.py +132 -0
  230. bootstack/core/publisher.py +147 -0
  231. bootstack/core/signals/README.md +112 -0
  232. bootstack/core/signals/__init__.py +8 -0
  233. bootstack/core/signals/integration.py +100 -0
  234. bootstack/core/signals/signal.py +317 -0
  235. bootstack/core/signals/types.py +4 -0
  236. bootstack/core/validation/__init__.py +5 -0
  237. bootstack/core/validation/types.py +13 -0
  238. bootstack/core/validation/validation_result.py +17 -0
  239. bootstack/core/validation/validation_rules.py +112 -0
  240. bootstack/core/variables.py +62 -0
  241. bootstack/datasource/README.md +607 -0
  242. bootstack/datasource/__init__.py +51 -0
  243. bootstack/datasource/base.py +474 -0
  244. bootstack/datasource/file_source.py +541 -0
  245. bootstack/datasource/memory_source.py +482 -0
  246. bootstack/datasource/sqlite_source.py +453 -0
  247. bootstack/datasource/types.py +259 -0
  248. bootstack/dialogs/__init__.py +56 -0
  249. bootstack/dialogs/colorchooser.py +674 -0
  250. bootstack/dialogs/colordropper.py +257 -0
  251. bootstack/dialogs/datedialog.py +404 -0
  252. bootstack/dialogs/dialog.py +514 -0
  253. bootstack/dialogs/filterdialog.py +358 -0
  254. bootstack/dialogs/fontdialog.py +339 -0
  255. bootstack/dialogs/formdialog.py +541 -0
  256. bootstack/dialogs/message.py +489 -0
  257. bootstack/dialogs/query.py +561 -0
  258. bootstack/py.typed +1 -0
  259. bootstack/runtime/__init__.py +3 -0
  260. bootstack/runtime/app.py +879 -0
  261. bootstack/runtime/base_window.py +786 -0
  262. bootstack/runtime/events.py +399 -0
  263. bootstack/runtime/menu.py +510 -0
  264. bootstack/runtime/shortcuts.py +423 -0
  265. bootstack/runtime/tk_patch.py +31 -0
  266. bootstack/runtime/toplevel.py +131 -0
  267. bootstack/runtime/utility.py +371 -0
  268. bootstack/runtime/visual_focus.py +228 -0
  269. bootstack/runtime/window_utilities.py +1043 -0
  270. bootstack/style/__init__.py +5498 -0
  271. bootstack/style/bootstyle.py +507 -0
  272. bootstack/style/bootstyle_builder_base.py +752 -0
  273. bootstack/style/bootstyle_builder_mixed.py +93 -0
  274. bootstack/style/bootstyle_builder_tk.py +109 -0
  275. bootstack/style/bootstyle_builder_ttk.py +354 -0
  276. bootstack/style/builders/__init__.py +51 -0
  277. bootstack/style/builders/badge.py +44 -0
  278. bootstack/style/builders/button.py +453 -0
  279. bootstack/style/builders/buttongroup.py +344 -0
  280. bootstack/style/builders/calendar.py +271 -0
  281. bootstack/style/builders/checkbutton.py +95 -0
  282. bootstack/style/builders/combobox.py +112 -0
  283. bootstack/style/builders/contextmenu.py +268 -0
  284. bootstack/style/builders/entry.py +83 -0
  285. bootstack/style/builders/expander.py +171 -0
  286. bootstack/style/builders/field.py +312 -0
  287. bootstack/style/builders/frame.py +27 -0
  288. bootstack/style/builders/label.py +28 -0
  289. bootstack/style/builders/labelframe.py +41 -0
  290. bootstack/style/builders/listview.py +267 -0
  291. bootstack/style/builders/menubar.py +74 -0
  292. bootstack/style/builders/menubutton.py +408 -0
  293. bootstack/style/builders/notebook.py +316 -0
  294. bootstack/style/builders/panedwindow.py +25 -0
  295. bootstack/style/builders/progressbar.py +71 -0
  296. bootstack/style/builders/radiobutton.py +68 -0
  297. bootstack/style/builders/scale.py +66 -0
  298. bootstack/style/builders/scrollbar.py +360 -0
  299. bootstack/style/builders/separator.py +45 -0
  300. bootstack/style/builders/sidenav.py +313 -0
  301. bootstack/style/builders/sizegrip.py +15 -0
  302. bootstack/style/builders/spinbox.py +119 -0
  303. bootstack/style/builders/switch.py +67 -0
  304. bootstack/style/builders/tabitem.py +205 -0
  305. bootstack/style/builders/toolbutton.py +260 -0
  306. bootstack/style/builders/tooltip.py +26 -0
  307. bootstack/style/builders/treeview.py +269 -0
  308. bootstack/style/builders/utils.py +404 -0
  309. bootstack/style/builders_tk/__init__.py +16 -0
  310. bootstack/style/builders_tk/defaults.py +229 -0
  311. bootstack/style/element.py +173 -0
  312. bootstack/style/style.py +499 -0
  313. bootstack/style/theme_provider.py +449 -0
  314. bootstack/style/tk_patch.py +5 -0
  315. bootstack/style/token_maps.py +42 -0
  316. bootstack/style/types.py +32 -0
  317. bootstack/style/typography.py +527 -0
  318. bootstack/style/utility.py +696 -0
  319. bootstack/themes/__init__.py +12 -0
  320. bootstack/themes/standard.py +415 -0
  321. bootstack/themes/user.py +45 -0
  322. bootstack/widgets/__init__.py +53 -0
  323. bootstack/widgets/composites/__init__.py +38 -0
  324. bootstack/widgets/composites/accordion.py +385 -0
  325. bootstack/widgets/composites/appshell.py +445 -0
  326. bootstack/widgets/composites/buttongroup.py +391 -0
  327. bootstack/widgets/composites/calendar.py +914 -0
  328. bootstack/widgets/composites/compositeframe.py +282 -0
  329. bootstack/widgets/composites/contextmenu.py +1754 -0
  330. bootstack/widgets/composites/dateentry.py +261 -0
  331. bootstack/widgets/composites/dropdownbutton.py +190 -0
  332. bootstack/widgets/composites/expander.py +508 -0
  333. bootstack/widgets/composites/field.py +448 -0
  334. bootstack/widgets/composites/floodgauge.py +434 -0
  335. bootstack/widgets/composites/form.py +983 -0
  336. bootstack/widgets/composites/labeledscale.py +209 -0
  337. bootstack/widgets/composites/list/__init__.py +15 -0
  338. bootstack/widgets/composites/list/listitem.py +733 -0
  339. bootstack/widgets/composites/list/listview.py +1507 -0
  340. bootstack/widgets/composites/menubar.py +303 -0
  341. bootstack/widgets/composites/meter.py +882 -0
  342. bootstack/widgets/composites/numericentry.py +183 -0
  343. bootstack/widgets/composites/pagestack.py +330 -0
  344. bootstack/widgets/composites/passwordentry.py +149 -0
  345. bootstack/widgets/composites/pathentry.py +223 -0
  346. bootstack/widgets/composites/radiogroup.py +466 -0
  347. bootstack/widgets/composites/scrolledtext.py +388 -0
  348. bootstack/widgets/composites/scrolledtext.pyi +186 -0
  349. bootstack/widgets/composites/scrollview.py +675 -0
  350. bootstack/widgets/composites/selectbox.py +544 -0
  351. bootstack/widgets/composites/sidenav/__init__.py +24 -0
  352. bootstack/widgets/composites/sidenav/group.py +485 -0
  353. bootstack/widgets/composites/sidenav/header.py +83 -0
  354. bootstack/widgets/composites/sidenav/item.py +413 -0
  355. bootstack/widgets/composites/sidenav/separator.py +51 -0
  356. bootstack/widgets/composites/sidenav/view.py +919 -0
  357. bootstack/widgets/composites/spinnerentry.py +232 -0
  358. bootstack/widgets/composites/tableview/__init__.py +5 -0
  359. bootstack/widgets/composites/tableview/tableview.py +2254 -0
  360. bootstack/widgets/composites/tableview/types.py +169 -0
  361. bootstack/widgets/composites/tabs/__init__.py +6 -0
  362. bootstack/widgets/composites/tabs/tabitem.py +372 -0
  363. bootstack/widgets/composites/tabs/tabs.py +478 -0
  364. bootstack/widgets/composites/tabs/tabview.py +352 -0
  365. bootstack/widgets/composites/textentry.py +90 -0
  366. bootstack/widgets/composites/timeentry.py +189 -0
  367. bootstack/widgets/composites/toast.py +364 -0
  368. bootstack/widgets/composites/togglegroup.py +382 -0
  369. bootstack/widgets/composites/toolbar.py +393 -0
  370. bootstack/widgets/composites/tooltip.py +404 -0
  371. bootstack/widgets/internal/__init__.py +0 -0
  372. bootstack/widgets/internal/wrapper_base.py +304 -0
  373. bootstack/widgets/mixins/__init__.py +25 -0
  374. bootstack/widgets/mixins/configure_mixin.py +186 -0
  375. bootstack/widgets/mixins/entry_mixin.py +70 -0
  376. bootstack/widgets/mixins/font_mixin.py +346 -0
  377. bootstack/widgets/mixins/icon_mixin.py +38 -0
  378. bootstack/widgets/mixins/localization_mixin.py +255 -0
  379. bootstack/widgets/mixins/signal_mixin.py +272 -0
  380. bootstack/widgets/mixins/validation_mixin.py +204 -0
  381. bootstack/widgets/parts/__init__.py +11 -0
  382. bootstack/widgets/parts/numberentry_part.py +345 -0
  383. bootstack/widgets/parts/spinnerentry_part.py +394 -0
  384. bootstack/widgets/parts/textentry_part.py +344 -0
  385. bootstack/widgets/primitives/__init__.py +55 -0
  386. bootstack/widgets/primitives/badge.py +44 -0
  387. bootstack/widgets/primitives/button.py +89 -0
  388. bootstack/widgets/primitives/card.py +66 -0
  389. bootstack/widgets/primitives/checkbutton.py +124 -0
  390. bootstack/widgets/primitives/checktoggle.py +53 -0
  391. bootstack/widgets/primitives/combobox.py +165 -0
  392. bootstack/widgets/primitives/entry.py +98 -0
  393. bootstack/widgets/primitives/frame.py +206 -0
  394. bootstack/widgets/primitives/gridframe.py +479 -0
  395. bootstack/widgets/primitives/label.py +95 -0
  396. bootstack/widgets/primitives/labelframe.py +63 -0
  397. bootstack/widgets/primitives/menubutton.py +118 -0
  398. bootstack/widgets/primitives/notebook.py +551 -0
  399. bootstack/widgets/primitives/optionmenu.py +248 -0
  400. bootstack/widgets/primitives/packframe.py +228 -0
  401. bootstack/widgets/primitives/panedwindow.py +58 -0
  402. bootstack/widgets/primitives/progressbar.py +95 -0
  403. bootstack/widgets/primitives/radiobutton.py +115 -0
  404. bootstack/widgets/primitives/radiotoggle.py +50 -0
  405. bootstack/widgets/primitives/scale.py +85 -0
  406. bootstack/widgets/primitives/scrollbar.py +56 -0
  407. bootstack/widgets/primitives/separator.py +56 -0
  408. bootstack/widgets/primitives/sizegrip.py +47 -0
  409. bootstack/widgets/primitives/spinbox.py +91 -0
  410. bootstack/widgets/primitives/switch.py +41 -0
  411. bootstack/widgets/primitives/treeview.py +77 -0
  412. bootstack/widgets/types.py +20 -0
  413. bootstack-0.1.0a1.dist-info/METADATA +196 -0
  414. bootstack-0.1.0a1.dist-info/RECORD +419 -0
  415. bootstack-0.1.0a1.dist-info/WHEEL +5 -0
  416. bootstack-0.1.0a1.dist-info/entry_points.txt +2 -0
  417. bootstack-0.1.0a1.dist-info/licenses/LICENSE +22 -0
  418. bootstack-0.1.0a1.dist-info/licenses/NOTICE +10 -0
  419. bootstack-0.1.0a1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,861 @@
1
+ """Project templates for bootstack start command."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Literal
7
+
8
+ ContainerType = Literal["grid", "pack"]
9
+ TemplateType = Literal["basic", "appshell"]
10
+
11
+
12
+ # =============================================================================
13
+ # Main entry point template
14
+ # =============================================================================
15
+
16
+ MAIN_PY_TEMPLATE = '''\
17
+ """
18
+ {app_name} - A bootstack application.
19
+
20
+ Run with: python -m {module_name}
21
+ """
22
+
23
+ import os
24
+
25
+ import bootstack as bs
26
+
27
+ from {module_name}.views.main_view import MainView
28
+
29
+
30
+ def main() -> None:
31
+ """Application entry point."""
32
+ app = bs.App(
33
+ title="{app_name}",
34
+ theme=os.environ.get("BOOTSTACK_THEME", "{theme}"),
35
+ size=(800, 600),
36
+ )
37
+
38
+ # Create and display main view
39
+ MainView(app).pack(fill="both", expand=True)
40
+
41
+ app.mainloop()
42
+
43
+
44
+ if __name__ == "__main__":
45
+ main()
46
+ '''
47
+
48
+
49
+ # =============================================================================
50
+ # View templates (GridFrame vs PackFrame)
51
+ # =============================================================================
52
+
53
+ MAIN_VIEW_GRID_TEMPLATE = '''\
54
+ """Main application view."""
55
+
56
+ import bootstack as bs
57
+
58
+
59
+ class MainView(bs.GridFrame):
60
+ """Main view using GridFrame layout."""
61
+
62
+ def __init__(self, master, **kwargs):
63
+ super().__init__(
64
+ master,
65
+ columns=["auto", 1],
66
+ gap=10,
67
+ padding=20,
68
+ **kwargs,
69
+ )
70
+ self._create_widgets()
71
+
72
+ def _create_widgets(self) -> None:
73
+ """Create and layout widgets."""
74
+ # Header
75
+ bs.Label(
76
+ self,
77
+ text="Welcome to {app_name}",
78
+ font=("TkDefaultFont", 18, "bold"),
79
+ ).grid(row=0, column=0, columnspan=2, sticky="w", pady=(0, 20))
80
+
81
+ # Example form layout
82
+ bs.Label(self, text="Name:").grid(row=1, column=0, sticky="e")
83
+ self.name_entry = bs.Entry(self)
84
+ self.name_entry.grid(row=1, column=1, sticky="ew")
85
+
86
+ bs.Label(self, text="Email:").grid(row=2, column=0, sticky="e")
87
+ self.email_entry = bs.Entry(self)
88
+ self.email_entry.grid(row=2, column=1, sticky="ew")
89
+
90
+ # Action button
91
+ bs.Button(
92
+ self,
93
+ text="Get Started",
94
+ accent="primary",
95
+ command=self._on_submit,
96
+ ).grid(row=3, column=0, columnspan=2, pady=(20, 0))
97
+
98
+ def _on_submit(self) -> None:
99
+ """Handle form submission."""
100
+ name = self.name_entry.get()
101
+ email = self.email_entry.get()
102
+ print(f"Name: {{name}}, Email: {{email}}")
103
+ '''
104
+
105
+
106
+ MAIN_VIEW_PACK_TEMPLATE = '''\
107
+ """Main application view."""
108
+
109
+ import bootstack as bs
110
+
111
+
112
+ class MainView(bs.PackFrame):
113
+ """Main view using PackFrame layout."""
114
+
115
+ def __init__(self, master, **kwargs):
116
+ super().__init__(
117
+ master,
118
+ direction="vertical",
119
+ gap=10,
120
+ padding=20,
121
+ **kwargs,
122
+ )
123
+ self._create_widgets()
124
+
125
+ def _create_widgets(self) -> None:
126
+ """Create and layout widgets."""
127
+ # Header
128
+ header = bs.Label(
129
+ self,
130
+ text="Welcome to {app_name}",
131
+ font=("TkDefaultFont", 18, "bold"),
132
+ )
133
+ self.add(header)
134
+
135
+ # Spacer
136
+ self.add(bs.Frame(self, height=10))
137
+
138
+ # Name field
139
+ name_frame = bs.PackFrame(self, direction="horizontal", gap=10)
140
+ bs.Label(name_frame, text="Name:", width=10).pack(side="left")
141
+ self.name_entry = bs.Entry(name_frame)
142
+ self.name_entry.pack(side="left", fill="x", expand=True)
143
+ self.add(name_frame, fill_items="x")
144
+
145
+ # Email field
146
+ email_frame = bs.PackFrame(self, direction="horizontal", gap=10)
147
+ bs.Label(email_frame, text="Email:", width=10).pack(side="left")
148
+ self.email_entry = bs.Entry(email_frame)
149
+ self.email_entry.pack(side="left", fill="x", expand=True)
150
+ self.add(email_frame, fill_items="x")
151
+
152
+ # Action button
153
+ self.add(bs.Frame(self, height=10))
154
+ btn = bs.Button(
155
+ self,
156
+ text="Get Started",
157
+ accent="primary",
158
+ command=self._on_submit,
159
+ )
160
+ self.add(btn)
161
+
162
+ def _on_submit(self) -> None:
163
+ """Handle form submission."""
164
+ name = self.name_entry.get()
165
+ email = self.email_entry.get()
166
+ print(f"Name: {{name}}, Email: {{email}}")
167
+ '''
168
+
169
+
170
+ # =============================================================================
171
+ # View/Dialog add templates
172
+ # =============================================================================
173
+
174
+ VIEW_GRID_TEMPLATE = '''\
175
+ """
176
+ {class_name} view.
177
+ """
178
+
179
+ import bootstack as bs
180
+
181
+
182
+ class {class_name}(bs.GridFrame):
183
+ """{class_name} using GridFrame layout."""
184
+
185
+ def __init__(self, master, **kwargs):
186
+ super().__init__(
187
+ master,
188
+ columns=["auto", 1],
189
+ gap=10,
190
+ padding=20,
191
+ **kwargs,
192
+ )
193
+ self._create_widgets()
194
+
195
+ def _create_widgets(self) -> None:
196
+ """Create and layout widgets."""
197
+ bs.Label(
198
+ self,
199
+ text="{class_name}",
200
+ font=("TkDefaultFont", 14, "bold"),
201
+ ).grid(row=0, column=0, columnspan=2, sticky="w")
202
+
203
+ # Add your widgets here
204
+ '''
205
+
206
+
207
+ VIEW_PACK_TEMPLATE = '''\
208
+ """
209
+ {class_name} view.
210
+ """
211
+
212
+ import bootstack as bs
213
+
214
+
215
+ class {class_name}(bs.PackFrame):
216
+ """{class_name} using PackFrame layout."""
217
+
218
+ def __init__(self, master, **kwargs):
219
+ super().__init__(
220
+ master,
221
+ direction="vertical",
222
+ gap=10,
223
+ padding=20,
224
+ **kwargs,
225
+ )
226
+ self._create_widgets()
227
+
228
+ def _create_widgets(self) -> None:
229
+ """Create and layout widgets."""
230
+ header = bs.Label(
231
+ self,
232
+ text="{class_name}",
233
+ font=("TkDefaultFont", 14, "bold"),
234
+ )
235
+ self.add(header)
236
+
237
+ # Add your widgets here
238
+ '''
239
+
240
+
241
+ DIALOG_TEMPLATE = '''\
242
+ """
243
+ {class_name} dialog.
244
+ """
245
+
246
+ import bootstack as bs
247
+ from bootstack.dialogs import Dialog
248
+
249
+
250
+ class {class_name}(Dialog):
251
+ """{class_name} modal dialog."""
252
+
253
+ def __init__(self, parent, title: str = "{class_name}", **kwargs):
254
+ super().__init__(parent, title=title, **kwargs)
255
+
256
+ def create_body(self, master) -> bs.Frame:
257
+ """Create the dialog body."""
258
+ body = bs.Frame(master, padding=20)
259
+
260
+ bs.Label(
261
+ body,
262
+ text="Dialog content goes here",
263
+ ).pack(pady=10)
264
+
265
+ return body
266
+
267
+ def create_buttonbox(self, master) -> bs.Frame:
268
+ """Create the dialog buttons."""
269
+ box = bs.Frame(master, padding=(20, 10))
270
+
271
+ bs.Button(
272
+ box,
273
+ text="Cancel",
274
+ command=self.cancel,
275
+ ).pack(side="right", padx=5)
276
+
277
+ bs.Button(
278
+ box,
279
+ text="OK",
280
+ accent="primary",
281
+ command=self.ok,
282
+ ).pack(side="right")
283
+
284
+ return box
285
+
286
+ def validate(self) -> bool:
287
+ """Validate dialog input before closing."""
288
+ return True
289
+
290
+ def apply(self) -> None:
291
+ """Process dialog input after OK is clicked."""
292
+ self.result = True
293
+ '''
294
+
295
+
296
+ # =============================================================================
297
+ # Package init template
298
+ # =============================================================================
299
+
300
+ INIT_PY_TEMPLATE = '''\
301
+ """{app_name} package."""
302
+
303
+ __version__ = "0.1.0"
304
+ '''
305
+
306
+
307
+ # =============================================================================
308
+ # README template
309
+ # =============================================================================
310
+
311
+ README_TEMPLATE = '''\
312
+ # {app_name}
313
+
314
+ A bootstack application.
315
+
316
+ ## Getting Started
317
+
318
+ ### Development
319
+
320
+ ```bash
321
+ # Run the application
322
+ python -m {module_name}
323
+
324
+ # Or use the CLI
325
+ bootstack run
326
+ ```
327
+
328
+ ### Building for Distribution
329
+
330
+ ```bash
331
+ # Promote to packaging-ready (adds PyInstaller support)
332
+ bootstack promote --pyinstaller
333
+
334
+ # Build the executable
335
+ bootstack build
336
+ ```
337
+
338
+ ## Project Structure
339
+
340
+ ```
341
+ {project_dir}/
342
+ ├── src/{module_name}/
343
+ │ ├── __init__.py
344
+ │ ├── main.py
345
+ │ └── views/
346
+ │ └── main_view.py
347
+ ├── assets/
348
+ ├── bootstack.toml
349
+ └── README.md
350
+ ```
351
+
352
+ ## Configuration
353
+
354
+ Application settings are defined in `bootstack.toml`:
355
+
356
+ - `[app]` - Application metadata
357
+ - `[settings]` - Runtime settings (theme, language)
358
+ - `[layout]` - Default layout preferences
359
+ - `[build]` - Build/packaging configuration (after `bootstack promote`)
360
+ '''
361
+
362
+
363
+ # =============================================================================
364
+ # AppShell templates
365
+ # =============================================================================
366
+
367
+ APPSHELL_MAIN_PY_TEMPLATE = '''\
368
+ """
369
+ {app_name} - A bootstack application.
370
+
371
+ Run with: python -m {module_name}
372
+ """
373
+
374
+ import os
375
+
376
+ import bootstack as bs
377
+
378
+ from {module_name}.pages.home_page import HomePage
379
+ from {module_name}.pages.settings_page import SettingsPage
380
+
381
+
382
+ def main() -> None:
383
+ """Application entry point."""
384
+ shell = bs.AppShell(
385
+ title="{app_name}",
386
+ theme=os.environ.get("BOOTSTACK_THEME", "{theme}"),
387
+ size=(1000, 650),
388
+ )
389
+
390
+ # Add a theme toggle button to the toolbar
391
+ shell.toolbar.add_button(icon="sun", command=bs.toggle_theme)
392
+
393
+ # Navigation pages
394
+ home = shell.add_page("home", text="Home", icon="house")
395
+ HomePage(home)
396
+
397
+ shell.add_separator()
398
+
399
+ # Footer pages
400
+ settings = shell.add_page("settings", text="Settings", icon="gear", is_footer=True)
401
+ SettingsPage(settings)
402
+
403
+ # Start on the home page
404
+ shell.navigate("home")
405
+ shell.mainloop()
406
+
407
+
408
+ if __name__ == "__main__":
409
+ main()
410
+ '''
411
+
412
+
413
+ APPSHELL_HOME_PAGE_TEMPLATE = '''\
414
+ """Home page."""
415
+
416
+ import bootstack as bs
417
+
418
+
419
+ class HomePage:
420
+ """Home page content.
421
+
422
+ Pages in an AppShell are not widget subclasses. The `parent` frame
423
+ is created by `shell.add_page()` and this class populates it.
424
+ """
425
+
426
+ def __init__(self, parent):
427
+ self.parent = parent
428
+ self._build()
429
+
430
+ def _build(self):
431
+ bs.Label(
432
+ self.parent,
433
+ text="Welcome to {app_name}",
434
+ font="heading-xl",
435
+ ).pack(anchor="w", padx=20, pady=(20, 10))
436
+
437
+ bs.Label(
438
+ self.parent,
439
+ text="This is your home page. Edit this file to get started.",
440
+ wraplength=500,
441
+ ).pack(anchor="w", padx=20, pady=(0, 20))
442
+
443
+ content = bs.LabelFrame(self.parent, text="Getting Started", padding=20)
444
+ content.pack(fill="both", expand=True, padx=20, pady=(0, 20))
445
+
446
+ bs.Label(
447
+ content,
448
+ text=(
449
+ "Add your widgets here.\\n\\n"
450
+ "To add another page:\\n"
451
+ " 1. Run 'bootstack add page <Name>' to generate the file under pages/.\\n"
452
+ " 2. In main.py, import it, call shell.add_page(...), and pass\\n"
453
+ " the returned frame to your page class. The CLI prints the\\n"
454
+ " exact lines to paste."
455
+ ),
456
+ ).pack(expand=True)
457
+ '''
458
+
459
+
460
+ APPSHELL_SETTINGS_PAGE_TEMPLATE = '''\
461
+ """Settings page."""
462
+
463
+ import bootstack as bs
464
+
465
+
466
+ class SettingsPage:
467
+ """Settings page content.
468
+
469
+ Pages in an AppShell are not widget subclasses. The `parent` frame
470
+ is created by `shell.add_page()` and this class populates it.
471
+ """
472
+
473
+ def __init__(self, parent):
474
+ self.parent = parent
475
+ self._build()
476
+
477
+ def _build(self):
478
+ bs.Label(
479
+ self.parent,
480
+ text="Settings",
481
+ font="heading-xl",
482
+ ).pack(anchor="w", padx=20, pady=(20, 10))
483
+
484
+ bs.Label(
485
+ self.parent,
486
+ text="Configure your application preferences.",
487
+ wraplength=500,
488
+ ).pack(anchor="w", padx=20, pady=(0, 20))
489
+
490
+ content = bs.LabelFrame(self.parent, text="Preferences", padding=20)
491
+ content.pack(fill="both", expand=True, padx=20, pady=(0, 20))
492
+
493
+ # Example settings
494
+ theme_frame = bs.Frame(content)
495
+ theme_frame.pack(fill="x", pady=(0, 10))
496
+ bs.Label(theme_frame, text="Theme:", width=15).pack(side="left")
497
+ bs.Button(
498
+ theme_frame,
499
+ text="Toggle Light/Dark",
500
+ command=bs.toggle_theme,
501
+ ).pack(side="left")
502
+ '''
503
+
504
+
505
+ APPSHELL_PAGE_TEMPLATE = '''\
506
+ """{page_title} page."""
507
+
508
+ import bootstack as bs
509
+
510
+
511
+ class {class_name}:
512
+ """{page_title} page content.
513
+
514
+ Pages in an AppShell are not widget subclasses. The `parent` frame
515
+ is created by `shell.add_page()` and this class populates it.
516
+ """
517
+
518
+ def __init__(self, parent):
519
+ self.parent = parent
520
+ self._build()
521
+
522
+ def _build(self):
523
+ bs.Label(
524
+ self.parent,
525
+ text="{page_title}",
526
+ font="heading-xl",
527
+ ).pack(anchor="w", padx=20, pady=(20, 10))
528
+
529
+ content = bs.LabelFrame(self.parent, text="Content", padding=20)
530
+ content.pack(fill="both", expand=True, padx=20, pady=(0, 20))
531
+
532
+ # Add your widgets here
533
+ '''
534
+
535
+
536
+ APPSHELL_README_TEMPLATE = '''\
537
+ # {app_name}
538
+
539
+ A bootstack application using AppShell navigation.
540
+
541
+ ## Getting Started
542
+
543
+ ### Development
544
+
545
+ ```bash
546
+ # Run the application
547
+ python -m {module_name}
548
+
549
+ # Or use the CLI
550
+ bootstack run
551
+ ```
552
+
553
+ ### Adding Pages
554
+
555
+ ```bash
556
+ # Scaffold a new page
557
+ bootstack add page DashboardPage
558
+
559
+ # Then wire it up in main.py:
560
+ # from {module_name}.pages.dashboard_page import DashboardPage
561
+ # page = shell.add_page("dashboard", text="Dashboard", icon="speedometer2")
562
+ # DashboardPage(page)
563
+ ```
564
+
565
+ ### Building for Distribution
566
+
567
+ ```bash
568
+ # Promote to packaging-ready (adds PyInstaller support)
569
+ bootstack promote --pyinstaller
570
+
571
+ # Build the executable
572
+ bootstack build
573
+ ```
574
+
575
+ ## Project Structure
576
+
577
+ ```
578
+ {project_dir}/
579
+ \u251c\u2500\u2500 src/{module_name}/
580
+ \u2502 \u251c\u2500\u2500 __init__.py
581
+ \u2502 \u251c\u2500\u2500 main.py
582
+ \u2502 \u2514\u2500\u2500 pages/
583
+ \u2502 \u251c\u2500\u2500 __init__.py
584
+ \u2502 \u251c\u2500\u2500 home_page.py
585
+ \u2502 \u2514\u2500\u2500 settings_page.py
586
+ \u251c\u2500\u2500 assets/
587
+ \u251c\u2500\u2500 bootstack.toml
588
+ \u2514\u2500\u2500 README.md
589
+ ```
590
+
591
+ ## Configuration
592
+
593
+ Application settings are defined in `bootstack.toml`:
594
+
595
+ - `[app]` - Application metadata
596
+ - `[settings]` - Runtime settings (theme, language)
597
+ - `[layout]` - Default layout preferences
598
+ - `[build]` - Build/packaging configuration (after `bootstack promote`)
599
+ '''
600
+
601
+
602
+ def create_page(
603
+ class_name: str,
604
+ target_dir: Path,
605
+ scrollable: bool = False,
606
+ ) -> Path:
607
+ """Create a new AppShell page file.
608
+
609
+ Args:
610
+ class_name: Page class name (CamelCase).
611
+ target_dir: Directory to create the page in.
612
+ scrollable: If True, the page template notes that
613
+ `scrollable=True` should be passed to `add_page()`.
614
+
615
+ Returns:
616
+ Path to the created file.
617
+ """
618
+ file_name = _camel_to_snake(class_name) + ".py"
619
+
620
+ # Derive a readable title from the class name (e.g. "DashboardPage" -> "Dashboard")
621
+ page_title = class_name
622
+ if page_title.endswith("Page"):
623
+ page_title = page_title[:-4]
624
+ # Insert spaces before uppercase letters
625
+ import re
626
+ page_title = re.sub(r"([a-z])([A-Z])", r"\1 \2", page_title)
627
+
628
+ content = APPSHELL_PAGE_TEMPLATE.format(
629
+ class_name=class_name,
630
+ page_title=page_title,
631
+ )
632
+
633
+ file_path = target_dir / file_name
634
+ file_path.write_text(content, encoding="utf-8")
635
+
636
+ return file_path
637
+
638
+
639
+ def create_project(
640
+ name: str,
641
+ target_dir: Path,
642
+ container: ContainerType = "grid",
643
+ theme: str = "bootstrap-light",
644
+ template: TemplateType = "basic",
645
+ simple: bool = False,
646
+ ) -> None:
647
+ """Create a new bootstack project.
648
+
649
+ Args:
650
+ name: Application name.
651
+ target_dir: Target directory for the project.
652
+ container: Default container type ('grid' or 'pack').
653
+ theme: Theme name for the application.
654
+ template: Project template ('basic' or 'appshell').
655
+ simple: If True, create minimal project without build config.
656
+ """
657
+ if template == "appshell":
658
+ _create_appshell_project(name, target_dir, theme, simple)
659
+ else:
660
+ _create_basic_project(name, target_dir, container, theme, simple)
661
+
662
+
663
+ def _create_basic_project(
664
+ name: str,
665
+ target_dir: Path,
666
+ container: ContainerType,
667
+ theme: str,
668
+ simple: bool,
669
+ ) -> None:
670
+ """Create a basic single-view project."""
671
+ from bootstack.cli.config import write_config
672
+
673
+ # Normalize names
674
+ name_lower = name.lower().replace(" ", "_").replace("-", "_")
675
+ module_name = name_lower
676
+
677
+ # Create directory structure
678
+ src_dir = target_dir / "src" / module_name
679
+ views_dir = src_dir / "views"
680
+ assets_dir = target_dir / "assets"
681
+
682
+ src_dir.mkdir(parents=True, exist_ok=True)
683
+ views_dir.mkdir(parents=True, exist_ok=True)
684
+ if not simple:
685
+ assets_dir.mkdir(parents=True, exist_ok=True)
686
+
687
+ # Write main.py
688
+ main_content = MAIN_PY_TEMPLATE.format(
689
+ app_name=name,
690
+ module_name=module_name,
691
+ theme=theme,
692
+ )
693
+ (src_dir / "main.py").write_text(main_content, encoding="utf-8")
694
+
695
+ # Write __init__.py
696
+ init_content = INIT_PY_TEMPLATE.format(app_name=name)
697
+ (src_dir / "__init__.py").write_text(init_content, encoding="utf-8")
698
+
699
+ # Write views/__init__.py
700
+ (views_dir / "__init__.py").write_text(
701
+ '"""Views package."""\n', encoding="utf-8"
702
+ )
703
+
704
+ # Write main_view.py
705
+ if container == "grid":
706
+ view_template = MAIN_VIEW_GRID_TEMPLATE
707
+ else:
708
+ view_template = MAIN_VIEW_PACK_TEMPLATE
709
+
710
+ view_content = view_template.format(app_name=name)
711
+ (views_dir / "main_view.py").write_text(view_content, encoding="utf-8")
712
+
713
+ # Write bootstack.toml
714
+ write_config(
715
+ path=target_dir / "bootstack.toml",
716
+ name=name,
717
+ entry=f"src/{module_name}/main.py",
718
+ theme=theme,
719
+ template="basic",
720
+ include_build=False,
721
+ )
722
+
723
+ # Write README.md
724
+ if not simple:
725
+ readme_content = README_TEMPLATE.format(
726
+ app_name=name,
727
+ module_name=module_name,
728
+ project_dir=target_dir.name,
729
+ )
730
+ (target_dir / "README.md").write_text(readme_content, encoding="utf-8")
731
+
732
+
733
+ def _create_appshell_project(
734
+ name: str,
735
+ target_dir: Path,
736
+ theme: str,
737
+ simple: bool,
738
+ ) -> None:
739
+ """Create an AppShell project with sidebar navigation and pages."""
740
+ from bootstack.cli.config import write_config
741
+
742
+ # Normalize names
743
+ name_lower = name.lower().replace(" ", "_").replace("-", "_")
744
+ module_name = name_lower
745
+
746
+ # Create directory structure
747
+ src_dir = target_dir / "src" / module_name
748
+ pages_dir = src_dir / "pages"
749
+ assets_dir = target_dir / "assets"
750
+
751
+ src_dir.mkdir(parents=True, exist_ok=True)
752
+ pages_dir.mkdir(parents=True, exist_ok=True)
753
+ if not simple:
754
+ assets_dir.mkdir(parents=True, exist_ok=True)
755
+
756
+ # Write main.py
757
+ main_content = APPSHELL_MAIN_PY_TEMPLATE.format(
758
+ app_name=name,
759
+ module_name=module_name,
760
+ theme=theme,
761
+ )
762
+ (src_dir / "main.py").write_text(main_content, encoding="utf-8")
763
+
764
+ # Write __init__.py
765
+ init_content = INIT_PY_TEMPLATE.format(app_name=name)
766
+ (src_dir / "__init__.py").write_text(init_content, encoding="utf-8")
767
+
768
+ # Write pages/__init__.py
769
+ (pages_dir / "__init__.py").write_text(
770
+ '"""Pages package."""\n', encoding="utf-8"
771
+ )
772
+
773
+ # Write home_page.py
774
+ home_content = APPSHELL_HOME_PAGE_TEMPLATE.format(app_name=name)
775
+ (pages_dir / "home_page.py").write_text(home_content, encoding="utf-8")
776
+
777
+ # Write settings_page.py
778
+ (pages_dir / "settings_page.py").write_text(
779
+ APPSHELL_SETTINGS_PAGE_TEMPLATE, encoding="utf-8"
780
+ )
781
+
782
+ # Write bootstack.toml
783
+ write_config(
784
+ path=target_dir / "bootstack.toml",
785
+ name=name,
786
+ entry=f"src/{module_name}/main.py",
787
+ theme=theme,
788
+ template="appshell",
789
+ include_build=False,
790
+ )
791
+
792
+ # Write README.md
793
+ if not simple:
794
+ readme_content = APPSHELL_README_TEMPLATE.format(
795
+ app_name=name,
796
+ module_name=module_name,
797
+ project_dir=target_dir.name,
798
+ )
799
+ (target_dir / "README.md").write_text(readme_content, encoding="utf-8")
800
+
801
+
802
+ def create_view(
803
+ class_name: str,
804
+ target_dir: Path,
805
+ container: ContainerType = "grid",
806
+ ) -> Path:
807
+ """Create a new view file.
808
+
809
+ Args:
810
+ class_name: View class name (CamelCase).
811
+ target_dir: Directory to create the view in.
812
+ container: Container type ('grid' or 'pack').
813
+
814
+ Returns:
815
+ Path to the created file.
816
+ """
817
+ # Convert CamelCase to snake_case
818
+ file_name = _camel_to_snake(class_name) + ".py"
819
+
820
+ if container == "grid":
821
+ template = VIEW_GRID_TEMPLATE
822
+ else:
823
+ template = VIEW_PACK_TEMPLATE
824
+
825
+ content = template.format(class_name=class_name)
826
+
827
+ file_path = target_dir / file_name
828
+ file_path.write_text(content, encoding="utf-8")
829
+
830
+ return file_path
831
+
832
+
833
+ def create_dialog(
834
+ class_name: str,
835
+ target_dir: Path,
836
+ ) -> Path:
837
+ """Create a new dialog file.
838
+
839
+ Args:
840
+ class_name: Dialog class name (CamelCase).
841
+ target_dir: Directory to create the dialog in.
842
+
843
+ Returns:
844
+ Path to the created file.
845
+ """
846
+ file_name = _camel_to_snake(class_name) + ".py"
847
+ content = DIALOG_TEMPLATE.format(class_name=class_name)
848
+
849
+ file_path = target_dir / file_name
850
+ file_path.write_text(content, encoding="utf-8")
851
+
852
+ return file_path
853
+
854
+
855
+ def _camel_to_snake(name: str) -> str:
856
+ """Convert CamelCase to snake_case."""
857
+ import re
858
+
859
+ # Insert underscore before uppercase letters and lowercase
860
+ s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)
861
+ return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()