@vandenberghinc/volt 1.1.4 → 1.1.6

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 (290) hide show
  1. package/backend/dist/cjs/database.d.ts +41 -68
  2. package/backend/dist/cjs/database.js +136 -78
  3. package/backend/dist/cjs/endpoint.d.ts +23 -9
  4. package/backend/dist/cjs/endpoint.js +98 -21
  5. package/backend/dist/cjs/file_watcher.js +2 -2
  6. package/backend/dist/cjs/frontend.d.ts +0 -2
  7. package/backend/dist/cjs/frontend.js +9 -9
  8. package/backend/dist/cjs/image_endpoint.d.ts +3 -1
  9. package/backend/dist/cjs/image_endpoint.js +2 -1
  10. package/backend/dist/cjs/payments/paddle.js +10 -2
  11. package/backend/dist/cjs/plugins/css.d.ts +6 -5
  12. package/backend/dist/cjs/plugins/css.js +32 -7
  13. package/backend/dist/cjs/plugins/ts/compiler.d.ts +6 -1
  14. package/backend/dist/cjs/plugins/ts/compiler.js +26 -2
  15. package/backend/dist/cjs/plugins/ts/preprocessing.js +5 -3
  16. package/backend/dist/cjs/server.d.ts +7 -13
  17. package/backend/dist/cjs/server.js +184 -303
  18. package/backend/dist/cjs/status.d.ts +1 -0
  19. package/backend/dist/cjs/status.js +2 -1
  20. package/backend/dist/cjs/stream.d.ts +5 -3
  21. package/backend/dist/cjs/stream.js +13 -4
  22. package/backend/dist/cjs/users.d.ts +1 -1
  23. package/backend/dist/cjs/users.js +87 -72
  24. package/backend/dist/cjs/utils.d.ts +17 -9
  25. package/backend/dist/cjs/utils.js +22 -64
  26. package/backend/dist/cjs/view.d.ts +2 -2
  27. package/backend/dist/cjs/view.js +38 -40
  28. package/backend/dist/cjs/volt.d.ts +3 -2
  29. package/backend/dist/cjs/volt.js +2 -2
  30. package/backend/dist/css/volt.css +5 -0
  31. package/backend/dist/esm/database.d.ts +41 -68
  32. package/backend/dist/esm/database.js +137 -79
  33. package/backend/dist/esm/endpoint.d.ts +23 -9
  34. package/backend/dist/esm/endpoint.js +99 -22
  35. package/backend/dist/esm/file_watcher.js +2 -2
  36. package/backend/dist/esm/frontend.d.ts +0 -2
  37. package/backend/dist/esm/frontend.js +9 -9
  38. package/backend/dist/esm/image_endpoint.d.ts +3 -1
  39. package/backend/dist/esm/image_endpoint.js +2 -1
  40. package/backend/dist/esm/payments/paddle.js +11 -3
  41. package/backend/dist/esm/plugins/css.d.ts +6 -5
  42. package/backend/dist/esm/plugins/css.js +32 -6
  43. package/backend/dist/esm/plugins/ts/compiler.d.ts +6 -1
  44. package/backend/dist/esm/plugins/ts/compiler.js +26 -2
  45. package/backend/dist/esm/plugins/ts/preprocessing.js +5 -3
  46. package/backend/dist/esm/server.d.ts +7 -13
  47. package/backend/dist/esm/server.js +182 -301
  48. package/backend/dist/esm/status.d.ts +1 -0
  49. package/backend/dist/esm/status.js +1 -0
  50. package/backend/dist/esm/stream.d.ts +5 -3
  51. package/backend/dist/esm/stream.js +13 -4
  52. package/backend/dist/esm/users.d.ts +1 -1
  53. package/backend/dist/esm/users.js +87 -72
  54. package/backend/dist/esm/utils.d.ts +17 -9
  55. package/backend/dist/esm/utils.js +21 -62
  56. package/backend/dist/esm/view.d.ts +2 -2
  57. package/backend/dist/esm/view.js +38 -40
  58. package/backend/dist/esm/volt.d.ts +3 -2
  59. package/backend/dist/esm/volt.js +2 -1
  60. package/backend/dist/esm-dev/blacklist.js +1 -1
  61. package/backend/dist/esm-dev/cli.js +2 -2
  62. package/backend/dist/esm-dev/database.d.ts +41 -68
  63. package/backend/dist/esm-dev/database.js +138 -80
  64. package/backend/dist/esm-dev/endpoint.d.ts +23 -9
  65. package/backend/dist/esm-dev/endpoint.js +100 -23
  66. package/backend/dist/esm-dev/file_watcher.js +3 -3
  67. package/backend/dist/esm-dev/frontend.d.ts +0 -2
  68. package/backend/dist/esm-dev/frontend.js +9 -9
  69. package/backend/dist/esm-dev/image_endpoint.d.ts +3 -1
  70. package/backend/dist/esm-dev/image_endpoint.js +2 -1
  71. package/backend/dist/esm-dev/logger.js +1 -1
  72. package/backend/dist/esm-dev/payments/paddle.js +12 -4
  73. package/backend/dist/esm-dev/plugins/css.d.ts +6 -5
  74. package/backend/dist/esm-dev/plugins/css.js +33 -7
  75. package/backend/dist/esm-dev/plugins/ts/compiler.d.ts +6 -1
  76. package/backend/dist/esm-dev/plugins/ts/compiler.js +27 -3
  77. package/backend/dist/esm-dev/plugins/ts/preprocessing.js +7 -5
  78. package/backend/dist/esm-dev/rate_limit.js +1 -1
  79. package/backend/dist/esm-dev/server.d.ts +7 -13
  80. package/backend/dist/esm-dev/server.js +184 -303
  81. package/backend/dist/esm-dev/status.d.ts +1 -0
  82. package/backend/dist/esm-dev/status.js +1 -0
  83. package/backend/dist/esm-dev/stream.d.ts +5 -3
  84. package/backend/dist/esm-dev/stream.js +13 -4
  85. package/backend/dist/esm-dev/users.d.ts +1 -1
  86. package/backend/dist/esm-dev/users.js +88 -73
  87. package/backend/dist/esm-dev/utils.d.ts +17 -9
  88. package/backend/dist/esm-dev/utils.js +22 -63
  89. package/backend/dist/esm-dev/view.d.ts +2 -2
  90. package/backend/dist/esm-dev/view.js +39 -41
  91. package/backend/dist/esm-dev/volt.d.ts +3 -2
  92. package/backend/dist/esm-dev/volt.js +2 -1
  93. package/backend/src/database.ts +173 -155
  94. package/backend/src/endpoint.ts +123 -31
  95. package/backend/src/file_watcher.ts +2 -2
  96. package/backend/src/frontend.ts +9 -8
  97. package/backend/src/image_endpoint.ts +4 -0
  98. package/backend/src/payments/paddle.ts +11 -3
  99. package/backend/src/plugins/css.ts +36 -8
  100. package/backend/src/plugins/ts/compiler.ts +37 -1
  101. package/backend/src/plugins/ts/preprocessing.ts +5 -3
  102. package/backend/src/server.ts +167 -306
  103. package/backend/src/status.ts +1 -0
  104. package/backend/src/stream.ts +28 -8
  105. package/backend/src/users.ts +87 -72
  106. package/backend/src/utils.ts +58 -25
  107. package/backend/src/view.ts +30 -28
  108. package/backend/src/{volt.js → volt.ts} +2 -1
  109. package/backend/tsconfig.cjs.json +3 -3
  110. package/backend/tsconfig.esm.json +3 -3
  111. package/frontend/dist/elements/base.d.ts +414 -432
  112. package/frontend/dist/elements/base.js +566 -329
  113. package/frontend/dist/elements/module.d.ts +26 -12
  114. package/frontend/dist/elements/module.js +69 -32
  115. package/frontend/dist/elements/register_element.d.ts +3 -0
  116. package/frontend/dist/elements/register_element.js +22 -0
  117. package/frontend/dist/modules/auth.d.ts +1 -0
  118. package/frontend/dist/modules/auth.js +6 -5
  119. package/frontend/dist/modules/color.d.ts +159 -0
  120. package/frontend/dist/modules/color.js +315 -0
  121. package/frontend/dist/modules/colors.d.ts +1 -26
  122. package/frontend/dist/modules/colors.js +417 -340
  123. package/frontend/dist/modules/cookies.d.ts +1 -0
  124. package/frontend/dist/modules/cookies.js +1 -0
  125. package/frontend/dist/modules/events.d.ts +1 -0
  126. package/frontend/dist/modules/events.js +1 -0
  127. package/frontend/dist/modules/google.d.ts +1 -0
  128. package/frontend/dist/modules/google.js +1 -0
  129. package/frontend/dist/modules/meta.d.ts +1 -0
  130. package/frontend/dist/modules/meta.js +1 -0
  131. package/frontend/dist/modules/mutex.d.ts +1 -2
  132. package/frontend/dist/modules/mutex.js +3 -4
  133. package/frontend/dist/modules/paddle.d.ts +1 -0
  134. package/frontend/dist/modules/paddle.js +14 -13
  135. package/frontend/dist/modules/scheme.d.ts +1 -0
  136. package/frontend/dist/modules/scheme.js +5 -3
  137. package/frontend/dist/modules/statics.d.ts +1 -0
  138. package/frontend/dist/modules/statics.js +1 -0
  139. package/frontend/dist/modules/support.d.ts +1 -0
  140. package/frontend/dist/modules/support.js +3 -2
  141. package/frontend/dist/modules/theme.d.ts +56 -0
  142. package/frontend/dist/{ui → modules}/theme.js +186 -75
  143. package/frontend/dist/modules/themes.d.ts +1 -1
  144. package/frontend/dist/modules/themes.js +1 -0
  145. package/frontend/dist/modules/user.d.ts +1 -0
  146. package/frontend/dist/modules/user.js +11 -10
  147. package/frontend/dist/modules/utils.d.ts +23 -2
  148. package/frontend/dist/modules/utils.js +93 -1
  149. package/frontend/dist/types/gradient.js +4 -0
  150. package/frontend/dist/ui/border_button.d.ts +0 -25
  151. package/frontend/dist/ui/border_button.js +50 -51
  152. package/frontend/dist/ui/button.d.ts +0 -21
  153. package/frontend/dist/ui/button.js +41 -46
  154. package/frontend/dist/ui/canvas.js +15 -15
  155. package/frontend/dist/ui/checkbox.d.ts +3 -17
  156. package/frontend/dist/ui/checkbox.js +36 -30
  157. package/frontend/dist/ui/code.d.ts +15 -82
  158. package/frontend/dist/ui/code.js +150 -125
  159. package/frontend/dist/ui/color.d.ts +0 -1
  160. package/frontend/dist/ui/color.js +1 -1
  161. package/frontend/dist/ui/context_menu.d.ts +4 -2
  162. package/frontend/dist/ui/context_menu.js +16 -17
  163. package/frontend/dist/ui/css.js +2 -0
  164. package/frontend/dist/ui/divider.d.ts +0 -7
  165. package/frontend/dist/ui/divider.js +21 -25
  166. package/frontend/dist/ui/dropdown.d.ts +13 -7
  167. package/frontend/dist/ui/dropdown.js +65 -30
  168. package/frontend/dist/ui/for_each.d.ts +0 -5
  169. package/frontend/dist/ui/for_each.js +17 -22
  170. package/frontend/dist/ui/form.d.ts +17 -12
  171. package/frontend/dist/ui/form.js +21 -18
  172. package/frontend/dist/ui/frame_modes.d.ts +9 -12
  173. package/frontend/dist/ui/frame_modes.js +8 -10
  174. package/frontend/dist/ui/google_map.d.ts +0 -11
  175. package/frontend/dist/ui/google_map.js +23 -28
  176. package/frontend/dist/ui/gradient.d.ts +0 -5
  177. package/frontend/dist/ui/gradient.js +17 -22
  178. package/frontend/dist/ui/image.d.ts +27 -58
  179. package/frontend/dist/ui/image.js +99 -93
  180. package/frontend/dist/ui/input.d.ts +20 -97
  181. package/frontend/dist/ui/input.js +192 -170
  182. package/frontend/dist/ui/link.d.ts +0 -18
  183. package/frontend/dist/ui/link.js +42 -48
  184. package/frontend/dist/ui/list.js +36 -37
  185. package/frontend/dist/ui/loader_button.d.ts +4 -19
  186. package/frontend/dist/ui/loader_button.js +35 -37
  187. package/frontend/dist/ui/loaders.d.ts +0 -8
  188. package/frontend/dist/ui/loaders.js +20 -25
  189. package/frontend/dist/ui/popup.d.ts +11 -8
  190. package/frontend/dist/ui/popup.js +183 -24
  191. package/frontend/dist/ui/pseudo.d.ts +3 -3
  192. package/frontend/dist/ui/pseudo.js +14 -17
  193. package/frontend/dist/ui/scroller.d.ts +10 -48
  194. package/frontend/dist/ui/scroller.js +306 -300
  195. package/frontend/dist/ui/slider.d.ts +9 -3
  196. package/frontend/dist/ui/slider.js +31 -17
  197. package/frontend/dist/ui/spacer.d.ts +0 -9
  198. package/frontend/dist/ui/spacer.js +21 -26
  199. package/frontend/dist/ui/span.js +13 -15
  200. package/frontend/dist/ui/stack.d.ts +14 -75
  201. package/frontend/dist/ui/stack.js +166 -169
  202. package/frontend/dist/ui/steps.d.ts +10 -23
  203. package/frontend/dist/ui/steps.js +47 -34
  204. package/frontend/dist/ui/style.d.ts +4 -3
  205. package/frontend/dist/ui/style.js +13 -18
  206. package/frontend/dist/ui/switch.d.ts +10 -4
  207. package/frontend/dist/ui/switch.js +24 -16
  208. package/frontend/dist/ui/table.d.ts +0 -23
  209. package/frontend/dist/ui/table.js +113 -119
  210. package/frontend/dist/ui/tabs.d.ts +3 -19
  211. package/frontend/dist/ui/tabs.js +35 -29
  212. package/frontend/dist/ui/text.d.ts +0 -8
  213. package/frontend/dist/ui/text.js +20 -25
  214. package/frontend/dist/ui/title.d.ts +0 -15
  215. package/frontend/dist/ui/title.js +39 -45
  216. package/frontend/dist/ui/ui.d.ts +0 -2
  217. package/frontend/dist/ui/ui.js +0 -2
  218. package/frontend/dist/ui/view.d.ts +3 -17
  219. package/frontend/dist/ui/view.js +27 -32
  220. package/frontend/dist/volt.d.ts +2 -1
  221. package/frontend/dist/volt.js +3 -1
  222. package/frontend/examples/dashboard/dashboard.ts +774 -0
  223. package/frontend/examples/theme/theme.ts +58 -0
  224. package/frontend/src/css/volt.css +5 -0
  225. package/frontend/src/elements/base.ts +767 -545
  226. package/frontend/src/elements/module.ts +90 -29
  227. package/frontend/src/elements/register_element.ts +24 -0
  228. package/frontend/src/modules/auth.ts +7 -6
  229. package/frontend/src/modules/color.ts +348 -0
  230. package/frontend/src/modules/colors.ts +468 -449
  231. package/frontend/src/modules/cookies.ts +1 -0
  232. package/frontend/src/modules/events.ts +1 -0
  233. package/frontend/src/modules/google.ts +1 -0
  234. package/frontend/src/modules/meta.ts +2 -1
  235. package/frontend/src/modules/mutex.ts +2 -4
  236. package/frontend/src/modules/paddle.ts +21 -20
  237. package/frontend/src/modules/scheme.ts +5 -4
  238. package/frontend/src/modules/statics.ts +2 -1
  239. package/frontend/src/modules/support.ts +3 -2
  240. package/frontend/src/modules/theme.ts +413 -0
  241. package/frontend/src/modules/themes.ts +2 -1
  242. package/frontend/src/modules/user.ts +12 -11
  243. package/frontend/src/modules/utils.ts +125 -2
  244. package/frontend/src/ui/border_button.ts +41 -37
  245. package/frontend/src/ui/button.ts +33 -32
  246. package/frontend/src/ui/canvas.ts +5 -2
  247. package/frontend/src/ui/checkbox.ts +21 -22
  248. package/frontend/src/ui/code.ts +92 -86
  249. package/frontend/src/ui/context_menu.ts +7 -5
  250. package/frontend/src/ui/css.ts +1 -1
  251. package/frontend/src/ui/divider.ts +15 -10
  252. package/frontend/src/ui/dropdown.ts +38 -21
  253. package/frontend/src/ui/for_each.ts +9 -8
  254. package/frontend/src/ui/form.ts +26 -21
  255. package/frontend/src/ui/frame_modes.ts +13 -17
  256. package/frontend/src/ui/google_map.ts +15 -13
  257. package/frontend/src/ui/gradient.ts +9 -8
  258. package/frontend/src/ui/image.ts +108 -86
  259. package/frontend/src/ui/input.ts +145 -144
  260. package/frontend/src/ui/link.ts +25 -23
  261. package/frontend/src/ui/list.ts +12 -6
  262. package/frontend/src/ui/loader_button.ts +26 -25
  263. package/frontend/src/ui/loaders.ts +12 -11
  264. package/frontend/src/ui/popup.ts +168 -14
  265. package/frontend/src/ui/pseudo.ts +5 -3
  266. package/frontend/src/ui/scroller.ts +303 -294
  267. package/frontend/src/ui/slider.ts +15 -10
  268. package/frontend/src/ui/spacer.ts +14 -11
  269. package/frontend/src/ui/span.ts +6 -2
  270. package/frontend/src/ui/stack.ts +196 -183
  271. package/frontend/src/ui/steps.ts +38 -22
  272. package/frontend/src/ui/style.ts +7 -4
  273. package/frontend/src/ui/switch.ts +16 -11
  274. package/frontend/src/ui/table.ts +42 -34
  275. package/frontend/src/ui/tabs.ts +20 -19
  276. package/frontend/src/ui/text.ts +12 -11
  277. package/frontend/src/ui/title.ts +22 -20
  278. package/frontend/src/ui/ui.ts +0 -2
  279. package/frontend/src/ui/view.ts +20 -19
  280. package/frontend/src/volt.ts +3 -1
  281. package/frontend/{compile.js → tools/compile.old.js} +2 -2
  282. package/frontend/tools/embed_scripts.js +69 -0
  283. package/frontend/tsconfig.json +26 -0
  284. package/package.json +7 -6
  285. package/frontend/dist/ui/theme.d.ts +0 -25
  286. package/frontend/exports.json +0 -1340
  287. package/frontend/src/modules/date.js +0 -535
  288. package/frontend/src/ui/color.ts +0 -117
  289. package/frontend/src/ui/theme.ts +0 -279
  290. /package/backend/src/{vinc.dev.js → vinc.dev.ts} +0 -0
