@owlmeans/web-panel 0.1.18-rc.9 → 0.1.18

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 (669) hide show
  1. package/README.md +510 -143
  2. package/THIRD-PARTY-NOTICES.txt +24 -0
  3. package/agent-meta/manifest.json +163 -4
  4. package/agent-meta/skills/web-panel/SKILL.md +136 -83
  5. package/agent-meta/skills/web-panel/parts/consent.md +114 -0
  6. package/agent-meta/skills/web-panel/parts/editor.md +47 -0
  7. package/agent-meta/skills/web-panel/parts/forms.md +85 -0
  8. package/agent-meta/skills/web-panel/parts/navigation.md +203 -0
  9. package/agent-meta/skills/web-panel/parts/picker.md +164 -0
  10. package/agent-meta/skills/web-panel/parts/reload.md +46 -0
  11. package/agent-meta/skills/web-panel/parts/sign-in.md +65 -0
  12. package/agent-meta/skills/web-panel/parts/theme.md +74 -0
  13. package/build/@/components/ui/alert-dialog.d.ts +15 -0
  14. package/build/@/components/ui/alert-dialog.d.ts.map +1 -0
  15. package/build/@/components/ui/alert-dialog.js +39 -0
  16. package/build/@/components/ui/alert-dialog.js.map +1 -0
  17. package/build/@/components/ui/alert.js +1 -1
  18. package/build/@/components/ui/alert.js.map +1 -1
  19. package/build/@/components/ui/button.js +1 -1
  20. package/build/@/components/ui/button.js.map +1 -1
  21. package/build/@/components/ui/card.js +1 -1
  22. package/build/@/components/ui/card.js.map +1 -1
  23. package/build/@/components/ui/input.js +1 -1
  24. package/build/@/components/ui/input.js.map +1 -1
  25. package/build/@/components/ui/label.js +1 -1
  26. package/build/@/components/ui/label.js.map +1 -1
  27. package/build/@/components/ui/navigation-menu.js +1 -1
  28. package/build/@/components/ui/navigation-menu.js.map +1 -1
  29. package/build/@/components/ui/popover.d.ts +8 -0
  30. package/build/@/components/ui/popover.d.ts.map +1 -0
  31. package/build/@/components/ui/popover.js +17 -0
  32. package/build/@/components/ui/popover.js.map +1 -0
  33. package/build/@/components/ui/progress.js +1 -1
  34. package/build/@/components/ui/progress.js.map +1 -1
  35. package/build/@/components/ui/separator.js +1 -1
  36. package/build/@/components/ui/separator.js.map +1 -1
  37. package/build/@/components/ui/sheet.d.ts +15 -0
  38. package/build/@/components/ui/sheet.d.ts.map +1 -0
  39. package/build/@/components/ui/sheet.js +40 -0
  40. package/build/@/components/ui/sheet.js.map +1 -0
  41. package/build/auth/context.d.ts.map +1 -1
  42. package/build/auth/context.js +0 -1
  43. package/build/auth/context.js.map +1 -1
  44. package/build/auth/entrypoints.d.ts +10 -0
  45. package/build/auth/entrypoints.d.ts.map +1 -0
  46. package/build/auth/entrypoints.js +4 -0
  47. package/build/auth/entrypoints.js.map +1 -0
  48. package/build/auth/exports.d.ts +4 -4
  49. package/build/auth/exports.d.ts.map +1 -1
  50. package/build/auth/exports.js +3 -3
  51. package/build/auth/exports.js.map +1 -1
  52. package/build/auth/modules.d.ts +1 -1
  53. package/build/auth/modules.d.ts.map +1 -1
  54. package/build/auth/plugins/basic-ed25519.js +4 -4
  55. package/build/auth/plugins/basic-ed25519.js.map +1 -1
  56. package/build/auth/plugins/re-captcha.js +3 -3
  57. package/build/auth/plugins/re-captcha.js.map +1 -1
  58. package/build/auth/plugins/tunnel-consumer.js +1 -1
  59. package/build/auth/plugins/tunnel-consumer.js.map +1 -1
  60. package/build/components/block.js +2 -2
  61. package/build/components/block.js.map +1 -1
  62. package/build/components/consts.local.d.ts +14 -0
  63. package/build/components/consts.local.d.ts.map +1 -0
  64. package/build/components/consts.local.js +26 -0
  65. package/build/components/consts.local.js.map +1 -0
  66. package/build/components/footer/component.d.ts +19 -1
  67. package/build/components/footer/component.d.ts.map +1 -1
  68. package/build/components/footer/component.js +38 -11
  69. package/build/components/footer/component.js.map +1 -1
  70. package/build/components/footer/credit.d.ts +27 -0
  71. package/build/components/footer/credit.d.ts.map +1 -0
  72. package/build/components/footer/credit.js +42 -0
  73. package/build/components/footer/credit.js.map +1 -0
  74. package/build/components/footer/index.d.ts +1 -0
  75. package/build/components/footer/index.d.ts.map +1 -1
  76. package/build/components/footer/index.js +1 -0
  77. package/build/components/footer/index.js.map +1 -1
  78. package/build/components/footer/types.d.ts +22 -1
  79. package/build/components/footer/types.d.ts.map +1 -1
  80. package/build/components/form/button/component.d.ts.map +1 -1
  81. package/build/components/form/button/component.js +5 -3
  82. package/build/components/form/button/component.js.map +1 -1
  83. package/build/components/form/component.js +2 -2
  84. package/build/components/form/component.js.map +1 -1
  85. package/build/components/form/text/component.js +2 -2
  86. package/build/components/form/text/component.js.map +1 -1
  87. package/build/components/helper.d.ts.map +1 -1
  88. package/build/components/helper.js +1 -12
  89. package/build/components/helper.js.map +1 -1
  90. package/build/components/index.d.ts +4 -0
  91. package/build/components/index.d.ts.map +1 -1
  92. package/build/components/index.js +4 -0
  93. package/build/components/index.js.map +1 -1
  94. package/build/components/link.js +3 -3
  95. package/build/components/link.js.map +1 -1
  96. package/build/components/login/append.d.ts +15 -0
  97. package/build/components/login/append.d.ts.map +1 -0
  98. package/build/components/login/append.js +26 -0
  99. package/build/components/login/append.js.map +1 -0
  100. package/build/components/login/consts.d.ts +3 -0
  101. package/build/components/login/consts.d.ts.map +1 -0
  102. package/build/components/login/consts.js +3 -0
  103. package/build/components/login/consts.js.map +1 -0
  104. package/build/components/login/consts.local.d.ts +4 -0
  105. package/build/components/login/consts.local.d.ts.map +1 -0
  106. package/build/components/login/consts.local.js +8 -0
  107. package/build/components/login/consts.local.js.map +1 -0
  108. package/build/components/login/credit.d.ts +12 -0
  109. package/build/components/login/credit.d.ts.map +1 -0
  110. package/build/components/login/credit.js +18 -0
  111. package/build/components/login/credit.js.map +1 -0
  112. package/build/components/login/i18n/be.json +10 -0
  113. package/build/components/login/i18n/de.json +10 -0
  114. package/build/components/login/i18n/en.json +10 -0
  115. package/build/components/login/i18n/es.json +10 -0
  116. package/build/components/login/i18n/fr.json +10 -0
  117. package/build/components/login/i18n/pl.json +10 -0
  118. package/build/components/login/i18n/ru.json +10 -0
  119. package/build/components/login/i18n/uk.json +10 -0
  120. package/build/components/login/i18n.d.ts +2 -0
  121. package/build/components/login/i18n.d.ts.map +1 -0
  122. package/build/components/login/i18n.js +28 -0
  123. package/build/components/login/i18n.js.map +1 -0
  124. package/build/components/login/icons.d.ts +14 -0
  125. package/build/components/login/icons.d.ts.map +1 -0
  126. package/build/components/login/icons.js +29 -0
  127. package/build/components/login/icons.js.map +1 -0
  128. package/build/components/login/index.d.ts +11 -0
  129. package/build/components/login/index.d.ts.map +1 -0
  130. package/build/components/login/index.js +10 -0
  131. package/build/components/login/index.js.map +1 -0
  132. package/build/components/login/notify.d.ts +18 -0
  133. package/build/components/login/notify.d.ts.map +1 -0
  134. package/build/components/login/notify.js +41 -0
  135. package/build/components/login/notify.js.map +1 -0
  136. package/build/components/login/provider.d.ts +20 -0
  137. package/build/components/login/provider.d.ts.map +1 -0
  138. package/build/components/login/provider.js +31 -0
  139. package/build/components/login/provider.js.map +1 -0
  140. package/build/components/login/screen.d.ts +24 -0
  141. package/build/components/login/screen.d.ts.map +1 -0
  142. package/build/components/login/screen.js +92 -0
  143. package/build/components/login/screen.js.map +1 -0
  144. package/build/components/login/terms.d.ts +19 -0
  145. package/build/components/login/terms.d.ts.map +1 -0
  146. package/build/components/login/terms.js +32 -0
  147. package/build/components/login/terms.js.map +1 -0
  148. package/build/components/login/types.d.ts +28 -0
  149. package/build/components/login/types.d.ts.map +1 -0
  150. package/build/components/login/types.js +2 -0
  151. package/build/components/login/types.js.map +1 -0
  152. package/build/components/nav/consts.local.d.ts +41 -0
  153. package/build/components/nav/consts.local.d.ts.map +1 -0
  154. package/build/components/nav/consts.local.js +60 -0
  155. package/build/components/nav/consts.local.js.map +1 -0
  156. package/build/components/nav/index.d.ts +1 -0
  157. package/build/components/nav/index.d.ts.map +1 -1
  158. package/build/components/nav/index.js +1 -0
  159. package/build/components/nav/index.js.map +1 -1
  160. package/build/components/nav/layout.d.ts +9 -2
  161. package/build/components/nav/layout.d.ts.map +1 -1
  162. package/build/components/nav/layout.js +48 -7
  163. package/build/components/nav/layout.js.map +1 -1
  164. package/build/components/nav/mobile.d.ts +21 -0
  165. package/build/components/nav/mobile.d.ts.map +1 -0
  166. package/build/components/nav/mobile.js +55 -0
  167. package/build/components/nav/mobile.js.map +1 -0
  168. package/build/components/nav/side.d.ts.map +1 -1
  169. package/build/components/nav/side.js +10 -10
  170. package/build/components/nav/side.js.map +1 -1
  171. package/build/components/nav/top.d.ts.map +1 -1
  172. package/build/components/nav/top.js +12 -8
  173. package/build/components/nav/top.js.map +1 -1
  174. package/build/components/nav/types.d.ts +64 -1
  175. package/build/components/nav/types.d.ts.map +1 -1
  176. package/build/components/nav/viewport.d.ts +3 -0
  177. package/build/components/nav/viewport.d.ts.map +1 -0
  178. package/build/components/nav/viewport.js +14 -0
  179. package/build/components/nav/viewport.js.map +1 -0
  180. package/build/components/panel-app/component.d.ts.map +1 -1
  181. package/build/components/panel-app/component.js +4 -3
  182. package/build/components/panel-app/component.js.map +1 -1
  183. package/build/components/picker/color-picker.d.ts +9 -0
  184. package/build/components/picker/color-picker.d.ts.map +1 -0
  185. package/build/components/picker/color-picker.js +9 -0
  186. package/build/components/picker/color-picker.js.map +1 -0
  187. package/build/components/picker/consts.local.d.ts +76 -0
  188. package/build/components/picker/consts.local.d.ts.map +1 -0
  189. package/build/components/picker/consts.local.js +214 -0
  190. package/build/components/picker/consts.local.js.map +1 -0
  191. package/build/components/picker/dot.d.ts +8 -0
  192. package/build/components/picker/dot.d.ts.map +1 -0
  193. package/build/components/picker/dot.js +10 -0
  194. package/build/components/picker/dot.js.map +1 -0
  195. package/build/components/picker/grid.d.ts +17 -0
  196. package/build/components/picker/grid.d.ts.map +1 -0
  197. package/build/components/picker/grid.js +73 -0
  198. package/build/components/picker/grid.js.map +1 -0
  199. package/build/components/picker/i18n/be.json +60 -0
  200. package/build/components/picker/i18n/de.json +60 -0
  201. package/build/components/picker/i18n/en.json +60 -0
  202. package/build/components/picker/i18n/es.json +60 -0
  203. package/build/components/picker/i18n/fr.json +60 -0
  204. package/build/components/picker/i18n/pl.json +60 -0
  205. package/build/components/picker/i18n/ru.json +60 -0
  206. package/build/components/picker/i18n/uk.json +60 -0
  207. package/build/components/picker/i18n.d.ts +2 -0
  208. package/build/components/picker/i18n.d.ts.map +1 -0
  209. package/build/components/picker/i18n.js +18 -0
  210. package/build/components/picker/i18n.js.map +1 -0
  211. package/build/components/picker/icon-color-picker.d.ts +14 -0
  212. package/build/components/picker/icon-color-picker.d.ts.map +1 -0
  213. package/build/components/picker/icon-color-picker.js +15 -0
  214. package/build/components/picker/icon-color-picker.js.map +1 -0
  215. package/build/components/picker/icon-picker.d.ts +8 -0
  216. package/build/components/picker/icon-picker.d.ts.map +1 -0
  217. package/build/components/picker/icon-picker.js +8 -0
  218. package/build/components/picker/icon-picker.js.map +1 -0
  219. package/build/components/picker/index.d.ts +11 -0
  220. package/build/components/picker/index.d.ts.map +1 -0
  221. package/build/components/picker/index.js +10 -0
  222. package/build/components/picker/index.js.map +1 -0
  223. package/build/components/picker/panel.d.ts +9 -0
  224. package/build/components/picker/panel.d.ts.map +1 -0
  225. package/build/components/picker/panel.js +23 -0
  226. package/build/components/picker/panel.js.map +1 -0
  227. package/build/components/picker/root.d.ts +13 -0
  228. package/build/components/picker/root.d.ts.map +1 -0
  229. package/build/components/picker/root.js +55 -0
  230. package/build/components/picker/root.js.map +1 -0
  231. package/build/components/picker/roving.d.ts +8 -0
  232. package/build/components/picker/roving.d.ts.map +1 -0
  233. package/build/components/picker/roving.js +62 -0
  234. package/build/components/picker/roving.js.map +1 -0
  235. package/build/components/picker/surface.d.ts +18 -0
  236. package/build/components/picker/surface.d.ts.map +1 -0
  237. package/build/components/picker/surface.js +36 -0
  238. package/build/components/picker/surface.js.map +1 -0
  239. package/build/components/picker/swatches/custom.d.ts +10 -0
  240. package/build/components/picker/swatches/custom.d.ts.map +1 -0
  241. package/build/components/picker/swatches/custom.js +65 -0
  242. package/build/components/picker/swatches/custom.js.map +1 -0
  243. package/build/components/picker/swatches.d.ts +16 -0
  244. package/build/components/picker/swatches.d.ts.map +1 -0
  245. package/build/components/picker/swatches.js +35 -0
  246. package/build/components/picker/swatches.js.map +1 -0
  247. package/build/components/picker/text.d.ts +5 -0
  248. package/build/components/picker/text.d.ts.map +1 -0
  249. package/build/components/picker/text.js +29 -0
  250. package/build/components/picker/text.js.map +1 -0
  251. package/build/components/picker/tile.d.ts +11 -0
  252. package/build/components/picker/tile.d.ts.map +1 -0
  253. package/build/components/picker/tile.js +19 -0
  254. package/build/components/picker/tile.js.map +1 -0
  255. package/build/components/picker/translate.d.ts +9 -0
  256. package/build/components/picker/translate.d.ts.map +1 -0
  257. package/build/components/picker/translate.js +13 -0
  258. package/build/components/picker/translate.js.map +1 -0
  259. package/build/components/picker/trigger.d.ts +12 -0
  260. package/build/components/picker/trigger.d.ts.map +1 -0
  261. package/build/components/picker/trigger.js +29 -0
  262. package/build/components/picker/trigger.js.map +1 -0
  263. package/build/components/picker/types.d.ts +114 -0
  264. package/build/components/picker/types.d.ts.map +1 -0
  265. package/build/components/picker/types.js +2 -0
  266. package/build/components/picker/types.js.map +1 -0
  267. package/build/components/picker/types.local.d.ts +143 -0
  268. package/build/components/picker/types.local.d.ts.map +1 -0
  269. package/build/components/picker/types.local.js +2 -0
  270. package/build/components/picker/types.local.js.map +1 -0
  271. package/build/components/scheme/consts.local.d.ts +8 -0
  272. package/build/components/scheme/consts.local.d.ts.map +1 -0
  273. package/build/components/scheme/consts.local.js +13 -0
  274. package/build/components/scheme/consts.local.js.map +1 -0
  275. package/build/components/scheme/hook.d.ts +16 -0
  276. package/build/components/scheme/hook.d.ts.map +1 -0
  277. package/build/components/scheme/hook.js +52 -0
  278. package/build/components/scheme/hook.js.map +1 -0
  279. package/build/components/scheme/index.d.ts +4 -0
  280. package/build/components/scheme/index.d.ts.map +1 -0
  281. package/build/components/scheme/index.js +3 -0
  282. package/build/components/scheme/index.js.map +1 -0
  283. package/build/components/scheme/toggle.d.ts +14 -0
  284. package/build/components/scheme/toggle.d.ts.map +1 -0
  285. package/build/components/scheme/toggle.js +24 -0
  286. package/build/components/scheme/toggle.js.map +1 -0
  287. package/build/components/scheme/types.d.ts +21 -0
  288. package/build/components/scheme/types.d.ts.map +1 -0
  289. package/build/components/scheme/types.js +2 -0
  290. package/build/components/scheme/types.js.map +1 -0
  291. package/build/components/socket/i18n/be.json +9 -0
  292. package/build/components/socket/i18n/de.json +9 -0
  293. package/build/components/socket/i18n/en.json +9 -0
  294. package/build/components/socket/i18n/es.json +9 -0
  295. package/build/components/socket/i18n/fr.json +9 -0
  296. package/build/components/socket/i18n/pl.json +9 -0
  297. package/build/components/socket/i18n/ru.json +9 -0
  298. package/build/components/socket/i18n/uk.json +9 -0
  299. package/build/components/socket/i18n.d.ts +2 -0
  300. package/build/components/socket/i18n.d.ts.map +1 -0
  301. package/build/components/socket/i18n.js +18 -0
  302. package/build/components/socket/i18n.js.map +1 -0
  303. package/build/components/socket/index.d.ts +3 -0
  304. package/build/components/socket/index.d.ts.map +1 -0
  305. package/build/components/socket/index.js +3 -0
  306. package/build/components/socket/index.js.map +1 -0
  307. package/build/components/socket/reload-dialog.d.ts +22 -0
  308. package/build/components/socket/reload-dialog.d.ts.map +1 -0
  309. package/build/components/socket/reload-dialog.js +34 -0
  310. package/build/components/socket/reload-dialog.js.map +1 -0
  311. package/build/components/status.js +1 -1
  312. package/build/components/status.js.map +1 -1
  313. package/build/components/text.d.ts.map +1 -1
  314. package/build/components/text.js +2 -13
  315. package/build/components/text.js.map +1 -1
  316. package/build/components/toaster.d.ts +16 -0
  317. package/build/components/toaster.d.ts.map +1 -0
  318. package/build/components/toaster.js +52 -0
  319. package/build/components/toaster.js.map +1 -0
  320. package/build/components/uploader/consts.local.d.ts +4 -0
  321. package/build/components/uploader/consts.local.d.ts.map +1 -0
  322. package/build/components/uploader/consts.local.js +6 -0
  323. package/build/components/uploader/consts.local.js.map +1 -0
  324. package/build/components/uploader/image.d.ts.map +1 -1
  325. package/build/components/uploader/image.js +2 -6
  326. package/build/components/uploader/image.js.map +1 -1
  327. package/build/consent/component.d.ts +27 -0
  328. package/build/consent/component.d.ts.map +1 -0
  329. package/build/consent/component.js +60 -0
  330. package/build/consent/component.js.map +1 -0
  331. package/build/consent/consts.d.ts +2 -0
  332. package/build/consent/consts.d.ts.map +1 -0
  333. package/build/consent/consts.js +2 -0
  334. package/build/consent/consts.js.map +1 -0
  335. package/build/consent/consts.local.d.ts +9 -0
  336. package/build/consent/consts.local.d.ts.map +1 -0
  337. package/build/consent/consts.local.js +9 -0
  338. package/build/consent/consts.local.js.map +1 -0
  339. package/build/consent/geo.d.ts +17 -0
  340. package/build/consent/geo.d.ts.map +1 -0
  341. package/build/consent/geo.js +19 -0
  342. package/build/consent/geo.js.map +1 -0
  343. package/build/consent/index.d.ts +11 -0
  344. package/build/consent/index.d.ts.map +1 -0
  345. package/build/consent/index.js +9 -0
  346. package/build/consent/index.js.map +1 -0
  347. package/build/consent/language.d.ts +12 -0
  348. package/build/consent/language.d.ts.map +1 -0
  349. package/build/consent/language.js +11 -0
  350. package/build/consent/language.js.map +1 -0
  351. package/build/consent/menu-widget.d.ts +13 -0
  352. package/build/consent/menu-widget.d.ts.map +1 -0
  353. package/build/consent/menu-widget.js +20 -0
  354. package/build/consent/menu-widget.js.map +1 -0
  355. package/build/consent/presence.d.ts +30 -0
  356. package/build/consent/presence.d.ts.map +1 -0
  357. package/build/consent/presence.js +40 -0
  358. package/build/consent/presence.js.map +1 -0
  359. package/build/consent/service.d.ts +18 -0
  360. package/build/consent/service.d.ts.map +1 -0
  361. package/build/consent/service.js +53 -0
  362. package/build/consent/service.js.map +1 -0
  363. package/build/consent/translate.d.ts +14 -0
  364. package/build/consent/translate.d.ts.map +1 -0
  365. package/build/consent/translate.js +28 -0
  366. package/build/consent/translate.js.map +1 -0
  367. package/build/consent/types.d.ts +39 -0
  368. package/build/consent/types.d.ts.map +1 -0
  369. package/build/consent/types.js +2 -0
  370. package/build/consent/types.js.map +1 -0
  371. package/build/consent/types.local.d.ts +6 -0
  372. package/build/consent/types.local.d.ts.map +1 -0
  373. package/build/consent/types.local.js +2 -0
  374. package/build/consent/types.local.js.map +1 -0
  375. package/build/context.d.ts.map +1 -1
  376. package/build/context.js +10 -0
  377. package/build/context.js.map +1 -1
  378. package/build/editor/component.d.ts +4 -0
  379. package/build/editor/component.d.ts.map +1 -0
  380. package/build/editor/component.js +103 -0
  381. package/build/editor/component.js.map +1 -0
  382. package/build/editor/consts.local.d.ts +6 -0
  383. package/build/editor/consts.local.d.ts.map +1 -0
  384. package/build/editor/consts.local.js +58 -0
  385. package/build/editor/consts.local.js.map +1 -0
  386. package/build/editor/index.d.ts +3 -0
  387. package/build/editor/index.d.ts.map +1 -0
  388. package/build/editor/index.js +2 -0
  389. package/build/editor/index.js.map +1 -0
  390. package/build/editor/types.d.ts +24 -0
  391. package/build/editor/types.d.ts.map +1 -0
  392. package/build/editor/types.js +2 -0
  393. package/build/editor/types.js.map +1 -0
  394. package/build/entrypoints.d.ts +8 -0
  395. package/build/entrypoints.d.ts.map +1 -0
  396. package/build/entrypoints.js +4 -0
  397. package/build/entrypoints.js.map +1 -0
  398. package/build/exports.d.ts +6 -5
  399. package/build/exports.d.ts.map +1 -1
  400. package/build/exports.js +5 -5
  401. package/build/exports.js.map +1 -1
  402. package/build/index.d.ts +1 -1
  403. package/build/index.d.ts.map +1 -1
  404. package/build/index.js +1 -1
  405. package/build/index.js.map +1 -1
  406. package/build/main.d.ts +1 -4
  407. package/build/main.d.ts.map +1 -1
  408. package/build/main.js.map +1 -1
  409. package/build/modules.d.ts +1 -1
  410. package/build/modules.d.ts.map +1 -1
  411. package/build/permission/i18n/be.json +13 -0
  412. package/build/permission/i18n/de.json +13 -0
  413. package/build/permission/i18n/en.json +13 -0
  414. package/build/permission/i18n/es.json +13 -0
  415. package/build/permission/i18n/fr.json +13 -0
  416. package/build/permission/i18n/pl.json +13 -0
  417. package/build/permission/i18n/ru.json +13 -0
  418. package/build/permission/i18n/uk.json +13 -0
  419. package/build/permission/i18n.d.ts +2 -0
  420. package/build/permission/i18n.d.ts.map +1 -0
  421. package/build/permission/i18n.js +13 -0
  422. package/build/permission/i18n.js.map +1 -0
  423. package/build/permission/index.d.ts +6 -0
  424. package/build/permission/index.d.ts.map +1 -0
  425. package/build/permission/index.js +27 -0
  426. package/build/permission/index.js.map +1 -0
  427. package/build/permission/toast.d.ts +5 -0
  428. package/build/permission/toast.d.ts.map +1 -0
  429. package/build/permission/toast.js +8 -0
  430. package/build/permission/toast.js.map +1 -0
  431. package/build/permission/types.d.ts +6 -0
  432. package/build/permission/types.d.ts.map +1 -0
  433. package/build/permission/types.js +2 -0
  434. package/build/permission/types.js.map +1 -0
  435. package/build/picker/icons/consts.d.ts +9 -0
  436. package/build/picker/icons/consts.d.ts.map +1 -0
  437. package/build/picker/icons/consts.js +264 -0
  438. package/build/picker/icons/consts.js.map +1 -0
  439. package/build/picker/icons/types.d.ts +18 -0
  440. package/build/picker/icons/types.d.ts.map +1 -0
  441. package/build/picker/icons/types.js +2 -0
  442. package/build/picker/icons/types.js.map +1 -0
  443. package/build/picker/icons.d.ts +4 -0
  444. package/build/picker/icons.d.ts.map +1 -0
  445. package/build/picker/icons.js +54 -0
  446. package/build/picker/icons.js.map +1 -0
  447. package/build/picker/index.d.ts +11 -0
  448. package/build/picker/index.d.ts.map +1 -0
  449. package/build/picker/index.js +10 -0
  450. package/build/picker/index.js.map +1 -0
  451. package/build/picker/utils/color/types.d.ts +35 -0
  452. package/build/picker/utils/color/types.d.ts.map +1 -0
  453. package/build/picker/utils/color/types.js +2 -0
  454. package/build/picker/utils/color/types.js.map +1 -0
  455. package/build/picker/utils/color.d.ts +4 -0
  456. package/build/picker/utils/color.d.ts.map +1 -0
  457. package/build/picker/utils/color.js +96 -0
  458. package/build/picker/utils/color.js.map +1 -0
  459. package/build/picker/vocabulary/consts.d.ts +26 -0
  460. package/build/picker/vocabulary/consts.d.ts.map +1 -0
  461. package/build/picker/vocabulary/consts.js +336 -0
  462. package/build/picker/vocabulary/consts.js.map +1 -0
  463. package/build/picker/vocabulary/types.d.ts +67 -0
  464. package/build/picker/vocabulary/types.d.ts.map +1 -0
  465. package/build/picker/vocabulary/types.js +2 -0
  466. package/build/picker/vocabulary/types.js.map +1 -0
  467. package/build/picker/vocabulary.d.ts +11 -0
  468. package/build/picker/vocabulary.d.ts.map +1 -0
  469. package/build/picker/vocabulary.js +83 -0
  470. package/build/picker/vocabulary.js.map +1 -0
  471. package/build/scheme/consts.d.ts +8 -0
  472. package/build/scheme/consts.d.ts.map +1 -0
  473. package/build/scheme/consts.js +8 -0
  474. package/build/scheme/consts.js.map +1 -0
  475. package/build/scheme/index.d.ts +4 -0
  476. package/build/scheme/index.d.ts.map +1 -0
  477. package/build/scheme/index.js +3 -0
  478. package/build/scheme/index.js.map +1 -0
  479. package/build/scheme/scheme.d.ts +16 -0
  480. package/build/scheme/scheme.d.ts.map +1 -0
  481. package/build/scheme/scheme.js +58 -0
  482. package/build/scheme/scheme.js.map +1 -0
  483. package/build/scheme/types.d.ts +30 -0
  484. package/build/scheme/types.d.ts.map +1 -0
  485. package/build/scheme/types.js +2 -0
  486. package/build/scheme/types.js.map +1 -0
  487. package/build/types.d.ts +18 -2
  488. package/build/types.d.ts.map +1 -1
  489. package/package.json +107 -52
  490. package/src/@/components/ui/alert-dialog.tsx +156 -0
  491. package/src/@/components/ui/alert.tsx +1 -1
  492. package/src/@/components/ui/button.tsx +1 -1
  493. package/src/@/components/ui/card.tsx +1 -1
  494. package/src/@/components/ui/input.tsx +1 -1
  495. package/src/@/components/ui/label.tsx +1 -1
  496. package/src/@/components/ui/navigation-menu.tsx +1 -1
  497. package/src/@/components/ui/popover.tsx +47 -0
  498. package/src/@/components/ui/progress.tsx +1 -1
  499. package/src/@/components/ui/separator.tsx +1 -1
  500. package/src/@/components/ui/sheet.tsx +142 -0
  501. package/src/auth/context.ts +0 -2
  502. package/src/auth/entrypoints.ts +5 -0
  503. package/src/auth/exports.ts +4 -4
  504. package/src/auth/plugins/basic-ed25519.tsx +4 -4
  505. package/src/auth/plugins/re-captcha.tsx +3 -3
  506. package/src/auth/plugins/tunnel-consumer.tsx +1 -1
  507. package/src/components/block.tsx +2 -2
  508. package/src/components/consts.local.ts +29 -0
  509. package/src/components/footer/component.tsx +58 -16
  510. package/src/components/footer/credit.tsx +61 -0
  511. package/src/components/footer/index.ts +1 -0
  512. package/src/components/footer/types.ts +22 -1
  513. package/src/components/form/button/component.tsx +7 -4
  514. package/src/components/form/component.tsx +2 -2
  515. package/src/components/form/text/component.tsx +2 -2
  516. package/src/components/helper.ts +1 -13
  517. package/src/components/index.ts +4 -0
  518. package/src/components/link.tsx +3 -3
  519. package/src/components/login/append.ts +34 -0
  520. package/src/components/login/consts.local.ts +10 -0
  521. package/src/components/login/consts.ts +2 -0
  522. package/src/components/login/credit.tsx +33 -0
  523. package/src/components/login/i18n/be.json +10 -0
  524. package/src/components/login/i18n/de.json +10 -0
  525. package/src/components/login/i18n/en.json +10 -0
  526. package/src/components/login/i18n/es.json +10 -0
  527. package/src/components/login/i18n/fr.json +10 -0
  528. package/src/components/login/i18n/pl.json +10 -0
  529. package/src/components/login/i18n/ru.json +10 -0
  530. package/src/components/login/i18n/uk.json +10 -0
  531. package/src/components/login/i18n.ts +29 -0
  532. package/src/components/login/icons.tsx +39 -0
  533. package/src/components/login/index.ts +11 -0
  534. package/src/components/login/notify.ts +48 -0
  535. package/src/components/login/provider.tsx +57 -0
  536. package/src/components/login/screen.tsx +178 -0
  537. package/src/components/login/terms.tsx +75 -0
  538. package/src/components/login/types.ts +30 -0
  539. package/src/components/nav/consts.local.ts +64 -0
  540. package/src/components/nav/index.ts +1 -0
  541. package/src/components/nav/layout.tsx +184 -26
  542. package/src/components/nav/mobile.tsx +165 -0
  543. package/src/components/nav/side.tsx +43 -27
  544. package/src/components/nav/top.tsx +44 -22
  545. package/src/components/nav/types.ts +65 -2
  546. package/src/components/nav/viewport.ts +16 -0
  547. package/src/components/panel-app/component.tsx +9 -1
  548. package/src/components/picker/color-picker.tsx +15 -0
  549. package/src/components/picker/consts.local.ts +267 -0
  550. package/src/components/picker/dot.tsx +21 -0
  551. package/src/components/picker/grid.tsx +138 -0
  552. package/src/components/picker/i18n/be.json +60 -0
  553. package/src/components/picker/i18n/de.json +60 -0
  554. package/src/components/picker/i18n/en.json +60 -0
  555. package/src/components/picker/i18n/es.json +60 -0
  556. package/src/components/picker/i18n/fr.json +60 -0
  557. package/src/components/picker/i18n/pl.json +60 -0
  558. package/src/components/picker/i18n/ru.json +60 -0
  559. package/src/components/picker/i18n/uk.json +60 -0
  560. package/src/components/picker/i18n.ts +19 -0
  561. package/src/components/picker/icon-color-picker.tsx +25 -0
  562. package/src/components/picker/icon-picker.tsx +13 -0
  563. package/src/components/picker/index.ts +11 -0
  564. package/src/components/picker/panel.tsx +61 -0
  565. package/src/components/picker/root.tsx +81 -0
  566. package/src/components/picker/roving.ts +70 -0
  567. package/src/components/picker/surface.tsx +62 -0
  568. package/src/components/picker/swatches/custom.tsx +110 -0
  569. package/src/components/picker/swatches.tsx +67 -0
  570. package/src/components/picker/text.ts +46 -0
  571. package/src/components/picker/tile.tsx +35 -0
  572. package/src/components/picker/translate.ts +15 -0
  573. package/src/components/picker/trigger.tsx +54 -0
  574. package/src/components/picker/types.local.ts +154 -0
  575. package/src/components/picker/types.ts +125 -0
  576. package/src/components/scheme/consts.local.ts +13 -0
  577. package/src/components/scheme/hook.ts +62 -0
  578. package/src/components/scheme/index.ts +4 -0
  579. package/src/components/scheme/toggle.tsx +32 -0
  580. package/src/components/scheme/types.ts +23 -0
  581. package/src/components/socket/i18n/be.json +9 -0
  582. package/src/components/socket/i18n/de.json +9 -0
  583. package/src/components/socket/i18n/en.json +9 -0
  584. package/src/components/socket/i18n/es.json +9 -0
  585. package/src/components/socket/i18n/fr.json +9 -0
  586. package/src/components/socket/i18n/pl.json +9 -0
  587. package/src/components/socket/i18n/ru.json +9 -0
  588. package/src/components/socket/i18n/uk.json +9 -0
  589. package/src/components/socket/i18n.ts +19 -0
  590. package/src/components/socket/index.ts +2 -0
  591. package/src/components/socket/reload-dialog.tsx +61 -0
  592. package/src/components/status.tsx +1 -1
  593. package/src/components/text.tsx +2 -14
  594. package/src/components/toaster.tsx +65 -0
  595. package/src/components/uploader/consts.local.ts +7 -0
  596. package/src/components/uploader/image.tsx +2 -6
  597. package/src/consent/component.tsx +84 -0
  598. package/src/consent/consts.local.ts +10 -0
  599. package/src/consent/consts.ts +1 -0
  600. package/src/consent/geo.ts +26 -0
  601. package/src/consent/index.ts +24 -0
  602. package/src/consent/language.ts +12 -0
  603. package/src/consent/menu-widget.tsx +22 -0
  604. package/src/consent/presence.ts +45 -0
  605. package/src/consent/service.ts +75 -0
  606. package/src/consent/translate.ts +31 -0
  607. package/src/consent/types.local.ts +6 -0
  608. package/src/consent/types.ts +43 -0
  609. package/src/context.ts +12 -0
  610. package/src/editor/component.tsx +172 -0
  611. package/src/editor/consts.local.ts +62 -0
  612. package/src/editor/index.ts +2 -0
  613. package/src/editor/types.ts +24 -0
  614. package/src/entrypoints.ts +5 -0
  615. package/src/exports.ts +6 -5
  616. package/src/index.ts +1 -1
  617. package/src/main.tsx +2 -6
  618. package/src/permission/i18n/be.json +13 -0
  619. package/src/permission/i18n/de.json +13 -0
  620. package/src/permission/i18n/en.json +13 -0
  621. package/src/permission/i18n/es.json +13 -0
  622. package/src/permission/i18n/fr.json +13 -0
  623. package/src/permission/i18n/pl.json +13 -0
  624. package/src/permission/i18n/ru.json +13 -0
  625. package/src/permission/i18n/uk.json +13 -0
  626. package/src/permission/i18n.ts +13 -0
  627. package/src/permission/index.ts +27 -0
  628. package/src/permission/toast.tsx +20 -0
  629. package/src/permission/types.ts +5 -0
  630. package/src/picker/icons/consts.ts +309 -0
  631. package/src/picker/icons/types.ts +18 -0
  632. package/src/picker/icons.ts +70 -0
  633. package/src/picker/index.ts +11 -0
  634. package/src/picker/utils/color/types.ts +37 -0
  635. package/src/picker/utils/color.ts +119 -0
  636. package/src/picker/vocabulary/consts.ts +347 -0
  637. package/src/picker/vocabulary/types.ts +72 -0
  638. package/src/picker/vocabulary.ts +111 -0
  639. package/src/scheme/consts.ts +8 -0
  640. package/src/scheme/index.ts +3 -0
  641. package/src/scheme/scheme.ts +66 -0
  642. package/src/scheme/types.ts +30 -0
  643. package/src/types.ts +19 -2
  644. package/tests/consent-language.spec.ts +31 -0
  645. package/tests/consent.spec.ts +112 -0
  646. package/tests/context.ts +4 -0
  647. package/tests/editor.spec.ts +58 -0
  648. package/tests/harness/editor.tsx +32 -0
  649. package/tests/harness/index.html +1 -0
  650. package/tests/harness/lazy-screen.tsx +9 -0
  651. package/tests/harness/mount.tsx +370 -29
  652. package/tests/harness/picker.tsx +110 -0
  653. package/tests/lazy.spec.ts +104 -0
  654. package/tests/login-provider.spec.ts +114 -0
  655. package/tests/login.spec.ts +447 -0
  656. package/tests/nav.spec.ts +449 -3
  657. package/tests/package-boundary.spec.ts +19 -0
  658. package/tests/picker-shots.spec.ts +174 -0
  659. package/tests/picker-vocabulary.spec.ts +217 -0
  660. package/tests/picker.spec.ts +333 -0
  661. package/tests/scheme.spec.ts +149 -0
  662. package/tests/smoke.spec.ts +2 -2
  663. package/tests/socket-dialog.spec.ts +154 -0
  664. package/tests/toaster.spec.ts +59 -0
  665. package/zz-tw.d.mts +2 -0
  666. package/zz-tw.d.mts.map +1 -0
  667. package/build/.gitkeep +0 -0
  668. package/src/auth/modules.ts +0 -5
  669. package/src/modules.ts +0 -5
