@surrealdb/ui 1.2.0 → 1.2.2

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 (281) hide show
  1. package/AGENTS.md +0 -1
  2. package/README.md +6 -2
  3. package/dist/assets/00a10f6ed8d28851.webp +0 -0
  4. package/dist/assets/0162c6a4ac2cfebd.webp +0 -0
  5. package/dist/assets/01b31b9257d57b8a.webp +0 -0
  6. package/dist/assets/02b4198388348511.webp +0 -0
  7. package/dist/assets/037a996120148e0b.webp +0 -0
  8. package/dist/assets/040a4fd015cdd0b7.webp +0 -0
  9. package/dist/assets/0526e0981d888126.webp +0 -0
  10. package/dist/assets/055abefe79b6e701.webp +0 -0
  11. package/dist/assets/0657d7ba8678dd5c.webp +0 -0
  12. package/dist/assets/0713360965c24418.webp +0 -0
  13. package/dist/assets/09af36dca92ae382.webp +0 -0
  14. package/dist/assets/09eec3632083144d.webp +0 -0
  15. package/dist/assets/0ae51c3e75175179.webp +0 -0
  16. package/dist/assets/0b1e649b60896d1b.webp +0 -0
  17. package/dist/assets/0cea48c7405074a6.webp +0 -0
  18. package/dist/assets/10fb18b7ef29f001.webp +0 -0
  19. package/dist/assets/1145150f6d6d554f.webp +0 -0
  20. package/dist/assets/11b1e7bf3bca451b.webp +0 -0
  21. package/dist/assets/13947bb6cca1c56e.webp +0 -0
  22. package/dist/assets/144f5da678a9258f.webp +0 -0
  23. package/dist/assets/16a3342882f33b40.webp +0 -0
  24. package/dist/assets/179f73130353ef01.webp +0 -0
  25. package/dist/assets/17fe34cc786799f8.webp +0 -0
  26. package/dist/assets/192ca51c99df0528.webp +0 -0
  27. package/dist/assets/194bc4e7d0be7145.webp +0 -0
  28. package/dist/assets/1a6f2cf9760fdd7e.webp +0 -0
  29. package/dist/assets/1b7a850bfb0af3e8.webp +0 -0
  30. package/dist/assets/1cc9e6767845e21c.webp +0 -0
  31. package/dist/assets/21731d9653706a78.webp +0 -0
  32. package/dist/assets/2207b2dc578622fe.webp +0 -0
  33. package/dist/assets/223bcefaa02568a8.webp +0 -0
  34. package/dist/assets/248ac00cd21f815a.webp +0 -0
  35. package/dist/assets/2647a47de41f9ae3.webp +0 -0
  36. package/dist/assets/2691af8ce9e9d5ce.webp +0 -0
  37. package/dist/assets/26abe1725525984a.webp +0 -0
  38. package/dist/assets/27ffc0d44a1f3be1.webp +0 -0
  39. package/dist/assets/2946d1ee47ed665d.webp +0 -0
  40. package/dist/assets/29a4e5dae52e11ff.webp +0 -0
  41. package/dist/assets/2b1d5bae1a5eae30.webp +0 -0
  42. package/dist/assets/2c6d5014b905a65c.webp +0 -0
  43. package/dist/assets/2cc4f4980c1bb29f.webp +0 -0
  44. package/dist/assets/2d30b090e914771f.webp +0 -0
  45. package/dist/assets/2ee142cc7ddc781f.webp +0 -0
  46. package/dist/assets/2f7c6d1c5fb82e2c.webp +0 -0
  47. package/dist/assets/2fedfaedf3e5eb80.webp +0 -0
  48. package/dist/assets/2ff21e9a34d3241f.webp +0 -0
  49. package/dist/assets/30dd1d8558ecbbb8.webp +0 -0
  50. package/dist/assets/346850e9684e7d97.webp +0 -0
  51. package/dist/assets/34effaa38093f34e.webp +0 -0
  52. package/dist/assets/350cd57f2d5cbeae.webp +0 -0
  53. package/dist/assets/351a1aef50fa5125.webp +0 -0
  54. package/dist/assets/372eea715c737270.webp +0 -0
  55. package/dist/assets/38e6703a7ee5ff1b.webp +0 -0
  56. package/dist/assets/39ae0cc748731119.webp +0 -0
  57. package/dist/assets/3a62798e03acaab1.webp +0 -0
  58. package/dist/assets/3bb0b598bc35e4b2.webp +0 -0
  59. package/dist/assets/3cbc127cdc2058e2.webp +0 -0
  60. package/dist/assets/3ccd7e9a3e883ef4.webp +0 -0
  61. package/dist/assets/3cf8e43990d9d89d.webp +0 -0
  62. package/dist/assets/3e632c9bb973b708.webp +0 -0
  63. package/dist/assets/3ee2d99ac860a623.webp +0 -0
  64. package/dist/assets/3fbcf5362280f81f.webp +0 -0
  65. package/dist/assets/3fe501a7865c16ae.webp +0 -0
  66. package/dist/assets/414e2d8a56ce7910.webp +0 -0
  67. package/dist/assets/41b23bd70281a865.webp +0 -0
  68. package/dist/assets/455b9eb8a609a708.webp +0 -0
  69. package/dist/assets/45e2ed33c14f0b04.webp +0 -0
  70. package/dist/assets/45f0191b96b665f1.webp +0 -0
  71. package/dist/assets/4825fc2b412e6c49.webp +0 -0
  72. package/dist/assets/484e9cdb969f15b9.webp +0 -0
  73. package/dist/assets/48b89b593ddf3859.webp +0 -0
  74. package/dist/assets/49886a9c10c84219.webp +0 -0
  75. package/dist/assets/4c5804e0445a2364.webp +0 -0
  76. package/dist/assets/4c606cb3cb92175b.webp +0 -0
  77. package/dist/assets/4c7c1c273025dcf1.webp +0 -0
  78. package/dist/assets/4d1e067d250e3da7.webp +0 -0
  79. package/dist/assets/4f8d51ffc6798a3f.webp +0 -0
  80. package/dist/assets/4feef73a1f59ead0.webp +0 -0
  81. package/dist/assets/503e2f91f525ced6.webp +0 -0
  82. package/dist/assets/507d9b965db335dc.webp +0 -0
  83. package/dist/assets/50ee2b8f746929fd.webp +0 -0
  84. package/dist/assets/5162561b1cf1157d.webp +0 -0
  85. package/dist/assets/519b2797ad349ab2.webp +0 -0
  86. package/dist/assets/52a04db8f3ef729a.webp +0 -0
  87. package/dist/assets/5410644476584555.webp +0 -0
  88. package/dist/assets/552e3b3c7a8b219f.webp +0 -0
  89. package/dist/assets/5680f57bba683ea8.webp +0 -0
  90. package/dist/assets/56e2c0df0df84d85.webp +0 -0
  91. package/dist/assets/57413876fab23bf4.webp +0 -0
  92. package/dist/assets/57735748702cef60.webp +0 -0
  93. package/dist/assets/579ffd3b6352fde8.webp +0 -0
  94. package/dist/assets/580af10c3a0d6214.webp +0 -0
  95. package/dist/assets/592d63e445941a48.webp +0 -0
  96. package/dist/assets/5969a507868247dc.webp +0 -0
  97. package/dist/assets/5ad66afddb5112e8.webp +0 -0
  98. package/dist/assets/5d6c6d3209e05455.webp +0 -0
  99. package/dist/assets/5e4ed61f6e3ddf63.webp +0 -0
  100. package/dist/assets/5f425d79f49de428.webp +0 -0
  101. package/dist/assets/60375484135ea20c.webp +0 -0
  102. package/dist/assets/60960b537570554b.webp +0 -0
  103. package/dist/assets/60a1723d1f64a67b.webp +0 -0
  104. package/dist/assets/60c240a2b0c62ff7.webp +0 -0
  105. package/dist/assets/60d0a8d0bfcf6aaa.webp +0 -0
  106. package/dist/assets/6191cf7b0ba752b1.webp +0 -0
  107. package/dist/assets/6230c2d26c7fb874.webp +0 -0
  108. package/dist/assets/6474ae0b83dd1961.webp +0 -0
  109. package/dist/assets/652b609078ac988f.webp +0 -0
  110. package/dist/assets/66326fee66039124.webp +0 -0
  111. package/dist/assets/679c6102b205fef3.webp +0 -0
  112. package/dist/assets/67e727126d43f52d.webp +0 -0
  113. package/dist/assets/68f95a529308ffd0.webp +0 -0
  114. package/dist/assets/6a49b166e27942d6.webp +0 -0
  115. package/dist/assets/6b612396a876a6cb.webp +0 -0
  116. package/dist/assets/6b741e24b789b759.webp +0 -0
  117. package/dist/assets/6bd1b97cabb7013b.webp +0 -0
  118. package/dist/assets/6c23b306b3b98347.webp +0 -0
  119. package/dist/assets/6c647c1f3bd39d04.webp +0 -0
  120. package/dist/assets/6d2ffcd3c87bf0b8.webp +0 -0
  121. package/dist/assets/6da50ab548c1f881.webp +0 -0
  122. package/dist/assets/7202c68df46af42f.webp +0 -0
  123. package/dist/assets/733327e345884210.webp +0 -0
  124. package/dist/assets/753795af2c5d7be2.webp +0 -0
  125. package/dist/assets/75641da57bc6dffd.webp +0 -0
  126. package/dist/assets/76f4466c03adcd1d.webp +0 -0
  127. package/dist/assets/795ed707186e4998.webp +0 -0
  128. package/dist/assets/7a3c2063a78a7671.webp +0 -0
  129. package/dist/assets/7a40e614f1abab41.webp +0 -0
  130. package/dist/assets/7a51bae6c8c0b8d6.webp +0 -0
  131. package/dist/assets/7ac03abe57635a22.webp +0 -0
  132. package/dist/assets/7afbeb4d3723bea9.webp +0 -0
  133. package/dist/assets/7b908fe597c371fe.webp +0 -0
  134. package/dist/assets/7c593a2cee07323d.webp +0 -0
  135. package/dist/assets/7ef46b1ee3c0fcc3.webp +0 -0
  136. package/dist/assets/7f19155287c0e9e2.webp +0 -0
  137. package/dist/assets/7f4980ef8d2e758e.webp +0 -0
  138. package/dist/assets/7fb40397fbf0a44f.webp +0 -0
  139. package/dist/assets/830cf1f097720215.webp +0 -0
  140. package/dist/assets/8409441a26339658.webp +0 -0
  141. package/dist/assets/8557a1175cf5b927.webp +0 -0
  142. package/dist/assets/85cbb57cabec9be3.webp +0 -0
  143. package/dist/assets/8890f1eb46c62eed.webp +0 -0
  144. package/dist/assets/8892b010e8f9c0fd.webp +0 -0
  145. package/dist/assets/897cb1960e8c41df.webp +0 -0
  146. package/dist/assets/8d382694be4b565a.webp +0 -0
  147. package/dist/assets/8eb74a3ae87778e5.webp +0 -0
  148. package/dist/assets/8f5d77f12b63e5fa.webp +0 -0
  149. package/dist/assets/8f82effc460e2e89.webp +0 -0
  150. package/dist/assets/91261685c5adbd6d.webp +0 -0
  151. package/dist/assets/9274d3588526a567.webp +0 -0
  152. package/dist/assets/935d6e6f2791ed73.webp +0 -0
  153. package/dist/assets/9426b76449fbf64b.webp +0 -0
  154. package/dist/assets/945c99dfa636ba36.webp +0 -0
  155. package/dist/assets/94a9a29ed66a4ef3.webp +0 -0
  156. package/dist/assets/94bd2f81b090a7e6.webp +0 -0
  157. package/dist/assets/951f2418a7fd0373.webp +0 -0
  158. package/dist/assets/9535295d6b09150d.webp +0 -0
  159. package/dist/assets/98629dd48fcea10b.webp +0 -0
  160. package/dist/assets/9a30f66d8a1e2b35.webp +0 -0
  161. package/dist/assets/9ad5c4db3af637fc.webp +0 -0
  162. package/dist/assets/9b88c1b8bd9e4274.webp +0 -0
  163. package/dist/assets/9e197be821d63126.webp +0 -0
  164. package/dist/assets/a0e567aeb88fd53f.webp +0 -0
  165. package/dist/assets/a108749cd7563ef6.webp +0 -0
  166. package/dist/assets/a1ae90b5309a83fb.webp +0 -0
  167. package/dist/assets/a22c2665236646b0.webp +0 -0
  168. package/dist/assets/a4675345ec0358f4.webp +0 -0
  169. package/dist/assets/a8de10da5e512d7b.webp +0 -0
  170. package/dist/assets/ad2af0582c0504ff.webp +0 -0
  171. package/dist/assets/adae3bc5bd13817b.webp +0 -0
  172. package/dist/assets/adb3fc29e677770e.webp +0 -0
  173. package/dist/assets/ae659f60557350c4.webp +0 -0
  174. package/dist/assets/aeaee0e289e2608e.webp +0 -0
  175. package/dist/assets/af24ba34b62492ac.webp +0 -0
  176. package/dist/assets/af7d97ae2466bbde.webp +0 -0
  177. package/dist/assets/afa9b3ef89679937.webp +0 -0
  178. package/dist/assets/b04753e5b98becb7.webp +0 -0
  179. package/dist/assets/b152b0331ec03bed.webp +0 -0
  180. package/dist/assets/b1d6aaff88edff14.webp +0 -0
  181. package/dist/assets/b25512027421d389.webp +0 -0
  182. package/dist/assets/b26cf4cd8b1f1131.webp +0 -0
  183. package/dist/assets/b28495c59529ee50.webp +0 -0
  184. package/dist/assets/b2bd7fdf877521bf.webp +0 -0
  185. package/dist/assets/b313afd86b997619.webp +0 -0
  186. package/dist/assets/b51cef69ba1cf9b8.webp +0 -0
  187. package/dist/assets/b5a9549e2fb98801.webp +0 -0
  188. package/dist/assets/b65447326dfe1209.webp +0 -0
  189. package/dist/assets/b89b3c6895142147.webp +0 -0
  190. package/dist/assets/b8dacfca93cafccb.webp +0 -0
  191. package/dist/assets/b92e9d16ff92dfd0.webp +0 -0
  192. package/dist/assets/b9ef318f0d0a84be.webp +0 -0
  193. package/dist/assets/baf060dfd0fa929b.webp +0 -0
  194. package/dist/assets/bb591e63dc4cdfac.webp +0 -0
  195. package/dist/assets/bb5f0dfecd337e4d.webp +0 -0
  196. package/dist/assets/bb62a4f6efde2638.webp +0 -0
  197. package/dist/assets/bb84aa5403a64e37.webp +0 -0
  198. package/dist/assets/bc4b209868329b4b.webp +0 -0
  199. package/dist/assets/bcdf4135fd2e23fd.webp +0 -0
  200. package/dist/assets/bd59c0661af8eed5.webp +0 -0
  201. package/dist/assets/be88a0e1bc590985.webp +0 -0
  202. package/dist/assets/bf0aad9f56d3e724.webp +0 -0
  203. package/dist/assets/bf75b4c2378e1dcd.webp +0 -0
  204. package/dist/assets/bf7727087dd96a85.webp +0 -0
  205. package/dist/assets/c23958fa928fdd6f.webp +0 -0
  206. package/dist/assets/c394cc8e4c60b800.webp +0 -0
  207. package/dist/assets/c4d4480844dafd93.webp +0 -0
  208. package/dist/assets/c7bfe6e7916af17a.webp +0 -0
  209. package/dist/assets/c88726dc18200a93.webp +0 -0
  210. package/dist/assets/c8e6f5c66cc27154.webp +0 -0
  211. package/dist/assets/caac7e0b2dd67187.webp +0 -0
  212. package/dist/assets/cc25fb057b110741.webp +0 -0
  213. package/dist/assets/ccbfbbafdcdcdcd4.webp +0 -0
  214. package/dist/assets/cd8af3b4f2b247f7.webp +0 -0
  215. package/dist/assets/ce57872c785aab9a.webp +0 -0
  216. package/dist/assets/ce58827f91b5b064.webp +0 -0
  217. package/dist/assets/cef226c91ccf363f.webp +0 -0
  218. package/dist/assets/d0044e1f2ce81b98.webp +0 -0
  219. package/dist/assets/d1ea2c3693d297c3.webp +0 -0
  220. package/dist/assets/d32f16404a97b1a1.webp +0 -0
  221. package/dist/assets/d52a5c0c51ac24a0.webp +0 -0
  222. package/dist/assets/d53f79b5d6ed25fe.webp +0 -0
  223. package/dist/assets/d60293fd2b968089.webp +0 -0
  224. package/dist/assets/d80fdc2650006dbc.webp +0 -0
  225. package/dist/assets/d860abdf21a1c9ba.webp +0 -0
  226. package/dist/assets/d8785da6d6a685dd.webp +0 -0
  227. package/dist/assets/d976877ebafa14da.webp +0 -0
  228. package/dist/assets/d9c5c1149db28ee9.webp +0 -0
  229. package/dist/assets/daeb1a7a520d97a0.webp +0 -0
  230. package/dist/assets/daf48a380db80725.webp +0 -0
  231. package/dist/assets/db8bfbeacef7cbc2.webp +0 -0
  232. package/dist/assets/dba267eb32acfc39.webp +0 -0
  233. package/dist/assets/dd86e2c5ced02541.webp +0 -0
  234. package/dist/assets/de3566780bd27a7a.webp +0 -0
  235. package/dist/assets/dee70270aacf3392.webp +0 -0
  236. package/dist/assets/df149fcc6bd3a0ac.webp +0 -0
  237. package/dist/assets/e02ec069ba946251.webp +0 -0
  238. package/dist/assets/e0a1bf1c59da7c51.webp +0 -0
  239. package/dist/assets/e15f73e4ae9823dd.webp +0 -0
  240. package/dist/assets/e2db5b0ed114d896.webp +0 -0
  241. package/dist/assets/e2e1feca1ca57e12.webp +0 -0
  242. package/dist/assets/e4cb11de7eb3f570.webp +0 -0
  243. package/dist/assets/e6e87e848d6d2a39.webp +0 -0
  244. package/dist/assets/e7c97214b0474c1a.webp +0 -0
  245. package/dist/assets/e83d0fd79ff85eaf.webp +0 -0
  246. package/dist/assets/e9676ab694038ec3.webp +0 -0
  247. package/dist/assets/ebd8a6199269a631.webp +0 -0
  248. package/dist/assets/edfea424dbb50652.webp +0 -0
  249. package/dist/assets/ef483b5744eb9c65.webp +0 -0
  250. package/dist/assets/f00a2ea2bda7c369.webp +0 -0
  251. package/dist/assets/f1328cc022093bbe.webp +0 -0
  252. package/dist/assets/f1985934f1360625.webp +0 -0
  253. package/dist/assets/f350494720282719.webp +0 -0
  254. package/dist/assets/f37dbfada942efa3.webp +0 -0
  255. package/dist/assets/f38baf6e465972ab.webp +0 -0
  256. package/dist/assets/f4cdacbb564448e4.webp +0 -0
  257. package/dist/assets/f5c3f05f6419fe35.webp +0 -0
  258. package/dist/assets/fa083d1a279355f9.webp +0 -0
  259. package/dist/assets/fa3a0b2d9a4bf2b0.webp +0 -0
  260. package/dist/assets/fa429269928a42f7.webp +0 -0
  261. package/dist/assets/fa714ddbf26326ed.webp +0 -0
  262. package/dist/assets/fb49f0faca9f841a.webp +0 -0
  263. package/dist/assets/fc9b571fa724a2b0.webp +0 -0
  264. package/dist/assets/fcca811aec8a2021.webp +0 -0
  265. package/dist/assets/ff509bd19b57cd11.webp +0 -0
  266. package/dist/assets/ffeb52404b9f7364.webp +0 -0
  267. package/dist/fonts.d.ts +8 -8
  268. package/dist/icons.d.ts +8 -8
  269. package/dist/ui.css +1 -1
  270. package/dist/ui.d.ts +538 -9
  271. package/dist/ui.js +3361 -2817
  272. package/dist/ui.js.map +1 -1
  273. package/package.json +1 -1
  274. package/res/_mixins.scss +13 -6
  275. package/tools/duplicate-vector-mappings.json +64 -0
  276. package/tools/integration-gradient-exports.json +44 -0
  277. package/tools/picto-compare.ts +64 -0
  278. package/tools/picto-merge-urls.ts +43 -0
  279. package/tools/picto-sync.ts +629 -0
  280. package/tools/picto-verify-gradients.ts +86 -0
  281. package/tools/vector-export-nodes.json +977 -0