@@ -0,0 +1,774 @@
1
+ // Imports.
2
+ import * as volt from "@vandenberghinc/volt/frontend"
3
+ import { ResponseStatus, Theme, UI } from "../defaults.js";
4
+
5
+ // Global variables.
6
+ const endpoint = volt.Utils.endpoint();
7
+
8
+ // ---------------------------------------------------------
9
+ // Utils.
10
+
11
+ // A side by side form container.
12
+ const SideByFormContainer = (...children) => {
13
+ return volt.HStack(
14
+ ...children
15
+ )
16
+ .align_height()
17
+ .width("100%")
18
+ .overflow("hidden")
19
+ .media(
20
+ "width >= 900px",
21
+ e => e.side_by_side({ columns: 2, vspacing: 0, hspacing: 65 }).margin_bottom(65),
22
+ e => e.side_by_side({ columns: 1, vspacing: 50, hspacing: 0 }).margin_bottom(50)
23
+ )
24
+ }
25
+
26
+ // Dashboard form.
27
+ function FormWidget(
28
+ {
29
+ title = undefined,
30
+ text = undefined,
31
+ button = "Button",
32
+ center_button = false,
33
+ small_button = true,
34
+ right_top_button = false,
35
+ inputs = [],
36
+ on_submit = (data, form) => { },
37
+ spacer = false,
38
+ }: {
39
+ title?: string,
40
+ text?: string,
41
+ button?: string | boolean,
42
+ center_button?: boolean,
43
+ small_button?: boolean,
44
+ right_top_button?: boolean,
45
+ inputs?: any[],
46
+ on_submit?: (data: any, form: volt.FormElement) => any,
47
+ spacer?: boolean,
48
+ }
49
+ ) {
50
+ return volt.Form(
51
+
52
+ right_top_button
53
+ ? [
54
+ volt.HStack(
55
+ UI.Title(title)
56
+ .stretch(true)
57
+ .margin(0)
58
+ .wrap(true),
59
+ UI.Button(button)
60
+ .padding(5, 15)
61
+ .margin_top(0)
62
+ .font_size(15)
63
+ )
64
+ .center_vertical()
65
+ .margin(0, 0, 12.5, 0)
66
+ .wrap(false)
67
+ ]
68
+ : title == null ? null : (
69
+ UI.Title(title)
70
+ .width("fit-content")
71
+ .margin(0, 0, 7.5, 0)
72
+ ),
73
+
74
+
75
+ // @ts-ignore-error
76
+ text == null ? null : (
77
+ UI.Text(text)
78
+ .margin_bottom(inputs.length > 0 ? 20 : 0)
79
+ ),
80
+
81
+ volt.ForEach(inputs, (item) => UI.Input(item)),
82
+
83
+ spacer ? volt.Spacer() : null,
84
+
85
+ // Save.
86
+ right_top_button ? null : (
87
+ volt.VStack(
88
+ button === false ? null : (
89
+ UI.Button(button)
90
+ .padding(small_button ? 7.5 : 10, small_button ? 25 : 40)
91
+ .margin_top(inputs.length > 0 ? 15 : 25)
92
+ )
93
+ )
94
+ .width("100%")
95
+ .align(center_button ? (inputs.length > 0 ? "center" : "start") : "start")
96
+ ),
97
+ )
98
+ .width("100%")
99
+ .on_submit((e, data) => on_submit(data, e))
100
+ .on_submit_error((_, error) => {
101
+ ResponseStatus.error(error)
102
+ })
103
+ }
104
+
105
+ // ---------------------------------------------------------
106
+ // Pages.
107
+
108
+ function AccountPage(): PageOptions {
109
+ return {
110
+ type: "item",
111
+ title: "Account Settings",
112
+ endpoint: "/dashboard/account",
113
+ icon: "/static/icons/username.webp",
114
+ content() {
115
+ return volt.Frame(
116
+ SideByFormContainer(
117
+
118
+ // General info.
119
+ FormWidget({
120
+ title: "Profile",
121
+ text: "Setup your account and edit your profile details.",
122
+ button: "Update",
123
+ inputs: [
124
+ { label: "First name", placeholder: "John", id: "first_name", required: true, image: "/static/icons/username.red.webp", },
125
+ { label: "Last name", placeholder: "Doe", id: "last_name", required: true, image: "/static/icons/username.red.webp", },
126
+ { label: "Username", placeholder: "myusername", id: "username", required: true, image: "/static/icons/username.red.webp", },
127
+ { label: "Email", placeholder: "my@email.com", id: "email", required: true, image: "/static/icons/mail.webp", },
128
+ ],
129
+ right_top_button: true,
130
+ on_submit: async (data) => {
131
+ const response = await volt.User.set(data)
132
+ ResponseStatus.message(response.message);
133
+ }
134
+ }),
135
+ // ThemeV2.Divider().margin(40, 0),
136
+
137
+ // Password.
138
+ FormWidget({
139
+ title: "Password",
140
+ text: "Change your account's password.",
141
+ button: "Update",
142
+ inputs: [
143
+ { label: "Current password", placeholder: "Current password", id: "current_password", required: true, image: "/static/icons/password.webp", type: "password" },
144
+ { label: "New Password", placeholder: "Password", id: "password", required: true, image: "/static/icons/password.webp", type: "password" },
145
+ { label: "Verify new password", placeholder: "Verify password", id: "verify_password", required: true, image: "/static/icons/password.webp", type: "password" },
146
+ ],
147
+ right_top_button: true,
148
+ on_submit: async (data, form) => {
149
+ const response =
150
+ volt.User.change_password(data)
151
+ .then((response) => {
152
+ ResponseStatus.message(response.message);
153
+ })
154
+ .catch(({ error, status, invalid_fields }) => {
155
+ if (invalid_fields) {
156
+ if (invalid_fields.current_password) {
157
+ form.fields.current_password.missing(true, invalid_fields.current_password);
158
+ }
159
+ if (invalid_fields.password) {
160
+ form.fields.password.missing(true, invalid_fields.password);
161
+ }
162
+ if (invalid_fields.verify_password) {
163
+ form.fields.verify_password.missing(true, invalid_fields.verify_password);
164
+ }
165
+ }
166
+ ResponseStatus.error(error);
167
+ })
168
+ },
169
+ }),
170
+ ),
171
+ SideByFormContainer(
172
+ volt.VStack(
173
+ // No api key exists.
174
+ FormWidget({
175
+ title: "API key",
176
+ text: "Currently you do not have an API key. Generate an API key to get API access.\nWhen generated the API key is only shown once. Make sure to store it correctly, since you have to regenerate the API key if you lose it.",
177
+ button: "Generate",
178
+ right_top_button: true,
179
+ async on_submit() {
180
+ const response = await volt.User.generate_api_key()
181
+ if (response.error) {
182
+ ResponseStatus.message(response.error);
183
+ } else if (response.api_key) {
184
+ volt.Elements.get("api_key").value(response.api_key);
185
+ volt.Elements.get("api_key_not_generated").hide();
186
+ volt.Elements.get("api_key_generated").show();
187
+ ResponseStatus.message(response.message);
188
+ }
189
+ }
190
+ })
191
+ .id("api_key_not_generated"),
192
+
193
+ // API key exists.
194
+ FormWidget({
195
+ title: "API key",
196
+ text: "Your personal API key. An API key is only shown once.\nYou should revoke your old API key and generate an one when you have lost your API key.",
197
+ button: "Revoke",
198
+ inputs: [
199
+ {
200
+ label: "API key",
201
+ placeholder: "**************************************************************",
202
+ id: "api_key",
203
+ readonly: true,
204
+ type: volt.Input,
205
+ image: "/static/icons/password.webp",
206
+ }
207
+ ],
208
+ right_top_button: true,
209
+ async on_submit(data) {
210
+ const response = await volt.User.revoke_api_key()
211
+ volt.Elements.get("api_key").value("");
212
+ volt.Elements.get("api_key_not_generated").show();
213
+ volt.Elements.get("api_key_generated").hide();
214
+ ResponseStatus.message(response.message);
215
+ }
216
+ })
217
+ .id("api_key_generated")
218
+ .hide(),
219
+ ),
220
+
221
+
222
+ // Support PIN.
223
+ FormWidget({
224
+ title: "Support PIN",
225
+ text: "Your account's support pin to verify any support tickets.",
226
+ button: false,
227
+ inputs: [
228
+ { label: "Support PIN", placeholder: "Support PIN", id: "support_pin", required: false, readonly: true, image: "/static/icons/key.webp" },
229
+ ],
230
+ }),
231
+ )
232
+ )
233
+ }
234
+ }
235
+ }
236
+
237
+ // ---------------------------------------------------------
238
+ // Build content tree mapped under Navigations module.
239
+
240
+ interface PageOptions {
241
+ type: "chapter" | "item",
242
+ title: string,
243
+ endpoint?: string, // only chapter type may omit this.
244
+ icon: string,
245
+ content?: () => void,
246
+ }
247
+
248
+ const Navigation: {
249
+ selected_name: string,
250
+ selected_index: number,
251
+ items: {
252
+ text: string,
253
+ active: boolean,
254
+ navigation_node?: { select(): void; },
255
+ content: PageOptions[],
256
+ on_select?: () => void,
257
+ }[],
258
+ select(index_or_name: string | number): void;
259
+ } = {
260
+ selected_name: undefined as any,
261
+ selected_index: undefined as any,
262
+ items: [
263
+ {
264
+ text: "Account",
265
+ active: endpoint === "/dashboard" || endpoint.includes("/dashboard/account/"),
266
+ content: [
267
+ {
268
+ type: "chapter",
269
+ title: "Account",
270
+ icon: "/static/icons/username.webp",
271
+ content: () => { }
272
+ },
273
+ AccountPage(),
274
+ {
275
+ type: "item",
276
+ title: "API",
277
+ endpoint: "/dashboard/api",
278
+ icon: "/static/icons/key.webp",
279
+ content: () => { }
280
+ },
281
+
282
+ {
283
+ type: "chapter",
284
+ title: "Billing",
285
+ icon: "/static/icons/pricing.webp",
286
+ content: () => { }
287
+ },
288
+ {
289
+ type: "item",
290
+ title: "Subscriptions",
291
+ endpoint: "/dashboard/billing",
292
+ icon: "/static/icons/pricing.webp",
293
+ content: () => { }
294
+ },
295
+ {
296
+ type: "item",
297
+ title: "Usage",
298
+ endpoint: "/dashboard/usage",
299
+ icon: "/static/icons/bar-chart.webp",
300
+ content: () => { }
301
+ },
302
+
303
+ {
304
+ type: "chapter",
305
+ title: "Customer Service",
306
+ icon: "/static/icons/username.webp",
307
+ content: () => { }
308
+ },
309
+ {
310
+ type: "item",
311
+ title: "Contact",
312
+ endpoint: "/dashboard/billing",
313
+ icon: "/static/icons/help.webp",
314
+ content: () => { }
315
+ },
316
+ {
317
+ type: "item",
318
+ title: "Feedback",
319
+ endpoint: "/dashboard/usage",
320
+ icon: "/static/icons/feedback.webp",
321
+ content: () => { }
322
+ },
323
+
324
+ ],
325
+ },
326
+ {
327
+ text: "Projects",
328
+ active: endpoint.includes("/dashboard/project/") || endpoint.includes("/dashboard/projects/"),
329
+ content: [
330
+ {
331
+ type: "chapter",
332
+ title: "Settings",
333
+ icon: "/static/icons/settings.webp",
334
+ content: () => { }
335
+ },
336
+ {
337
+ type: "item",
338
+ title: "Roles & Permissions",
339
+ endpoint: "/dashboard/project/permissions",
340
+ icon: "/static/icons/key.webp",
341
+ content: () => { }
342
+ },
343
+ {
344
+ type: "item",
345
+ title: "Git Integration",
346
+ endpoint: "/dashboard/project/git",
347
+ icon: "/static/icons/github.webp",
348
+ content: () => { }
349
+ },
350
+ // ------------------------------------------
351
+ {
352
+ type: "chapter",
353
+ title: "AI",
354
+ icon: "/static/icons/sparkle.webp",
355
+ content: () => { }
356
+ },
357
+ {
358
+ type: "item",
359
+ title: "MDX Pages",
360
+ endpoint: "/dashboard/project/mdx",
361
+ icon: "/static/icons/code.webp",
362
+ content: () => { }
363
+ },
364
+ {
365
+ type: "item",
366
+ title: "Generated Pages",
367
+ endpoint: "/dashboard/project/generate",
368
+ icon: "/static/icons/docs.webp",
369
+ content: () => { }
370
+ },
371
+ // ------------------------------------------
372
+ {
373
+ type: "chapter",
374
+ title: "Insight",
375
+ icon: "/static/icons/search.webp",
376
+ content: () => { }
377
+ },
378
+ {
379
+ type: "item",
380
+ title: "Analytics",
381
+ endpoint: "/dashboard/project/analytics",
382
+ icon: "/static/icons/bar-chart.webp",
383
+ content: () => { }
384
+ },
385
+ {
386
+ type: "item",
387
+ title: "User Feedback",
388
+ endpoint: "/dashboard/project/feedback",
389
+ icon: "/static/icons/feedback.webp",
390
+ content: () => { }
391
+ },
392
+ ],
393
+ on_select() {
394
+ const node = volt.HStack(
395
+ UI.SelectionPicker({
396
+ value: "Select Project",
397
+ title: "Select Project",
398
+ items: [],
399
+ })
400
+ .border_radius(12.5)
401
+ .width("initial")
402
+ .letter_spacing(UI.letter_spacing_1)
403
+ .flex(1),
404
+ volt.ImageMask("/static/icons/plus.webp")
405
+ .frame(25, 25)
406
+ .padding(6.5)
407
+ .margin_left(15)
408
+ .flex_shrink(0)
409
+ .color(Theme.fg_2)
410
+ .border(1, Theme.div_bg)
411
+ .border_radius("50%")
412
+ .flex_shrink(0) // wrap items in hstack instead of shrinking.
413
+ .transition("background 300ms ease-in-out")
414
+ .transition_mask("background 300ms ease-in-out")
415
+ .on_mouse_over_out(
416
+ e => e.color(Theme.fg).background(Theme.auto_darken_lighten("bg", 0.05)),
417
+ e => e.color(Theme.fg_2).background("transparent"),
418
+ )
419
+ )
420
+ .center_vertical()
421
+ .width("100%").overflow("hidden").wrap(false)
422
+ .padding(7.5, 20, 20, 20)
423
+ SideBar.content.insertBefore(node, SideBar.content.child(0))
424
+ },
425
+ },
426
+ ],
427
+ select(index: string | number) {
428
+ if (typeof index === "string") {
429
+ const name = index;
430
+ for (let i = 0; i < this.items.length; i++) {
431
+ if (this.items[i].text === name) {
432
+ index = i;
433
+ break;
434
+ }
435
+ }
436
+ if (typeof index === "string") {
437
+ throw new Error(`Navigation "${name}" does not exist.`)
438
+ }
439
+ }
440
+
441
+ // Set attrs.
442
+ if (index >= this.items.length) {
443
+ throw new Error(`Invalid index ${index} max index is ${this.items.length - 1}`);
444
+ }
445
+ const item = this.items[index];
446
+ this.selected_name = item.text;
447
+ this.selected_index = index as number;
448
+
449
+ // Select active node from nav bar.
450
+ this.items[index]?.navigation_node?.select();
451
+
452
+ // Render sidebar content of active nav.
453
+ SideBar.render();
454
+
455
+ // Call on select.
456
+ if (typeof item.on_select === "function") {
457
+ item.on_select();
458
+ }
459
+ },
460
+ }
461
+ if (endpoint === "/dashboard") {
462
+ Navigation.selected_name = Navigation.items[0].text;
463
+ Navigation.selected_index = 0;
464
+ } else {
465
+ for (let i = 0; i < Navigation.items.length; i++) {
466
+ if (Navigation.items[i].content.find(item => endpoint === item.endpoint)){
467
+ Navigation.selected_name = Navigation.items[i].text;
468
+ Navigation.selected_index = i;
469
+ break;
470
+ }
471
+ }
472
+ }
473
+ if (!Navigation.selected_name) {
474
+ throw new Error("No navigation is selected with the current url.");
475
+ }
476
+
477
+ // ---------------------------------------------------------
478
+ // Core elements.
479
+
480
+ // TopBar.
481
+ const TopBar = (() => {
482
+ return volt.HStack(
483
+ UI.ProjectIcon(20),
484
+ volt.Spacer(),
485
+ volt.ImageMask("/static/icons/username.webp")
486
+ .color(Theme.fg)
487
+ .frame(20,20)
488
+ .margin_right(15),
489
+ volt.Frame(
490
+ UI.Text(volt.User.first_name())
491
+ .color(Theme.fg)
492
+ .font_size(13)
493
+ .margin(0, 0, 0, 0),
494
+ UI.Text(volt.User.email())
495
+ .color(Theme.fg_1)
496
+ .font_size(11)
497
+ .margin(0),
498
+ )
499
+ .width("fit-content")
500
+ .on_click(() => Navigation.select("Account"))
501
+ )
502
+ .center_vertical()
503
+ .border_bottom(1, Theme.div_bg)
504
+ .padding(12.5, 20)
505
+ })()
506
+
507
+ // Navigation bar (a second top bar below the first top bar).
508
+ const NavigationBar = (() => {
509
+ let selected_node;
510
+ return volt.HStack(
511
+
512
+ Navigation.items.map((item, index) => {
513
+ let text, divider;
514
+ const node = volt.VStack(
515
+ text = UI.Text(item.text)
516
+ .font_size(14)
517
+ .line_height("2.2em")
518
+ .font_weight(500)
519
+ .margin(0, 7.5) // to make divider larger then text.
520
+ .letter_spacing(UI.letter_spacing_2)
521
+ .transition("color 300ms ease-in-out, font-weight 500ms ease-in-out"),
522
+ divider = volt.Frame()
523
+ .position(null, 0, 0, 0)
524
+ .height(1.75)
525
+ .border_radius(0.5)
526
+ .transition("background 300ms ease-in-out")
527
+ .background("transparent"),
528
+ )
529
+ .width("fit-content")
530
+ .position("relative")
531
+ .margin_right(10)
532
+ .extend({
533
+ hover(forced = false) {
534
+ if (!forced && selected_node === node) return;
535
+ text.color(Theme.fg);
536
+ },
537
+ unhover(forced = false) {
538
+ if (!forced && selected_node === node) return;
539
+ text.color(Theme.fg_2);
540
+ },
541
+ select() {
542
+ if (selected_node === node) return;
543
+ else if (selected_node) selected_node.unselect();
544
+ selected_node = node;
545
+ this.hover(true);
546
+ text.font_weight(600);
547
+ divider.background(Theme.fg);
548
+ },
549
+ unselect() {
550
+ if (selected_node !== node) return;
551
+ selected_node = undefined;
552
+ this.unhover(true);
553
+ text.font_weight(500);
554
+ divider.background("transparent");
555
+ },
556
+ })
557
+ .on_mouse_over_out(e => e.hover(), e => e.unhover())
558
+ .on_click(() => index != null && Navigation.select(index))
559
+ if (Navigation.selected_index === index) {
560
+ node.select();
561
+ }
562
+ item.navigation_node = node;
563
+ return node;
564
+ }),
565
+
566
+ volt.Spacer(),
567
+ )
568
+ .center_vertical()
569
+ .border_bottom(1, Theme.div_bg)
570
+ .padding(15, 20)
571
+ })();
572
+
573
+ // SideBar.
574
+ const SideBar = (() => {
575
+ let selected_node: any;
576
+ return volt.Scroller()
577
+ .flex("1 1 0") // for height
578
+ .fixed_width(350)
579
+ .border_right(1, Theme.div_bg)
580
+ .content
581
+ .padding(15, 0)
582
+ .parent<volt.ScrollerElement>()
583
+ .extend({
584
+ render() {
585
+ selected_node = undefined; // reset is required.
586
+ const items = Navigation.items[Navigation.selected_index].content;
587
+ console.log("Rendering sidebar...");
588
+ console.log("Items:", items);
589
+ this.remove_children()
590
+ this.append(
591
+ items.map((item, index) => {
592
+ let image, text, divider;
593
+ const node = volt.HStack(
594
+ divider = item.type === "chapter" ? undefined : UI.Divider()
595
+ .frame(1, "100%")
596
+ .transition("background 300ms ease-in-out")
597
+ .margin(0, 23, 0, 7.5),
598
+ volt.HStack(
599
+ image = volt.ImageMask(item.icon)
600
+ .frame(15, 15)
601
+ .transition_mask("background 300ms ease-in-out")
602
+ .color(item.type === "chapter" ? Theme.fg : Theme.fg_1)
603
+ .margin_right(15)
604
+ .margin_bottom(4),
605
+ text = volt.Text(item.title)
606
+ .font_size(14)
607
+ .line_height("1.6em")
608
+ .font_weight(item.type === "chapter" ? 500 : 300)
609
+ .transition("color 300ms ease-in-out, font-weight 300ms ease-in-out")
610
+ .color(item.type === "chapter" ? Theme.fg : Theme.fg_1)
611
+ .letter_spacing(UI.letter_spacing_1)
612
+ .margin(0),
613
+ )
614
+ .wrap(false)
615
+ .center_vertical()
616
+ .padding(10, 0)
617
+ )
618
+ .padding(0, 20)
619
+ .center_vertical()
620
+ .transition("background 300ms ease-in-out")
621
+ .on_click(() => {
622
+ if (item.content) item.content();
623
+ })
624
+ .extend({
625
+ hover(forced = false) {
626
+ if (item.type === "chapter") { return; }
627
+ else if (!forced && selected_node === node) return;
628
+ image.color(Theme.fg);
629
+ // text.font_weight(400)
630
+ text.color(Theme.fg);
631
+ this.background(Theme.auto_darken_lighten("bg", 0.025))
632
+ if (divider) divider.background(Theme.auto_darken_lighten("bg", 0.5))
633
+ },
634
+ unhover(forced = false) {
635
+ if (item.type === "chapter") { return; }
636
+ else if (!forced && selected_node === node) return;
637
+ image.color(Theme.fg_2);
638
+ // text.font_weight(300)
639
+ text.color(Theme.fg_2);
640
+ this.background("transparent")
641
+ if (divider) divider.background(Theme.div_bg)
642
+ },
643
+ select() {
644
+ if (item.type === "chapter") { return; }
645
+ else if (selected_node === node) return;
646
+ else if (selected_node) selected_node.unselect();
647
+ selected_node = node;
648
+ this.hover(true);
649
+ text.font_weight(400)
650
+ if (divider) divider.background(Theme.fg_1)
651
+ },
652
+ unselect() {
653
+ if (item.type === "chapter") { return; }
654
+ else if (selected_node !== node) return;
655
+ selected_node = undefined;
656
+ this.unhover(true);
657
+ text.font_weight(300)
658
+ if (divider) divider.background(Theme.div_bg)
659
+ },
660
+ })
661
+ .on_mouse_over_out(e => e.hover(), e => e.unhover())
662
+ if (item.type === "chapter") {
663
+ node.color("#ffffff")
664
+ if (index > 0) {
665
+ node.margin_top(15)
666
+ }
667
+ } else {
668
+ if (endpoint === item.endpoint || (selected_node === undefined && endpoint === "/dashboard")) {
669
+ node.select();
670
+ } else {
671
+ node.unselect();
672
+ }
673
+ }
674
+ return node;
675
+ })
676
+ );
677
+ return this;
678
+ },
679
+ })
680
+ .render()
681
+ })();
682
+
683
+ // Actions.
684
+ const Actions = (() => {
685
+ return volt.VStack(
686
+ [
687
+ { text: "Documentation", icon: "/static/icons/book-0.webp", href: "/docs" }
688
+ ].map((item) => {
689
+ return volt.AnchorHStack<{ text: volt.TextElement, img: volt.ImageMaskElement, arrow: volt.ImageMaskElement }>(
690
+ volt.ImageMask(item.icon)
691
+ .assign_to_parent_as("img")
692
+ .frame(15, 15)
693
+ .transition_mask("background 300ms ease-in-out")
694
+ .color(Theme.fg_1)
695
+ .margin_right(15)
696
+ .margin_bottom(2),
697
+ UI.Text(item.text)
698
+ .assign_to_parent_as("text")
699
+ .font_size(14)
700
+ .line_height("2.2em")
701
+ .font_weight(500)
702
+ .margin(0)
703
+ .letter_spacing(UI.letter_spacing_2)
704
+ .transition("color 300ms ease-in-out, font-weight 500ms ease-in-out"),
705
+ volt.Spacer(),
706
+ UI.FoldArrow()
707
+ .rotate(0)
708
+ .assign_to_parent_as("arrow")
709
+ .color(Theme.fg_1)
710
+ .margin_left(15),
711
+ )
712
+ .position("relative")
713
+ .center_vertical()
714
+ .wrap(false)
715
+ .margin_right(10)
716
+ .href(item.href)
717
+ .on_mouse_over_out(
718
+ e => {
719
+ e.text.color(Theme.fg);
720
+ e.img.color(Theme.fg);
721
+ e.arrow.color(Theme.fg);
722
+ },
723
+ e => {
724
+ e.text.color(Theme.fg_1);
725
+ e.img.color(Theme.fg_1);
726
+ e.arrow.color(Theme.fg_1);
727
+ },
728
+ )
729
+ })
730
+
731
+ )
732
+ .flex(0)
733
+ .padding(10, 20)
734
+ .border_top(1, Theme.div_bg)
735
+ .border_right(1, Theme.div_bg)
736
+ })()
737
+
738
+ // Content.
739
+ const Content = (() => {
740
+ return volt.Scroller(
741
+
742
+ )
743
+ .height("100%")
744
+ .flex(1)
745
+ .background(Theme.auto_darken_lighten("bg", 0.01))
746
+ .content
747
+ .padding(20)
748
+ .parent<volt.ScrollerElement>()
749
+ })
750
+
751
+ // ---------------------------------------------------------
752
+ // On load.
753
+
754
+ volt.Utils.on_load(() => {
755
+ return UI.View(
756
+
757
+ // Topbar.
758
+ TopBar,
759
+
760
+ // Navigation bar.
761
+ NavigationBar,
762
+
763
+ // Main content.
764
+ volt.HStack(
765
+ volt.VStack(
766
+ SideBar,
767
+ Actions,
768
+ )
769
+ .frame("fit-content", "100%"),
770
+ Content,
771
+ )
772
+ .flex("1 1 0")
773
+ );
774
+ });