@@ -1,5 +1,6 @@
1
1
  import type { PropsWithChildren, ReactNode } from 'react'
2
2
  import type { NavTranslate, PanelNavConfig, PanelNavLink } from '@owlmeans/client-panel'
3
+ import type { FooterThemeToggle } from '../footer/types.js'
3
4
  import type { StyledProps } from '../types.js'
4
5
 
5
6
  interface NavCommonProps extends StyledProps {
@@ -7,9 +8,10 @@ interface NavCommonProps extends StyledProps {
7
8
  /** See {@link NavTranslate} — omitted, literal labels and humanized aliases are used. */
8
9
  translate?: NavTranslate
9
10
  ariaLabel?: string
11
+ testId?: string
10
12
  }
11
13
 
12
- export interface TopNavProps extends NavCommonProps { }
14
+ export interface TopNavProps extends NavCommonProps {}
13
15
 
14
16
  export interface SideNavProps extends NavCommonProps {
15
17
  /**
@@ -19,8 +21,17 @@ export interface SideNavProps extends NavCommonProps {
19
21
  variant?: 'side' | 'bar'
20
22
  }
21
23
 
24
+ /**
25
+ * `ariaLabel` names the navigation landmark INSIDE the sheet; `translate` also resolves the menu
26
+ * button's accessible name and the sheet's title (`shell.menu`, default "Menu") and its close
27
+ * button's (`shell.close`, default "Close"). `className` and `style` land on the trigger button.
28
+ */
29
+ export interface MobileNavProps extends NavCommonProps {}
30
+
22
31
  export interface NavLayoutProps extends PropsWithChildren<StyledProps> {
23
32
  nav: PanelNavConfig
33
+ /** Stable selector on the desktop navigation landmark. */
34
+ navTestId?: string
24
35
  translate?: NavTranslate
25
36
  /** Brand slot — rendered at the far left of the header. */
26
37
  title?: ReactNode
@@ -28,7 +39,59 @@ export interface NavLayoutProps extends PropsWithChildren<StyledProps> {
28
39
  home?: string
29
40
  /** Header right side — sign-in controls, a theme toggle, whatever the app puts there. */
30
41
  actions?: ReactNode
31
- /** Links array renders the standard footer; a node replaces it entirely. */
42
+ /**
43
+ * Opt-in narrow-viewport menu. Below `md` (768px) the section menu is hidden and a menu button
44
+ * at the end of the header opens a sheet listing every section and its screens ({@link
45
+ * MobileNavProps}); `actions` stay in the header at every width. The screen strip the narrow
46
+ * viewport otherwise gets under the header is NOT rendered then — the sheet already lists the
47
+ * same screens, and two menus for one level is one too many. Off, the shell is exactly what it
48
+ * has always been.
49
+ */
50
+ mobileMenu?: boolean
51
+ /**
52
+ * The skip link rendered first in the page, ahead of the header, moving focus to the content
53
+ * (`<main id="main">`). Invisible until focused, then a pill in the top-left corner. Defaults to
54
+ * `translate('shell.skip', 'Skip to content')`; `false` renders no link AND leaves `main`
55
+ * without the `main` id, for an application that renders its own skip link and target.
56
+ */
57
+ skipLinkLabel?: string | false
58
+ /**
59
+ * The light/dark switcher in the footer's bottom row, beside the credit — forwarded to
60
+ * `Footer`, whether `footer` is links, a node or absent. The accessible names resolve
61
+ * `shell.toLight` / `shell.toDark` through `translate` unless `labels` gives them. Absent or
62
+ * `false`, the footer renders exactly as it does without one.
63
+ */
64
+ themeToggle?: FooterThemeToggle
65
+ /**
66
+ * An array renders the standard footer: a centred row of links above the credit line.
67
+ *
68
+ * A node is the application's OWN footer layout — brand, description, link columns — and is
69
+ * rendered as a full-width block (`w-full self-stretch`, start-aligned text) inside the footer's
70
+ * container, on the shell's rhythm, above the platform/owner credit line. It never replaces the
71
+ * credit: `ShellCredit` stays last in every footer, and nothing a caller passes here removes it.
72
+ */
32
73
  footer?: PanelNavLink[] | ReactNode
74
+ /**
75
+ * Styles the HEADER — the sticky bar carrying the brand, the section menu and `actions`.
76
+ *
77
+ * The header is its own SURFACE: it paints an opaque background because content scrolls
78
+ * under it. Give it a background here and you must give it the paired foreground too
79
+ * (`bg-secondary text-secondary-foreground`), exactly as on any other surface — this is the
80
+ * supported way to give an application a dark top bar, and it is why colouring the root
81
+ * instead is not.
82
+ */
83
+ headerClassName?: string
84
+ /** Styles the content area. NOT its width — see `containerClassName`. */
33
85
  contentClassName?: string
86
+ /**
87
+ * The page's horizontal rhythm — width and side padding — applied identically to the header
88
+ * row, the content and the footer row. Give the content a width of its own and it sits inset
89
+ * from a full-width header, which reads as a bug rather than as a layout.
90
+ *
91
+ * MERGED over the shell's default (`mx-auto w-full max-w-6xl px-4`), not substituted for it:
92
+ * pass `max-w-[1280px]` and only the width changes, while the centring and the side padding
93
+ * stay. Name the utility you actually want to move — `px-8` widens the gutters — because
94
+ * anything you do not name keeps its default.
95
+ */
96
+ containerClassName?: string
34
97
  }
@@ -0,0 +1,16 @@
1
+ import { useEffect, useState } from 'react'
2
+
3
+ /** The same md boundary as the shell's Tailwind layout, including resize after mount. */
4
+ export const useWideNav = (): boolean => {
5
+ const [wide, setWide] = useState(
6
+ () => typeof window === 'undefined' || window.matchMedia('(min-width: 768px)').matches
7
+ )
8
+ useEffect(() => {
9
+ const media = window.matchMedia('(min-width: 768px)')
10
+ const change = () => setWide(media.matches)
11
+ change()
12
+ media.addEventListener('change', change)
13
+ return () => media.removeEventListener('change', change)
14
+ }, [])
15
+ return wide
16
+ }
@@ -3,13 +3,21 @@ import type { PanelAppProps } from './types.js'
3
3
 
4
4
  import { App } from '@owlmeans/client'
5
5
  import { I18nContext } from '@owlmeans/client-i18n'
6
- import { cn } from '@/lib/utils'
6
+ import { cn } from '../../@/lib/utils.js'
7
+ import { SocketReloadDialog } from '../socket/reload-dialog.js'
7
8
 
8
9
  export const PanelApp: FC<PanelAppProps> = ({ context, provide, children, rootClassName }) => {
9
10
  return <div className={cn('min-h-screen bg-background text-foreground', rootClassName)}>
10
11
  <I18nContext config={context.cfg}>
11
12
  <App context={context} provide={provide}>
12
13
  {children}
14
+ {/*
15
+ A sibling of the Router, exactly like `PanelCookieConsent` — a dialog mounted inside a
16
+ route is torn down on every navigation, which for a modal means it closes itself the
17
+ first time anything moves. Opt-in per app via `cfg.socket.reloadDialog`; the component
18
+ itself stays inert (renders nothing) whenever the flag is off or nothing is `'lost'`.
19
+ */}
20
+ {context.cfg.socket?.reloadDialog === true && <SocketReloadDialog />}
13
21
  </App>
14
22
  </I18nContext>
15
23
  </div>
@@ -0,0 +1,15 @@
1
+ import type { FC } from 'react'
2
+ import type { ColorPickerProps } from './types.js'
3
+ import { PickerRoot } from './root.js'
4
+
5
+ /**
6
+ * The colour half alone: a trigger opening the swatches (plus a colour wheel and a hex field with
7
+ * `customColors`). A swatch commits its key and closes; the wheel and the field commit as they
8
+ * change and keep it open. Pass `colors` for an application palette — a status palette, say.
9
+ */
10
+ export const ColorPicker: FC<ColorPickerProps> = (
11
+ { value, onChange, trigger = 'button', customColors = false, ...base }
12
+ ) => <PickerRoot
13
+ {...base} mode="color" trigger={trigger} customColors={customColors} closeOnPick color={value}
14
+ onColor={onChange} onIcon={() => undefined}
15
+ />
@@ -0,0 +1,267 @@
1
+ import type { CSSProperties } from 'react'
2
+ import type { PickerDotSize, PickerTileSize } from './types.js'
3
+ import type { PickerLayout } from './types.local.js'
4
+
5
+ /** From this width up `surface="auto"` opens a popover; below it, a bottom sheet. */
6
+ export const POPOVER_QUERY = '(min-width: 768px)'
7
+
8
+ /** A mouse or trackpad — the search field may take focus on open without raising a keyboard. */
9
+ export const FINE_POINTER_QUERY = '(pointer: fine)'
10
+
11
+ /**
12
+ * The current mode's ink and ground, read from the five custom properties `styleOf` sets.
13
+ *
14
+ * Dark follows web-panel's colour-scheme contract — `.dark` on the document element, or the
15
+ * operating system's dark unless `.light` is there — through explicit arbitrary variants. Never the
16
+ * consumer's `dark:`: an application may define it any way it likes, or not at all. Every part that
17
+ * carries a colour's style puts this on the same element; children read `--pick-fg` / `--pick-bg`.
18
+ */
19
+ export const PICK_SCOPE = [
20
+ '[--pick-fg:var(--pick-ink)] [--pick-bg:var(--pick-soft)]',
21
+ '[.dark_&]:[--pick-fg:var(--pick-ink-dark)] [.dark_&]:[--pick-bg:var(--pick-soft-dark)]',
22
+ '[@media(prefers-color-scheme:dark)]:[:root:not(.light)_&]:[--pick-fg:var(--pick-ink-dark)]',
23
+ '[@media(prefers-color-scheme:dark)]:[:root:not(.light)_&]:[--pick-bg:var(--pick-soft-dark)]',
24
+ ].join(' ')
25
+
26
+ /** A hairline inside a swatch, so a dark swatch keeps an edge on a dark surface and a pale one on a light. */
27
+ export const HAIRLINE = [
28
+ 'shadow-[inset_0_0_0_1px_rgb(0_0_0/0.14)]',
29
+ '[.dark_&]:shadow-[inset_0_0_0_1px_rgb(255_255_255/0.24)]',
30
+ '[@media(prefers-color-scheme:dark)]:[:root:not(.light)_&]:shadow-[inset_0_0_0_1px_rgb(255_255_255/0.24)]',
31
+ ].join(' ')
32
+
33
+ export const TILE = 'inline-flex shrink-0 items-center justify-center bg-(--pick-bg) text-(--pick-fg)'
34
+
35
+ export const TILE_SIZE: Record<PickerTileSize, string> = {
36
+ xs: 'size-5 rounded-[5px] [&>svg]:size-3',
37
+ sm: 'size-7 rounded-md [&>svg]:size-4',
38
+ md: 'size-9 rounded-lg [&>svg]:size-5',
39
+ lg: 'size-12 rounded-xl [&>svg]:size-6',
40
+ }
41
+
42
+ export const PLAIN = 'inline-flex shrink-0 items-center justify-center text-(--pick-fg)'
43
+
44
+ export const PLAIN_SIZE: Record<PickerTileSize, string> = {
45
+ xs: '[&>svg]:size-3',
46
+ sm: '[&>svg]:size-4',
47
+ md: '[&>svg]:size-5',
48
+ lg: '[&>svg]:size-6',
49
+ }
50
+
51
+ export const DOT = 'inline-block shrink-0 rounded-full bg-(--pick-fg)'
52
+
53
+ export const DOT_SIZE: Record<PickerDotSize, string> = {
54
+ xs: 'size-2',
55
+ sm: 'size-2.5',
56
+ md: 'size-3.5',
57
+ }
58
+
59
+ /**
60
+ * Focus on a cell is an outline, so it never fights the ring that marks the selected one. Tailwind
61
+ * v4's `outline-none` would pin the style to `none` under the focus width — `outline-hidden` plus an
62
+ * explicit `outline-solid` is what shows it.
63
+ */
64
+ const CELL_FOCUS = [
65
+ 'outline-hidden focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-1',
66
+ 'focus-visible:outline-ring',
67
+ ].join(' ')
68
+
69
+ /** Below 768px and on a coarse pointer every control is at least 44px. */
70
+ const TOUCH_HEIGHT = 'max-md:h-11 pointer-coarse:h-11'
71
+
72
+ export const TRIGGER_BUTTON = [
73
+ 'group/picker inline-flex h-9 w-full min-w-0 cursor-pointer items-center gap-2 rounded-md border border-input',
74
+ 'bg-transparent py-1 pr-2.5 pl-1 text-left text-sm shadow-xs outline-none',
75
+ 'transition-[color,box-shadow,background-color] hover:bg-accent/60 motion-reduce:transition-none',
76
+ 'focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50',
77
+ 'aria-expanded:border-ring aria-expanded:ring-[3px] aria-expanded:ring-ring/30',
78
+ 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
79
+ 'max-md:h-11 max-md:pl-2 pointer-coarse:h-11 pointer-coarse:pl-2',
80
+ ].join(' ')
81
+
82
+ export const TRIGGER_COMPACT = [
83
+ 'inline-flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-lg outline-none',
84
+ 'transition-shadow motion-reduce:transition-none',
85
+ 'focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-expanded:ring-[3px] aria-expanded:ring-ring/30',
86
+ 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
87
+ 'max-md:size-11 pointer-coarse:size-11',
88
+ ].join(' ')
89
+
90
+ export const TRIGGER_DOT = 'rounded-full border border-input bg-transparent hover:bg-accent/60'
91
+
92
+ /** The empty tile of a trigger while nothing is chosen. */
93
+ export const TRIGGER_EMPTY = [
94
+ 'inline-flex size-7 shrink-0 items-center justify-center rounded-md border border-dashed',
95
+ 'border-muted-foreground/40 text-muted-foreground [&>svg]:size-4',
96
+ ].join(' ')
97
+
98
+ export const CHEVRON = [
99
+ 'ml-auto size-4 shrink-0 text-muted-foreground transition-transform motion-reduce:transition-none',
100
+ 'group-aria-expanded/picker:rotate-180',
101
+ ].join(' ')
102
+
103
+ export const POPOVER = [
104
+ 'flex w-[23rem] max-w-[calc(100vw-1.5rem)] flex-col overflow-hidden rounded-xl border border-border p-0 shadow-lg',
105
+ 'bg-popover text-popover-foreground',
106
+ 'max-h-[min(34rem,var(--radix-popover-content-available-height))]',
107
+ // `!`: the primitive's `data-[state=open]:animate-in` outranks a plain variant class.
108
+ 'pointer-coarse:w-[26rem] motion-reduce:animate-none! motion-reduce:transition-none!',
109
+ ].join(' ')
110
+
111
+ export const SHEET = [
112
+ 'mx-auto max-h-[88dvh] w-full gap-0 overflow-hidden rounded-t-2xl border-t border-border p-0',
113
+ 'bg-popover text-popover-foreground pb-[env(safe-area-inset-bottom)]',
114
+ 'sm:max-w-xl sm:border-x motion-reduce:animate-none! motion-reduce:transition-none!',
115
+ ].join(' ')
116
+
117
+ /** With an icon grid the surface keeps one height, so filtering never makes it jump. */
118
+ export const TALL: Record<'popover' | 'sheet', string> = {
119
+ popover: 'h-[min(34rem,var(--radix-popover-content-available-height))]',
120
+ sheet: 'h-[88dvh]',
121
+ }
122
+
123
+ /** The trigger's swatch disc for a colour-only picker — the colour as it was picked. */
124
+ export const TRIGGER_DISC = 'block size-4 shrink-0 rounded-full bg-(--pick-swatch)'
125
+
126
+ export const GRAB = 'mx-auto mt-2 mb-1 h-1.5 w-10 shrink-0 rounded-full bg-muted-foreground/30'
127
+
128
+ export const HEADER: Record<'popover' | 'sheet', string> = {
129
+ popover: 'flex shrink-0 items-center gap-3 border-b border-border px-3 py-2.5',
130
+ sheet: 'flex shrink-0 items-center gap-3 border-b border-border px-4 pt-1 pb-3',
131
+ }
132
+
133
+ export const HEADER_TITLE = 'truncate text-sm font-semibold leading-5'
134
+ export const HEADER_SUMMARY = 'truncate text-xs leading-4 text-muted-foreground'
135
+
136
+ export const DONE = [
137
+ 'inline-flex h-11 min-w-16 shrink-0 cursor-pointer items-center justify-center rounded-lg px-4',
138
+ 'bg-primary text-sm font-medium text-primary-foreground outline-none hover:bg-primary/90',
139
+ 'focus-visible:ring-[3px] focus-visible:ring-ring/50',
140
+ ].join(' ')
141
+
142
+ export const BODY = 'min-h-0 flex-1 overflow-y-auto overscroll-contain'
143
+
144
+ export const SECTION: Record<'popover' | 'sheet', string> = {
145
+ popover: 'px-3 pt-3',
146
+ sheet: 'px-4 pt-4',
147
+ }
148
+
149
+ export const SECTION_TITLE = 'mb-2 text-xs font-medium text-muted-foreground'
150
+
151
+ export const SWATCHES: Record<PickerLayout, string> = {
152
+ popover: [
153
+ 'grid grid-cols-12 gap-1',
154
+ 'max-md:grid-cols-[repeat(auto-fill,minmax(44px,1fr))] pointer-coarse:grid-cols-[repeat(auto-fill,minmax(44px,1fr))]',
155
+ ].join(' '),
156
+ sheet: 'grid grid-cols-[repeat(auto-fill,minmax(44px,1fr))] gap-1.5',
157
+ inline: [
158
+ 'grid grid-cols-[repeat(auto-fill,minmax(44px,1fr))] gap-1.5',
159
+ 'md:pointer-fine:grid-cols-[repeat(12,minmax(0,2rem))] md:pointer-fine:gap-1',
160
+ ].join(' '),
161
+ }
162
+
163
+ export const SWATCH = [
164
+ 'group/swatch inline-flex aspect-square w-full min-w-0 cursor-pointer items-center justify-center rounded-full',
165
+ CELL_FOCUS,
166
+ ].join(' ')
167
+
168
+ export const SWATCH_DISC = [
169
+ 'pointer-events-none block size-[76%] max-h-9 max-w-9 rounded-full bg-(--pick-swatch)',
170
+ 'transition-transform group-hover/swatch:scale-110 motion-reduce:transition-none motion-reduce:group-hover/swatch:scale-100',
171
+ HAIRLINE,
172
+ ].join(' ')
173
+
174
+ export const SWATCH_SELECTED = 'ring-2 ring-foreground ring-offset-2 ring-offset-popover'
175
+
176
+ export const CUSTOM_ROW = [
177
+ 'mt-2 flex h-8 w-full cursor-pointer items-center gap-2 rounded-md px-1.5 text-left text-sm',
178
+ 'hover:bg-accent hover:text-accent-foreground',
179
+ 'outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50',
180
+ TOUCH_HEIGHT,
181
+ ].join(' ')
182
+
183
+ export const CUSTOM_DISC = 'block size-5 shrink-0 rounded-full'
184
+
185
+ /** The colour wheel's mark while no custom colour is chosen. */
186
+ export const RAINBOW = 'bg-[conic-gradient(from_180deg,#ef4444,#f59e0b,#eab308,#22c55e,#06b6d4,#3b82f6,#8b5cf6,#ec4899,#ef4444)]'
187
+
188
+ export const CUSTOM_PANEL = 'mt-2 flex flex-col gap-2'
189
+
190
+ /** A full six-digit value — committed while typing; a three-digit one waits for Enter or blur. */
191
+ export const FULL_HEX = /^#?[0-9a-f]{6}$/i
192
+
193
+ /** The wheel's colour while nothing custom is chosen yet — also the hex field's placeholder. */
194
+ export const CUSTOM_START = '#3b82f6'
195
+
196
+ /** react-colorful sizes itself with a stylesheet it injects; an inline size is the one that always wins. */
197
+ export const WHEEL_STYLE: CSSProperties = { width: '100%', height: 148 }
198
+
199
+ export const FIELD = [
200
+ 'h-8 w-full min-w-0 rounded-md border border-input bg-transparent px-2.5 text-sm shadow-xs outline-none',
201
+ 'placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50',
202
+ 'aria-invalid:border-destructive aria-invalid:ring-destructive/20',
203
+ TOUCH_HEIGHT,
204
+ ].join(' ')
205
+
206
+ export const HEX_FIELD = 'font-mono'
207
+
208
+ export const FIELD_ERROR = 'text-xs text-destructive'
209
+
210
+ /** The search field and the chips stay in view while the grid scrolls under them. */
211
+ export const ICON_TOOLS: Record<PickerLayout, string> = {
212
+ popover: 'sticky top-0 z-10 -mx-3 bg-popover px-3 pb-2',
213
+ sheet: 'sticky top-0 z-10 -mx-4 bg-popover px-4 pb-2',
214
+ inline: 'pb-2',
215
+ }
216
+
217
+ export const SEARCH_WRAP = 'relative'
218
+ export const SEARCH_ICON = 'pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground'
219
+ export const SEARCH = 'pl-8 [&::-webkit-search-cancel-button]:cursor-pointer'
220
+
221
+ /** One scrolling row of category chips, running to the surface's edges rather than its padding. */
222
+ export const CHIPS: Record<PickerLayout, string> = {
223
+ popover: 'mt-2 -mx-3 flex gap-1.5 overflow-x-auto px-3 pb-0.5 scroll-px-3 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
224
+ sheet: 'mt-2 -mx-4 flex gap-1.5 overflow-x-auto px-4 pb-0.5 scroll-px-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
225
+ inline: 'mt-2 flex gap-1.5 overflow-x-auto pb-0.5 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
226
+ }
227
+
228
+ export const CHIP = [
229
+ 'inline-flex h-7 shrink-0 cursor-pointer items-center rounded-full border border-input px-2.5',
230
+ 'text-xs font-medium text-muted-foreground transition-colors motion-reduce:transition-none',
231
+ 'hover:bg-accent hover:text-accent-foreground',
232
+ 'aria-pressed:border-transparent aria-pressed:bg-primary aria-pressed:text-primary-foreground',
233
+ CELL_FOCUS,
234
+ 'max-md:h-11 max-md:px-4 max-md:text-sm pointer-coarse:h-11 pointer-coarse:px-4 pointer-coarse:text-sm',
235
+ ].join(' ')
236
+
237
+ export const ICONS: Record<PickerLayout, string> = {
238
+ popover: [
239
+ 'grid grid-cols-9 gap-0.5',
240
+ 'max-md:grid-cols-[repeat(auto-fill,minmax(44px,1fr))] pointer-coarse:grid-cols-[repeat(auto-fill,minmax(44px,1fr))]',
241
+ ].join(' '),
242
+ sheet: 'grid grid-cols-[repeat(auto-fill,minmax(44px,1fr))] gap-1',
243
+ inline: [
244
+ 'grid grid-cols-[repeat(auto-fill,minmax(44px,1fr))] gap-1',
245
+ 'md:pointer-fine:grid-cols-[repeat(auto-fill,minmax(36px,1fr))] md:pointer-fine:gap-0.5',
246
+ ].join(' '),
247
+ }
248
+
249
+ export const ICON_CELL = [
250
+ 'inline-flex aspect-square w-full min-w-0 cursor-pointer items-center justify-center rounded-md text-(--pick-fg)',
251
+ 'transition-colors hover:bg-accent motion-reduce:transition-none [&>svg]:size-5',
252
+ 'aria-pressed:bg-(--pick-bg) aria-pressed:ring-2 aria-pressed:ring-(--pick-fg) aria-pressed:ring-inset',
253
+ CELL_FOCUS,
254
+ ].join(' ')
255
+
256
+ export const ICON_GRID_PAD: Record<PickerLayout, string> = {
257
+ popover: 'pb-3',
258
+ sheet: 'pb-4',
259
+ inline: '',
260
+ }
261
+
262
+ export const EMPTY = 'flex flex-col items-center gap-2 px-4 py-8 text-center text-sm text-muted-foreground'
263
+
264
+ export const LINK_BUTTON = [
265
+ 'cursor-pointer rounded-sm text-sm font-medium text-foreground underline underline-offset-4',
266
+ 'outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50',
267
+ ].join(' ')
@@ -0,0 +1,21 @@
1
+ import type { FC } from 'react'
2
+ import { cn } from '../../@/lib/utils.js'
3
+ import { pickerColorHelper } from '../../picker/vocabulary.js'
4
+ import type { ColorDotProps } from './types.js'
5
+ import { DOT, DOT_SIZE, PICK_SCOPE } from './consts.local.js'
6
+
7
+ /**
8
+ * A stored colour as a dot, in the colour's ink — the ink keeps 3:1 on the page in both schemes,
9
+ * which a dot (a graphic) needs; the brighter swatch does not. Unknown → slate.
10
+ */
11
+ export const ColorDot: FC<ColorDotProps> = ({ color, colors, size = 'sm', label, className }) =>
12
+ <span
13
+ data-color-dot
14
+ data-color={pickerColorHelper.resolve(color, colors)?.key}
15
+ role={label != null ? 'img' : undefined}
16
+ aria-label={label}
17
+ aria-hidden={label != null ? undefined : true}
18
+ title={label}
19
+ style={pickerColorHelper.styleOf(color, colors)}
20
+ className={cn(PICK_SCOPE, DOT, DOT_SIZE[size], className)}
21
+ />
@@ -0,0 +1,138 @@
1
+ import { useMemo, useRef, useState } from 'react'
2
+ import type { FC, KeyboardEvent } from 'react'
3
+ import { SearchIcon, SearchXIcon } from 'lucide-react'
4
+ import { cn } from '../../@/lib/utils.js'
5
+ import { pickerIconHelper } from '../../picker/icons.js'
6
+ import { pickerColorHelper } from '../../picker/vocabulary.js'
7
+ import { PICKER_COLORS, PICKER_ICON_CATEGORIES } from '../../picker/vocabulary/consts.js'
8
+ import type { PickerIconCategory } from '../../picker/vocabulary/types.js'
9
+ import type { IconGridProps } from './types.js'
10
+ import type { IconBrowserProps } from './types.local.js'
11
+ import { useRovingGrid } from './roving.js'
12
+ import { makePickerText } from './text.js'
13
+ import {
14
+ CHIP, CHIPS, EMPTY, FIELD, ICON_CELL, ICON_TOOLS, ICONS, LINK_BUTTON, PICK_SCOPE, SEARCH, SEARCH_ICON, SEARCH_WRAP,
15
+ } from './consts.local.js'
16
+
17
+ /**
18
+ * The searchable icon grid every picker shares: a search field, category chips and the icons,
19
+ * tinted in the chosen colour. The search field and the chips stay put while the grid scrolls;
20
+ * ArrowDown (or Enter) moves from the field into the grid, ArrowUp from the grid's first row back.
21
+ * An empty result says so and offers to clear; the result count is announced politely.
22
+ */
23
+ export const IconBrowser: FC<IconBrowserProps> = (
24
+ { value, onChange, color, colors, icons, text, layout, label, searchRef, className }
25
+ ) => {
26
+ const [query, setQuery] = useState('')
27
+ const [category, setCategory] = useState<PickerIconCategory | null>(null)
28
+ const search = useRef<HTMLInputElement | null>(null)
29
+
30
+ const categories = useMemo(() => {
31
+ const scope = pickerIconHelper.search('', icons)
32
+
33
+ return PICKER_ICON_CATEGORIES.filter(candidate => scope.some(entry => entry.category === candidate))
34
+ }, [icons])
35
+ const results = useMemo(
36
+ () => pickerIconHelper.search(query, icons).filter(entry => category == null || entry.category === category),
37
+ [query, icons, category]
38
+ )
39
+
40
+ const grid = useRovingGrid({
41
+ count: results.length,
42
+ selected: results.findIndex(entry => entry.name === value),
43
+ onExitUp: () => search.current?.focus(),
44
+ })
45
+ const chips = useRovingGrid({
46
+ count: categories.length + 1,
47
+ selected: category == null ? 0 : categories.indexOf(category) + 1,
48
+ grid: false,
49
+ })
50
+
51
+ const bindSearch = (node: HTMLInputElement | null): void => {
52
+ search.current = node
53
+ if (typeof searchRef === 'function') {
54
+ searchRef(node)
55
+ } else if (searchRef != null) {
56
+ searchRef.current = node
57
+ }
58
+ }
59
+
60
+ const onSearchKey = (event: KeyboardEvent<HTMLInputElement>): void => {
61
+ if (event.key === 'ArrowDown' || event.key === 'Enter') {
62
+ // Enter must never submit the form the grid sits in.
63
+ event.preventDefault()
64
+ grid.focusCurrent()
65
+ }
66
+ }
67
+
68
+ const filtered = query.trim() !== '' || category != null
69
+
70
+ return <div
71
+ data-picker-icons style={pickerColorHelper.styleOf(color, colors)} className={cn(PICK_SCOPE, className)}
72
+ >
73
+ <div className={ICON_TOOLS[layout]}>
74
+ <div className={SEARCH_WRAP}>
75
+ <SearchIcon aria-hidden="true" className={SEARCH_ICON} />
76
+ <input
77
+ ref={bindSearch} type="search" data-picker-search autoComplete="off" spellCheck={false} enterKeyHint="search"
78
+ aria-label={text.text('search', 'Search icons')} placeholder={text.text('searchPlaceholder', 'Search icons…')}
79
+ value={query} onChange={event => setQuery(event.target.value)} onKeyDown={onSearchKey}
80
+ className={cn(FIELD, SEARCH)}
81
+ />
82
+ </div>
83
+ {categories.length > 1 && <div
84
+ ref={chips.ref} role="group" aria-label={text.text('categoriesLabel', 'Categories')} onKeyDown={chips.onKeyDown}
85
+ className={CHIPS[layout]}
86
+ >
87
+ {[null, ...categories].map((candidate, index) => {
88
+ const name = candidate == null ? text.text('all', 'All') : text.category(candidate)
89
+
90
+ return <button
91
+ key={candidate ?? 'all'} type="button" data-roving-item data-picker-category={candidate ?? 'all'}
92
+ aria-label={name} aria-pressed={category === candidate} tabIndex={chips.tabIndexOf(index)}
93
+ onFocus={() => chips.setCurrent(index)} onClick={() => setCategory(candidate)} className={CHIP}
94
+ >{name}</button>
95
+ })}
96
+ </div>}
97
+ </div>
98
+ <p className="sr-only" aria-live="polite">{filtered ? text.count(results.length) : ''}</p>
99
+ {results.length > 0
100
+ ? <div ref={grid.ref} role="group" aria-label={label} onKeyDown={grid.onKeyDown} className={ICONS[layout]}>
101
+ {results.map((entry, index) => {
102
+ const Icon = pickerIconHelper.iconOf(entry.name)
103
+ const name = text.icon(entry.name)
104
+
105
+ return <button
106
+ key={entry.name} type="button" data-roving-item data-picker-icon={entry.name}
107
+ aria-label={name} aria-pressed={entry.name === value} title={name}
108
+ tabIndex={grid.tabIndexOf(index)} onFocus={() => grid.setCurrent(index)}
109
+ onClick={() => onChange(entry.name)} className={ICON_CELL}
110
+ ><Icon aria-hidden="true" /></button>
111
+ })}
112
+ </div>
113
+ : <div data-picker-empty className={EMPTY}>
114
+ <SearchXIcon aria-hidden="true" className="size-6" />
115
+ <p>{text.empty(query.trim())}</p>
116
+ <button
117
+ type="button" aria-label={text.text('clear', 'Clear search')} className={LINK_BUTTON}
118
+ onClick={() => { setQuery(''); setCategory(null); search.current?.focus() }}
119
+ >{text.text('clear', 'Clear search')}</button>
120
+ </div>}
121
+ </div>
122
+ }
123
+
124
+ /**
125
+ * The searchable icon grid inline — for a dialog or sheet the application already owns. Commits
126
+ * on click; `color` tints it, `icons` narrows (and orders) the catalogue. Strings through
127
+ * `translate` (English without it — never an implicit i18n read).
128
+ */
129
+ export const IconGrid: FC<IconGridProps> = (
130
+ { value, onChange, color, colors = PICKER_COLORS, icons, translate, label, className }
131
+ ) => {
132
+ const text = useMemo(() => makePickerText(translate), [translate])
133
+
134
+ return <IconBrowser
135
+ value={value} onChange={onChange} color={color} colors={colors} icons={icons} text={text} layout="inline"
136
+ label={label ?? text.text('icon', 'Icon')} className={className}
137
+ />
138
+ }
@@ -0,0 +1,60 @@
1
+ {
2
+ "label": "Значок і колер",
3
+ "icon": "Значок",
4
+ "color": "Колер",
5
+ "placeholder": {
6
+ "both": "Выберыце значок і колер",
7
+ "icon": "Выберыце значок",
8
+ "color": "Выберыце колер"
9
+ },
10
+ "nothing": "Нічога не выбрана",
11
+ "done": "Гатова",
12
+ "search": "Пошук значкоў",
13
+ "searchPlaceholder": "Пошук значкоў…",
14
+ "categoriesLabel": "Катэгорыі",
15
+ "all": "Усе",
16
+ "results": "Знойдзена значкоў: {count}",
17
+ "empty": "Няма значкоў па запыце «{query}»",
18
+ "clear": "Ачысціць пошук",
19
+ "custom": "Свой колер",
20
+ "hex": "Колер у фармаце HEX",
21
+ "invalidHex": "Увядзіце колер, напрыклад #3b82f6",
22
+ "colors": {
23
+ "red": "Чырвоны",
24
+ "orange": "Аранжавы",
25
+ "amber": "Бурштынавы",
26
+ "yellow": "Жоўты",
27
+ "lime": "Лаймавы",
28
+ "green": "Зялёны",
29
+ "emerald": "Смарагдавы",
30
+ "teal": "Бірузовы",
31
+ "cyan": "Цыян",
32
+ "sky": "Нябесны",
33
+ "blue": "Сіні",
34
+ "indigo": "Індыга",
35
+ "violet": "Фіялетавы",
36
+ "purple": "Пурпурны",
37
+ "fuchsia": "Фуксія",
38
+ "pink": "Ружовы",
39
+ "rose": "Малінавы",
40
+ "maroon": "Бардовы",
41
+ "brown": "Карычневы",
42
+ "olive": "Аліўкавы",
43
+ "navy": "Цёмна-сіні",
44
+ "slate": "Сланцавы",
45
+ "stone": "Каменны",
46
+ "graphite": "Графітавы"
47
+ },
48
+ "categories": {
49
+ "work": "Праца",
50
+ "people": "Людзі",
51
+ "communication": "Зносіны",
52
+ "commerce": "Гандаль",
53
+ "operations": "Аперацыі",
54
+ "places": "Месцы",
55
+ "tech": "Тэхналогіі",
56
+ "status": "Статусы",
57
+ "objects": "Прадметы",
58
+ "nature": "Прырода"
59
+ }
60
+ }