@@ -0,0 +1,629 @@
1
+ /**
2
+ * Parses Figma metadata XML, maps picto names to ui-kit conventions,
3
+ * and prepares gradient asset exports.
4
+ *
5
+ * Usage:
6
+ * bun tools/picto-sync.ts parse <metadata.xml> # build mapping JSON
7
+ * bun tools/picto-sync.ts optimize <png-dir> # convert PNGs to WebP
8
+ * bun tools/picto-sync.ts generate-imports <mapping.json> # update pictos.ts entries
9
+ *
10
+ * See also: bun tools/picto-verify-gradients.ts — compare glass vs gradient silhouettes
11
+ */
12
+
13
+ import { execSync } from "node:child_process";
14
+ import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
15
+ import { basename, join } from "node:path";
16
+
17
+ const PICTOS_DIR = join(import.meta.dir, "../src/assets/pictos");
18
+ const MAPPING_PATH = join(import.meta.dir, "../src/constants/picto-figma-map.json");
19
+ const EXPORT_NODES_PATH = join(import.meta.dir, "vector-export-nodes.json");
20
+ const INTEGRATION_EXPORTS_PATH = join(import.meta.dir, "integration-gradient-exports.json");
21
+ const DUPLICATE_VECTOR_MAPPINGS_PATH = join(import.meta.dir, "duplicate-vector-mappings.json");
22
+ const PNG_DIR = join(import.meta.dir, "../.picto-gradient-png");
23
+
24
+ type VectorExportNode = {
25
+ symbolId: string;
26
+ exportNodeId: string;
27
+ exportNodeName: string;
28
+ exportNodeType?: string;
29
+ };
30
+
31
+ type PictoMapping = {
32
+ figmaFrameName: string;
33
+ figmaLightName: string;
34
+ figmaVectorName: string;
35
+ figmaLightNodeId: string;
36
+ figmaVectorNodeId: string;
37
+ figmaVectorExportNodeId: string;
38
+ uiKitFileName: string;
39
+ uiKitExportName: string;
40
+ uiKitGradientFileName: string;
41
+ uiKitGradientExportName: string;
42
+ matchMethod: "exact" | "normalized" | "manual" | "image";
43
+ };
44
+
45
+ /** Manual overrides where Figma names diverge significantly from ui-kit filenames. */
46
+ const MANUAL_FRAME_TO_FILE: Record<string, string> = {
47
+ "Pension Dollar": "Pension",
48
+ "Speed / Performance": "Performance",
49
+ "Code blob (JSON)": "JSON",
50
+ "Full-Text Search": "Full-TextSearch",
51
+ "Real time applications": "RealTimeApplications",
52
+ "Knowledge graph": "KnowledgeGraph",
53
+ "Instance version": "InstanceVersion",
54
+ "Fraud detection": "FraudDetection",
55
+ "Embedded edge": "EmbeddedEdge",
56
+ "Embedded devices": "EmbeddedDevices",
57
+ "Machine Learning Brain": "MachineLearning",
58
+ Flexible_time: "Flexible",
59
+ Learn: "Tutorials",
60
+ "Tiny asset / thumbnail": "Thumbnail",
61
+ "Inclusive communication": "InclusiveCommunication",
62
+ "regulatory compliance": "RegulatoryCompliance",
63
+ "Conflict detection": "ConflictDetection",
64
+ "Health Chat": "HealthChat",
65
+ "Video file": "VideoFile",
66
+ "Padlock Closed": "PadlockClosed",
67
+ "Padlock Open": "PadlockOpen",
68
+ "Two Circles": "TwoCircles",
69
+ "Pie Chart": "PieChart",
70
+ "Arrow Up": "ArrowUp",
71
+ "Arrow Down": "ArrowDown",
72
+ "Play Pause": "PlayPause",
73
+ "Price Tag": "PriceTag",
74
+ "Key Value": "KeyValue",
75
+ "Finger Prints": "FingerPrints",
76
+ "Hands On": "HandsOn",
77
+ "Claims Management": "ClaimsManagement",
78
+ "Mental Health": "MentalHealth",
79
+ "Generative AI": "GenerativeAI",
80
+ "Vector Search": "VectorSearch",
81
+ "Document Search": "DocumentSearch",
82
+ "Reference guides": "Reference-guides",
83
+ "5 Stars": "5Stars",
84
+ "10": "2106",
85
+ "2112": "2106",
86
+ "360 Degree View": "360DegreeView",
87
+ "Save Floppy Disc": "SaveFloppyDisc",
88
+ "Hard Disc": "HardDisc",
89
+ "Storage / Hard Disc": "HardDisc",
90
+ "On-disk": "OnDisk",
91
+ "Labs / Atom": "Atom",
92
+ "Image (photo)": "Image",
93
+ "Stack Overflow": "StackOverflow",
94
+ YouTube: "Youtube",
95
+ WebAssembly: "Wasm",
96
+ n8n: "N8n",
97
+ "Man In Circle": "ManInCircle",
98
+ "Health Bubble": "HealthBubble",
99
+ "Health Insurance": "HealthInsurance",
100
+ "Home Setup": "HomeSetup",
101
+ "Cloud Nodes": "CloudNodes",
102
+ "Merge Queue": "MergeQueue",
103
+ "Commit Queue": "CommitQueue",
104
+ "Custom API Endpoints": "CustomAPIEndpoints",
105
+ "Portfolio Risk Management": "PortfolioRiskManagement",
106
+ "Personalized Policy": "PersonalizedPolicy",
107
+ "Problem Danger Error": "ProblemDangerError",
108
+ "Operational Readiness": "OperationalReadiness",
109
+ "Integration Support": "IntegrationSupport",
110
+ "Dedicated Support": "DedicatedSupport",
111
+ "Secure Document": "SecureDocument",
112
+ "Visual Studio Code": "VisualStudioCode",
113
+ "Node Brain": "NodeBrain",
114
+ "Drag Cursor": "DragCursor",
115
+ "Audio Clip": "AudioClip",
116
+ "Media File": "MediaFile",
117
+ "Create Plus": "Create",
118
+ "Document / PDF": "PDF",
119
+ "Document PDF": "PDF",
120
+ "Agent / Bot": "Bot",
121
+ "cloud nodes": "CloudNodes",
122
+ "Commit queue": "CommitQueue",
123
+ "Merge queue": "MergeQueue",
124
+ "JSON File": "JSONFile",
125
+ "Video File": "VideoFile",
126
+ "Time Series": "TimeSeries",
127
+ "SQL Backends": "SQLBackends",
128
+ "Full Text Search": "Full-TextSearch",
129
+ "Badge Access": "BadgeAccess",
130
+ "Quotation Marks": "QuotationMarks",
131
+ "Thumbs Up": "ThumbsUp",
132
+ "Thumbs Down": "ThumbsDown",
133
+ "Zoom In": "ZoomIn",
134
+ "SDB Cloud": "SDBCloud",
135
+ "YU App": "YUApp",
136
+ };
137
+
138
+ /** Storybook frame names that differ from the Figma Icons section frame name. */
139
+ const MANUAL_STORYBOOK_FRAME_TO_FIGMA_FRAME: Record<string, string> = {
140
+ "2112": "10",
141
+ };
142
+
143
+ /** Vector symbol names can be truncated or differ from frame names. */
144
+ const MANUAL_VECTOR_TO_FRAME: Record<string, string> = {
145
+ "Inclusive commu_vector": "Inclusive communication",
146
+ Flexible_vector: "Flexible",
147
+ "Code blob (JSON)_vector": "Code blob (JSON)",
148
+ "Speed / Performance_vector": "Speed / Performance",
149
+ "Pension Dollar_vector": "Pension Dollar",
150
+ "Real time applications_vector": "Real time applications",
151
+ "Knowledge graph_vector": "Knowledge graph",
152
+ "Instance version_vector": "Instance version",
153
+ "Fraud detection_vector": "Fraud detection",
154
+ "Embedded edge_vector": "Embedded edge",
155
+ "Embedded devices_vector": "Embedded devices",
156
+ "Machine Learning Brain_vector": "Machine Learning Brain",
157
+ Learn_vector: "Learn",
158
+ "Tiny asset / thumbnail_vector": "Tiny asset / thumbnail",
159
+ "regulatory compliance_vector": "regulatory compliance",
160
+ "Conflict detection_vector": "Conflict detection",
161
+ "Document Search_vector": "Document Search",
162
+ "Reference guides_vector": "Reference guides",
163
+ "Health Chat_vector": "Health Chat",
164
+ "Video file_vector": "Video file",
165
+ "Padlock Closed_vector": "Padlock Closed",
166
+ "Padlock Open_vector": "Padlock Open",
167
+ "Two Circles_vector": "Two Circles",
168
+ "Pie Chart_vector": "Pie Chart",
169
+ "Arrow Up_vector": "Arrow Up",
170
+ "Arrow Down_vector": "Arrow Down",
171
+ "Play Pause_vector": "Play Pause",
172
+ "Price Tag_vector": "Price Tag",
173
+ "Key Value_vector": "Key Value",
174
+ "Finger Prints_vector": "Finger Prints",
175
+ "Hands On_vector": "Hands On",
176
+ "Claims Management_vector": "Claims Management",
177
+ "Mental Health_vector": "Mental Health",
178
+ "Generative AI_vector": "Generative AI",
179
+ "Vector Search_vector": "Vector Search",
180
+ "5 Stars_vector": "5 Stars",
181
+ "Full-Text Search_vector": "Full-Text Search",
182
+ embedding_vector: "embeddingg",
183
+ "Storage / Hard Disc_vector": "Storage / Hard Disc",
184
+ "On-disk_vector": "On-disk",
185
+ "Labs / Atom_vector": "Labs / Atom",
186
+ "Image (photo)_vector": "Image (photo)",
187
+ "reference-guides_vector": "reference-guides",
188
+ "Group 14303_vector": "Begin",
189
+ };
190
+
191
+ /** ui-kit export names that diverge from fileNameToExportName(). */
192
+ const EXPORT_NAME_OVERRIDES: Record<string, string> = {
193
+ "Reference-guides": "pictoReferenceGuides",
194
+ };
195
+
196
+ function normalizeFrameName(name: string): string {
197
+ return name
198
+ .replace(/\s*\/\s*/g, " ")
199
+ .replace(/\s+/g, " ")
200
+ .trim();
201
+ }
202
+
203
+ function frameNameToFileName(frameName: string): string {
204
+ const manual = MANUAL_FRAME_TO_FILE[frameName];
205
+ if (manual) return manual;
206
+
207
+ // Preserve intentional hyphens (e.g. Full-Text Search)
208
+ if (frameName.includes("-")) {
209
+ return frameName
210
+ .split(" ")
211
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
212
+ .join("");
213
+ }
214
+
215
+ // Default: PascalCase without spaces
216
+ return frameName
217
+ .split(/[\s_]+/)
218
+ .filter(Boolean)
219
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
220
+ .join("");
221
+ }
222
+
223
+ function fileNameToExportName(fileName: string): string {
224
+ const override = EXPORT_NAME_OVERRIDES[fileName];
225
+ if (override) return override;
226
+
227
+ const base = fileName.replace(/[^a-zA-Z0-9]/g, "");
228
+ if (/^\d/.test(base)) return `picto${base}`;
229
+ return `picto${base.charAt(0).toUpperCase()}${base.slice(1)}`;
230
+ }
231
+
232
+ type IntegrationGradientExport = {
233
+ uiKitFileName: string;
234
+ exportNodeId: string;
235
+ figmaFrameName: string;
236
+ };
237
+
238
+ type DuplicateVectorMapping = {
239
+ uiKitFileName: string;
240
+ symbolId: string;
241
+ exportNodeId: string;
242
+ figmaVectorName: string;
243
+ figmaFrameName?: string;
244
+ figmaLightNodeId?: string;
245
+ };
246
+
247
+ async function loadIntegrationExports(): Promise<IntegrationGradientExport[]> {
248
+ try {
249
+ return JSON.parse(await readFile(INTEGRATION_EXPORTS_PATH, "utf8"));
250
+ } catch {
251
+ return [];
252
+ }
253
+ }
254
+
255
+ async function loadDuplicateVectorMappings(): Promise<DuplicateVectorMapping[]> {
256
+ try {
257
+ return JSON.parse(await readFile(DUPLICATE_VECTOR_MAPPINGS_PATH, "utf8"));
258
+ } catch {
259
+ return [];
260
+ }
261
+ }
262
+
263
+ function parseMetadata(xml: string) {
264
+ const storybookFrames = new Map<
265
+ string,
266
+ { frameId: string; lightName: string; lightNodeId: string }
267
+ >();
268
+ const vectorSymbols = new Map<string, { vectorName: string; vectorNodeId: string }>();
269
+
270
+ const frameRegex =
271
+ /<frame id="([^"]+)" name="([^"]+)"[^>]*>\s*<instance id="([^"]+)" name="([^"]+)_light"/g;
272
+ for (const match of xml.matchAll(frameRegex)) {
273
+ const [, , frameName, lightNodeId, lightBaseName] = match;
274
+ const normalized = normalizeFrameName(frameName);
275
+ if (!storybookFrames.has(normalized)) {
276
+ storybookFrames.set(normalized, {
277
+ frameId: match[1],
278
+ lightName: `${lightBaseName}_light`,
279
+ lightNodeId,
280
+ });
281
+ }
282
+ }
283
+
284
+ const symbolRegex = /<symbol id="([^"]+)" name="([^"]+_vector)"/g;
285
+ for (const match of xml.matchAll(symbolRegex)) {
286
+ const [, vectorNodeId, vectorName] = match;
287
+ if (!vectorSymbols.has(vectorName)) {
288
+ vectorSymbols.set(vectorName, { vectorName, vectorNodeId });
289
+ }
290
+ }
291
+
292
+ return { storybookFrames, vectorSymbols };
293
+ }
294
+
295
+ function vectorNameToFrameName(vectorName: string): string {
296
+ if (MANUAL_VECTOR_TO_FRAME[vectorName]) {
297
+ return MANUAL_VECTOR_TO_FRAME[vectorName];
298
+ }
299
+ return normalizeFrameName(vectorName.replace(/_vector$/, ""));
300
+ }
301
+
302
+ async function loadExportNodes(): Promise<Record<string, VectorExportNode>> {
303
+ try {
304
+ return JSON.parse(await readFile(EXPORT_NODES_PATH, "utf8"));
305
+ } catch {
306
+ return {};
307
+ }
308
+ }
309
+
310
+ async function buildMapping(xmlPath: string): Promise<PictoMapping[]> {
311
+ const xml = await readFile(xmlPath, "utf8");
312
+ const exportNodes = await loadExportNodes();
313
+ const repoFiles = new Set(
314
+ (await readdir(PICTOS_DIR))
315
+ .filter((f) => f.endsWith(".webp") && !f.endsWith("Gradient.webp"))
316
+ .map((f) => f.replace(/\.webp$/, "")),
317
+ );
318
+ const { storybookFrames, vectorSymbols } = parseMetadata(xml);
319
+
320
+ const vectorsByFrame = new Map<string, { vectorName: string; vectorNodeId: string }>();
321
+ for (const [, vector] of vectorSymbols) {
322
+ const frameName = vectorNameToFrameName(vector.vectorName);
323
+ if (!vectorsByFrame.has(frameName)) {
324
+ vectorsByFrame.set(frameName, vector);
325
+ }
326
+ }
327
+
328
+ const mappings: PictoMapping[] = [];
329
+
330
+ for (const [frameName, light] of storybookFrames) {
331
+ const figmaFrameName = MANUAL_STORYBOOK_FRAME_TO_FIGMA_FRAME[frameName] ?? frameName;
332
+ const vector = vectorsByFrame.get(figmaFrameName);
333
+ if (!vector) continue;
334
+
335
+ let uiKitFileName = frameNameToFileName(figmaFrameName);
336
+ let matchMethod: PictoMapping["matchMethod"] = "normalized";
337
+
338
+ if (MANUAL_FRAME_TO_FILE[figmaFrameName] || MANUAL_FRAME_TO_FILE[frameName]) {
339
+ matchMethod = "manual";
340
+ } else if (repoFiles.has(uiKitFileName)) {
341
+ matchMethod = "exact";
342
+ } else {
343
+ // Try case-insensitive match
344
+ const found = [...repoFiles].find(
345
+ (f) => f.toLowerCase() === uiKitFileName.toLowerCase(),
346
+ );
347
+ if (found) {
348
+ uiKitFileName = found;
349
+ matchMethod = "exact";
350
+ }
351
+ }
352
+
353
+ if (!repoFiles.has(uiKitFileName)) continue;
354
+
355
+ const exportNode = exportNodes[vector.vectorName];
356
+ mappings.push({
357
+ figmaFrameName: figmaFrameName,
358
+ figmaLightName: light.lightName,
359
+ figmaVectorName: vector.vectorName,
360
+ figmaLightNodeId: light.lightNodeId,
361
+ figmaVectorNodeId: vector.vectorNodeId,
362
+ figmaVectorExportNodeId: exportNode?.exportNodeId ?? vector.vectorNodeId,
363
+ uiKitFileName,
364
+ uiKitExportName: fileNameToExportName(uiKitFileName),
365
+ uiKitGradientFileName: `${uiKitFileName}Gradient`,
366
+ uiKitGradientExportName: `${fileNameToExportName(uiKitFileName)}Gradient`,
367
+ matchMethod,
368
+ });
369
+ }
370
+
371
+ // Include vectors that exist but weren't in storybook (from Icons section only)
372
+ for (const [vectorName, vector] of vectorSymbols) {
373
+ const frameName = vectorNameToFrameName(vectorName);
374
+ if (storybookFrames.has(frameName)) continue;
375
+
376
+ const uiKitFileName = frameNameToFileName(frameName);
377
+ if (!repoFiles.has(uiKitFileName)) continue;
378
+ if (mappings.some((m) => m.uiKitFileName === uiKitFileName)) continue;
379
+
380
+ const exportNode = exportNodes[vector.vectorName];
381
+ mappings.push({
382
+ figmaFrameName: frameName,
383
+ figmaLightName: `${frameName.replace(/\s+/g, " ")}_light`,
384
+ figmaVectorName: vector.vectorName,
385
+ figmaLightNodeId: "",
386
+ figmaVectorNodeId: vector.vectorNodeId,
387
+ figmaVectorExportNodeId: exportNode?.exportNodeId ?? vector.vectorNodeId,
388
+ uiKitFileName,
389
+ uiKitExportName: fileNameToExportName(uiKitFileName),
390
+ uiKitGradientFileName: `${uiKitFileName}Gradient`,
391
+ uiKitGradientExportName: `${fileNameToExportName(uiKitFileName)}Gradient`,
392
+ matchMethod: "manual",
393
+ });
394
+ }
395
+
396
+ const integrationExports = await loadIntegrationExports();
397
+ for (const entry of integrationExports) {
398
+ if (!repoFiles.has(entry.uiKitFileName)) continue;
399
+ if (mappings.some((m) => m.uiKitFileName === entry.uiKitFileName)) continue;
400
+
401
+ mappings.push({
402
+ figmaFrameName: entry.figmaFrameName,
403
+ figmaLightName: `${entry.figmaFrameName}_light`,
404
+ figmaVectorName: `${entry.figmaFrameName}_gradient`,
405
+ figmaLightNodeId: "",
406
+ figmaVectorNodeId: entry.exportNodeId,
407
+ figmaVectorExportNodeId: entry.exportNodeId,
408
+ uiKitFileName: entry.uiKitFileName,
409
+ uiKitExportName: fileNameToExportName(entry.uiKitFileName),
410
+ uiKitGradientFileName: `${entry.uiKitFileName}Gradient`,
411
+ uiKitGradientExportName: `${fileNameToExportName(entry.uiKitFileName)}Gradient`,
412
+ matchMethod: "manual",
413
+ });
414
+ }
415
+
416
+ // Keep one mapping per ui-kit file (prefer exact frame name casing)
417
+ const byFile = new Map<string, PictoMapping>();
418
+ for (const mapping of mappings) {
419
+ const existing = byFile.get(mapping.uiKitFileName);
420
+ if (!existing) {
421
+ byFile.set(mapping.uiKitFileName, mapping);
422
+ continue;
423
+ }
424
+ const preferNew =
425
+ mapping.figmaFrameName === mapping.uiKitFileName ||
426
+ (existing.figmaFrameName !== existing.uiKitFileName &&
427
+ mapping.figmaFrameName.length <= existing.figmaFrameName.length);
428
+ if (preferNew) byFile.set(mapping.uiKitFileName, mapping);
429
+ }
430
+
431
+ const duplicateMappings = await loadDuplicateVectorMappings();
432
+ for (const dup of duplicateMappings) {
433
+ const hasGlass = repoFiles.has(dup.uiKitFileName);
434
+ const isNewGlass = dup.uiKitFileName === "Compute";
435
+ if (!hasGlass && !isNewGlass) continue;
436
+
437
+ const existing = byFile.get(dup.uiKitFileName);
438
+ byFile.set(dup.uiKitFileName, {
439
+ figmaFrameName: dup.figmaFrameName ?? existing?.figmaFrameName ?? dup.uiKitFileName,
440
+ figmaLightName: existing?.figmaLightName ?? `${dup.uiKitFileName}_light`,
441
+ figmaVectorName: dup.figmaVectorName,
442
+ figmaLightNodeId: dup.figmaLightNodeId ?? existing?.figmaLightNodeId ?? "",
443
+ figmaVectorNodeId: dup.symbolId,
444
+ figmaVectorExportNodeId: dup.exportNodeId,
445
+ uiKitFileName: dup.uiKitFileName,
446
+ uiKitExportName: fileNameToExportName(dup.uiKitFileName),
447
+ uiKitGradientFileName: `${dup.uiKitFileName}Gradient`,
448
+ uiKitGradientExportName: `${fileNameToExportName(dup.uiKitFileName)}Gradient`,
449
+ matchMethod: "manual",
450
+ });
451
+ }
452
+
453
+ return [...byFile.values()].sort((a, b) => a.uiKitFileName.localeCompare(b.uiKitFileName));
454
+ }
455
+
456
+ async function optimizePngDir(pngDir: string, outDir = PICTOS_DIR) {
457
+ await mkdir(outDir, { recursive: true });
458
+ const files = (await readdir(pngDir)).filter((f) => f.endsWith(".png"));
459
+
460
+ for (const file of files) {
461
+ const base = basename(file, ".png");
462
+ const input = join(pngDir, file);
463
+ const sized = join(pngDir, `.tmp-${base}.png`);
464
+ const out = join(outDir, `${base}.webp`);
465
+ // Two-step convert avoids ImageMagick WebP encoder hangs on some systems.
466
+ // Trim export padding, then scale icon content to fill the 500×500 canvas.
467
+ execSync(
468
+ `magick "${input}" -trim +repage -resize 500x500 -background none -gravity center -extent 500x500 PNG32:"${sized}"`,
469
+ );
470
+ execSync(`magick "${sized}" -define webp:lossless=true "${out}"`);
471
+ execSync(`rm -f "${sized}"`);
472
+ console.log(`Optimized ${file} -> ${basename(out)}`);
473
+ }
474
+ }
475
+
476
+ async function main() {
477
+ const [command, arg] = process.argv.slice(2);
478
+
479
+ if (command === "parse" && arg) {
480
+ const mappings = await buildMapping(arg);
481
+ const repoExports = [
482
+ ...new Set(
483
+ (await readFile(join(import.meta.dir, "../src/constants/pictos.ts"), "utf8"))
484
+ .match(/export \{[^}]+\}/s)?.[0]
485
+ .match(/picto[A-Za-z0-9]+/g) ?? [],
486
+ ),
487
+ ].filter((name) => name !== "pictos");
488
+ const mappedExports = new Set(mappings.map((m) => m.uiKitExportName));
489
+ const output = {
490
+ figmaFileKey: "mcdcK62LxTlRHgolqxqLhf",
491
+ figmaPageNodeId: "25770:1245",
492
+ figmaPageUrl:
493
+ "https://www.figma.com/design/mcdcK62LxTlRHgolqxqLhf/SurrealDB-Brand-Guidelines?node-id=25770-1245",
494
+ description:
495
+ "Maps Figma picto names (light + vector variants) to ui-kit export names. Gradient assets use the vector variant.",
496
+ mappings,
497
+ uiKitPictosWithoutGradient: repoExports.filter((name) => !mappedExports.has(name)),
498
+ };
499
+ await writeFile(MAPPING_PATH, `${JSON.stringify(output, null, 4)}\n`);
500
+ console.log(`Wrote ${mappings.length} mappings to ${MAPPING_PATH}`);
501
+ console.log(
502
+ `${output.uiKitPictosWithoutGradient.length} ui-kit pictos have no gradient vector in Figma yet`,
503
+ );
504
+ return;
505
+ }
506
+
507
+ if (command === "optimize" && arg) {
508
+ await optimizePngDir(arg);
509
+ return;
510
+ }
511
+
512
+ if (command === "list-vector-ids" && arg) {
513
+ const parsed = JSON.parse(await readFile(arg, "utf8"));
514
+ const mappings: PictoMapping[] = Array.isArray(parsed) ? parsed : parsed.mappings;
515
+ for (const m of mappings) {
516
+ console.log(
517
+ `${m.uiKitGradientFileName}\t${m.figmaVectorExportNodeId ?? m.figmaVectorNodeId}`,
518
+ );
519
+ }
520
+ return;
521
+ }
522
+
523
+ if (command === "write-export-batches") {
524
+ const parsed = JSON.parse(await readFile(MAPPING_PATH, "utf8"));
525
+ const mappings: PictoMapping[] = parsed.mappings ?? parsed;
526
+ await mkdir(PNG_DIR, { recursive: true });
527
+ const batches: { fileName: string; nodeId: string }[][] = [];
528
+ const items = mappings.map((m) => ({
529
+ fileName: m.uiKitGradientFileName,
530
+ nodeId: m.figmaVectorExportNodeId,
531
+ }));
532
+ for (let i = 0; i < items.length; i += 20) {
533
+ batches.push(items.slice(i, i + 20));
534
+ await writeFile(
535
+ join(PNG_DIR, `screenshot-batch-${batches.length - 1}.json`),
536
+ `${JSON.stringify(batches.at(-1), null, 2)}\n`,
537
+ );
538
+ }
539
+ console.log(`Wrote ${batches.length} screenshot batches for ${items.length} pictos`);
540
+ return;
541
+ }
542
+
543
+ if (command === "download-urls" && arg) {
544
+ const manifest: { fileName: string; url: string }[] = JSON.parse(
545
+ await readFile(arg, "utf8"),
546
+ );
547
+ const pngDir = join(import.meta.dir, "../.picto-gradient-png");
548
+ await mkdir(pngDir, { recursive: true });
549
+ for (const { fileName, url } of manifest) {
550
+ const res = await fetch(url);
551
+ if (!res.ok) throw new Error(`Failed ${fileName}: ${res.status}`);
552
+ await writeFile(join(pngDir, `${fileName}.png`), await res.arrayBuffer());
553
+ console.log(`Downloaded ${fileName}.png`);
554
+ }
555
+ return;
556
+ }
557
+
558
+ if (command === "generate-imports") {
559
+ const parsed = JSON.parse(await readFile(MAPPING_PATH, "utf8"));
560
+ const mappings: PictoMapping[] = Array.isArray(parsed) ? parsed : parsed.mappings;
561
+ const gradientDir = join(PICTOS_DIR);
562
+ const available = new Set(
563
+ (await readdir(gradientDir))
564
+ .filter((f) => f.endsWith("Gradient.webp"))
565
+ .map((f) => f.replace(/\.webp$/, "")),
566
+ );
567
+ const lines: string[] = [];
568
+ const exports: string[] = [];
569
+ for (const m of mappings) {
570
+ if (!available.has(m.uiKitGradientFileName)) continue;
571
+ lines.push(
572
+ `import ${m.uiKitGradientExportName} from "../assets/pictos/${m.uiKitGradientFileName}.webp";`,
573
+ );
574
+ exports.push(m.uiKitGradientExportName);
575
+ }
576
+ const outPath = join(import.meta.dir, "../src/constants/picto-gradients.ts");
577
+ await writeFile(
578
+ outPath,
579
+ `${lines.join("\n")}\n\nexport {\n ${exports.join(",\n ")},\n};\n`,
580
+ );
581
+ console.log(`Wrote ${exports.length} gradient imports to ${outPath}`);
582
+ return;
583
+ }
584
+
585
+ if (command === "generate-pictos-imports") {
586
+ const glassFiles = (await readdir(PICTOS_DIR))
587
+ .filter((f) => f.endsWith(".webp") && !f.endsWith("Gradient.webp"))
588
+ .map((f) => f.replace(/\.webp$/, ""))
589
+ .sort((a, b) => a.localeCompare(b));
590
+ const lines = glassFiles.map(
591
+ (fileName) =>
592
+ `import ${fileNameToExportName(fileName)} from "../assets/pictos/${fileName}.webp";`,
593
+ );
594
+ const exports = glassFiles.map((fileName) => fileNameToExportName(fileName));
595
+ const outPath = join(import.meta.dir, "../src/constants/pictos.ts");
596
+ await writeFile(
597
+ outPath,
598
+ `${lines.join("\n")}\n\nexport {\n ${exports.join(",\n ")},\n};\n`,
599
+ );
600
+ console.log(`Wrote ${exports.length} glass picto imports to ${outPath}`);
601
+ return;
602
+ }
603
+
604
+ if (command === "list-glass-ids") {
605
+ const parsed = JSON.parse(await readFile(MAPPING_PATH, "utf8"));
606
+ const mappings: PictoMapping[] = parsed.mappings ?? parsed;
607
+ const glassFiles = new Set(
608
+ (await readdir(PICTOS_DIR))
609
+ .filter((f) => f.endsWith(".webp") && !f.endsWith("Gradient.webp"))
610
+ .map((f) => f.replace(/\.webp$/, "")),
611
+ );
612
+ for (const m of mappings) {
613
+ if (!glassFiles.has(m.uiKitFileName) && m.figmaLightNodeId) {
614
+ console.log(`${m.uiKitFileName}\t${m.figmaLightNodeId}`);
615
+ }
616
+ }
617
+ return;
618
+ }
619
+
620
+ console.error(
621
+ `Usage: bun tools/picto-sync.ts <parse|optimize|list-vector-ids|list-glass-ids|download-urls|generate-imports|generate-pictos-imports> <path>`,
622
+ );
623
+ process.exit(1);
624
+ }
625
+
626
+ main().catch((err) => {
627
+ console.error(err);
628
+ process.exit(1);
629
+ });