@parto-system-design/ui 1.1.11 → 1.1.16

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 (411) hide show
  1. package/dist/components/brand/parto-logo.cjs +130 -0
  2. package/dist/components/brand/parto-logo.cjs.map +1 -0
  3. package/dist/components/brand/parto-logo.d.cts +38 -0
  4. package/dist/components/brand/parto-logo.d.ts +38 -0
  5. package/dist/components/brand/parto-logo.js +108 -0
  6. package/dist/components/brand/parto-logo.js.map +1 -0
  7. package/dist/components/charts/PartoAreaChart.cjs +579 -7
  8. package/dist/components/charts/PartoAreaChart.cjs.map +1 -1
  9. package/dist/components/charts/PartoAreaChart.js +564 -4
  10. package/dist/components/charts/PartoAreaChart.js.map +1 -1
  11. package/dist/components/charts/PartoBarChart.cjs +616 -7
  12. package/dist/components/charts/PartoBarChart.cjs.map +1 -1
  13. package/dist/components/charts/PartoBarChart.js +601 -4
  14. package/dist/components/charts/PartoBarChart.js.map +1 -1
  15. package/dist/components/charts/PartoLineChart.cjs +584 -7
  16. package/dist/components/charts/PartoLineChart.cjs.map +1 -1
  17. package/dist/components/charts/PartoLineChart.js +569 -4
  18. package/dist/components/charts/PartoLineChart.js.map +1 -1
  19. package/dist/components/charts/PartoPieChart.cjs +566 -7
  20. package/dist/components/charts/PartoPieChart.cjs.map +1 -1
  21. package/dist/components/charts/PartoPieChart.js +551 -4
  22. package/dist/components/charts/PartoPieChart.js.map +1 -1
  23. package/dist/components/ui/accordion.cjs +97 -0
  24. package/dist/components/ui/accordion.cjs.map +1 -0
  25. package/dist/components/ui/accordion.d.cts +22 -0
  26. package/dist/components/ui/accordion.d.ts +22 -0
  27. package/dist/components/ui/accordion.js +72 -0
  28. package/dist/components/ui/accordion.js.map +1 -0
  29. package/dist/{chunk-MMC6M35Q.cjs → components/ui/alert-dialog.cjs} +216 -22
  30. package/dist/components/ui/alert-dialog.cjs.map +1 -0
  31. package/dist/components/ui/alert-dialog.d.cts +17 -0
  32. package/dist/components/ui/alert-dialog.d.ts +17 -0
  33. package/dist/{chunk-3QYYPPFJ.js → components/ui/alert-dialog.js} +175 -10
  34. package/dist/components/ui/alert-dialog.js.map +1 -0
  35. package/dist/components/ui/alert-rule-card.cjs +289 -8
  36. package/dist/components/ui/alert-rule-card.cjs.map +1 -1
  37. package/dist/components/ui/alert-rule-card.d.cts +1 -1
  38. package/dist/components/ui/alert-rule-card.d.ts +1 -1
  39. package/dist/components/ui/alert-rule-card.js +271 -4
  40. package/dist/components/ui/alert-rule-card.js.map +1 -1
  41. package/dist/components/ui/alert.cjs +81 -0
  42. package/dist/components/ui/alert.cjs.map +1 -0
  43. package/dist/components/ui/alert.d.cts +11 -0
  44. package/dist/components/ui/alert.d.ts +11 -0
  45. package/dist/components/ui/alert.js +57 -0
  46. package/dist/components/ui/alert.js.map +1 -0
  47. package/dist/components/ui/app-bar.cjs +67 -0
  48. package/dist/components/ui/app-bar.cjs.map +1 -0
  49. package/dist/components/ui/app-bar.d.cts +22 -0
  50. package/dist/components/ui/app-bar.d.ts +22 -0
  51. package/dist/components/ui/app-bar.js +44 -0
  52. package/dist/components/ui/app-bar.js.map +1 -0
  53. package/dist/components/ui/avatar.cjs +66 -14
  54. package/dist/components/ui/avatar.cjs.map +1 -1
  55. package/dist/components/ui/avatar.js +47 -2
  56. package/dist/components/ui/avatar.js.map +1 -1
  57. package/dist/components/ui/badge.cjs +113 -9
  58. package/dist/components/ui/badge.cjs.map +1 -1
  59. package/dist/components/ui/badge.d.cts +1 -1
  60. package/dist/components/ui/badge.d.ts +1 -1
  61. package/dist/components/ui/badge.js +96 -2
  62. package/dist/components/ui/badge.js.map +1 -1
  63. package/dist/components/ui/breadcrumb.cjs +100 -0
  64. package/dist/components/ui/breadcrumb.cjs.map +1 -0
  65. package/dist/components/ui/breadcrumb.d.cts +35 -0
  66. package/dist/components/ui/breadcrumb.d.ts +35 -0
  67. package/dist/components/ui/breadcrumb.js +92 -0
  68. package/dist/components/ui/breadcrumb.js.map +1 -0
  69. package/dist/components/ui/button.cjs +304 -11
  70. package/dist/components/ui/button.cjs.map +1 -1
  71. package/dist/components/ui/button.d.cts +3 -3
  72. package/dist/components/ui/button.d.ts +3 -3
  73. package/dist/components/ui/button.js +306 -3
  74. package/dist/components/ui/button.js.map +1 -1
  75. package/dist/components/ui/calendar.cjs +401 -8
  76. package/dist/components/ui/calendar.cjs.map +1 -1
  77. package/dist/components/ui/calendar.js +404 -4
  78. package/dist/components/ui/calendar.js.map +1 -1
  79. package/dist/components/ui/card.cjs +154 -30
  80. package/dist/components/ui/card.cjs.map +1 -1
  81. package/dist/components/ui/card.js +131 -2
  82. package/dist/components/ui/card.js.map +1 -1
  83. package/dist/{chunk-CAJKSTXX.cjs → components/ui/checkbox.cjs} +10 -5
  84. package/dist/components/ui/checkbox.cjs.map +1 -0
  85. package/dist/components/ui/checkbox.d.cts +6 -0
  86. package/dist/components/ui/checkbox.d.ts +6 -0
  87. package/dist/{chunk-5JJSRGJD.js → components/ui/checkbox.js} +9 -4
  88. package/dist/components/ui/checkbox.js.map +1 -0
  89. package/dist/components/ui/concept-card.cjs +728 -11
  90. package/dist/components/ui/concept-card.cjs.map +1 -1
  91. package/dist/components/ui/concept-card.d.cts +2 -2
  92. package/dist/components/ui/concept-card.d.ts +2 -2
  93. package/dist/components/ui/concept-card.js +710 -7
  94. package/dist/components/ui/concept-card.js.map +1 -1
  95. package/dist/components/ui/data-table.cjs +1553 -10
  96. package/dist/components/ui/data-table.cjs.map +1 -1
  97. package/dist/components/ui/data-table.js +1537 -7
  98. package/dist/components/ui/data-table.js.map +1 -1
  99. package/dist/components/ui/dialog.cjs +119 -42
  100. package/dist/components/ui/dialog.cjs.map +1 -1
  101. package/dist/components/ui/dialog.js +92 -2
  102. package/dist/components/ui/dialog.js.map +1 -1
  103. package/dist/components/ui/dropdown-menu.cjs +268 -0
  104. package/dist/components/ui/dropdown-menu.cjs.map +1 -0
  105. package/dist/components/ui/dropdown-menu.d.cts +73 -0
  106. package/dist/components/ui/dropdown-menu.d.ts +73 -0
  107. package/dist/components/ui/dropdown-menu.js +232 -0
  108. package/dist/components/ui/dropdown-menu.js.map +1 -0
  109. package/dist/components/ui/filter-provider.cjs +70 -13
  110. package/dist/components/ui/filter-provider.cjs.map +1 -1
  111. package/dist/components/ui/filter-provider.js +51 -1
  112. package/dist/components/ui/filter-provider.js.map +1 -1
  113. package/dist/components/ui/form.cjs +169 -0
  114. package/dist/components/ui/form.cjs.map +1 -0
  115. package/dist/components/ui/form.d.cts +46 -0
  116. package/dist/components/ui/form.d.ts +46 -0
  117. package/dist/components/ui/form.js +139 -0
  118. package/dist/components/ui/form.js.map +1 -0
  119. package/dist/components/ui/input.cjs +135 -15
  120. package/dist/components/ui/input.cjs.map +1 -1
  121. package/dist/components/ui/input.d.cts +15 -0
  122. package/dist/components/ui/input.d.ts +15 -0
  123. package/dist/components/ui/input.js +116 -3
  124. package/dist/components/ui/input.js.map +1 -1
  125. package/dist/components/ui/iran-province-heat.cjs +328 -5
  126. package/dist/components/ui/iran-province-heat.cjs.map +1 -1
  127. package/dist/components/ui/iran-province-heat.js +312 -2
  128. package/dist/components/ui/iran-province-heat.js.map +1 -1
  129. package/dist/components/ui/label.cjs +52 -0
  130. package/dist/components/ui/label.cjs.map +1 -0
  131. package/dist/components/ui/label.d.cts +10 -0
  132. package/dist/components/ui/label.d.ts +10 -0
  133. package/dist/components/ui/label.js +30 -0
  134. package/dist/components/ui/label.js.map +1 -0
  135. package/dist/components/ui/page-card.cjs +627 -8
  136. package/dist/components/ui/page-card.cjs.map +1 -1
  137. package/dist/components/ui/page-card.d.cts +3 -2
  138. package/dist/components/ui/page-card.d.ts +3 -2
  139. package/dist/components/ui/page-card.js +611 -5
  140. package/dist/components/ui/page-card.js.map +1 -1
  141. package/dist/components/ui/page-header.cjs +299 -0
  142. package/dist/components/ui/page-header.cjs.map +1 -0
  143. package/dist/components/ui/page-header.d.cts +21 -0
  144. package/dist/components/ui/page-header.d.ts +21 -0
  145. package/dist/components/ui/page-header.js +277 -0
  146. package/dist/components/ui/page-header.js.map +1 -0
  147. package/dist/components/ui/password-input.cjs +168 -0
  148. package/dist/components/ui/password-input.cjs.map +1 -0
  149. package/dist/components/ui/password-input.d.cts +48 -0
  150. package/dist/components/ui/password-input.d.ts +48 -0
  151. package/dist/components/ui/password-input.js +146 -0
  152. package/dist/components/ui/password-input.js.map +1 -0
  153. package/dist/components/ui/popover.cjs +51 -18
  154. package/dist/components/ui/popover.cjs.map +1 -1
  155. package/dist/components/ui/popover.js +30 -2
  156. package/dist/components/ui/popover.js.map +1 -1
  157. package/dist/components/ui/progress.cjs +95 -0
  158. package/dist/components/ui/progress.cjs.map +1 -0
  159. package/dist/components/ui/progress.d.cts +18 -0
  160. package/dist/components/ui/progress.d.ts +18 -0
  161. package/dist/components/ui/progress.js +72 -0
  162. package/dist/components/ui/progress.js.map +1 -0
  163. package/dist/components/ui/radio-card.cjs +84 -0
  164. package/dist/components/ui/radio-card.cjs.map +1 -0
  165. package/dist/components/ui/radio-card.d.cts +12 -0
  166. package/dist/components/ui/radio-card.d.ts +12 -0
  167. package/dist/components/ui/radio-card.js +58 -0
  168. package/dist/components/ui/radio-card.js.map +1 -0
  169. package/dist/components/ui/radio-group.cjs +62 -0
  170. package/dist/components/ui/radio-group.cjs.map +1 -0
  171. package/dist/components/ui/radio-group.d.cts +7 -0
  172. package/dist/components/ui/radio-group.d.ts +7 -0
  173. package/dist/components/ui/radio-group.js +38 -0
  174. package/dist/components/ui/radio-group.js.map +1 -0
  175. package/dist/components/ui/saved-query-card.cjs +409 -7
  176. package/dist/components/ui/saved-query-card.cjs.map +1 -1
  177. package/dist/components/ui/saved-query-card.js +394 -4
  178. package/dist/components/ui/saved-query-card.js.map +1 -1
  179. package/dist/components/ui/scroll-area.cjs +79 -0
  180. package/dist/components/ui/scroll-area.cjs.map +1 -0
  181. package/dist/components/ui/scroll-area.d.cts +14 -0
  182. package/dist/components/ui/scroll-area.d.ts +14 -0
  183. package/dist/components/ui/scroll-area.js +56 -0
  184. package/dist/components/ui/scroll-area.js.map +1 -0
  185. package/dist/components/ui/select.cjs +242 -0
  186. package/dist/components/ui/select.cjs.map +1 -0
  187. package/dist/components/ui/select.d.cts +29 -0
  188. package/dist/components/ui/select.d.ts +29 -0
  189. package/dist/components/ui/select.js +210 -0
  190. package/dist/components/ui/select.js.map +1 -0
  191. package/dist/components/ui/separator.cjs +105 -6
  192. package/dist/components/ui/separator.cjs.map +1 -1
  193. package/dist/components/ui/separator.js +87 -2
  194. package/dist/components/ui/separator.js.map +1 -1
  195. package/dist/components/ui/sheet.cjs +134 -38
  196. package/dist/components/ui/sheet.cjs.map +1 -1
  197. package/dist/components/ui/sheet.js +109 -2
  198. package/dist/components/ui/sheet.js.map +1 -1
  199. package/dist/{chunk-D2EBLE2B.cjs → components/ui/skeleton.cjs} +21 -16
  200. package/dist/components/ui/skeleton.cjs.map +1 -0
  201. package/dist/components/ui/skeleton.d.cts +90 -0
  202. package/dist/components/ui/skeleton.d.ts +90 -0
  203. package/dist/{chunk-SB5DSYR5.js → components/ui/skeleton.js} +8 -3
  204. package/dist/components/ui/skeleton.js.map +1 -0
  205. package/dist/components/ui/slider.cjs +129 -0
  206. package/dist/components/ui/slider.cjs.map +1 -0
  207. package/dist/components/ui/slider.d.cts +10 -0
  208. package/dist/components/ui/slider.d.ts +10 -0
  209. package/dist/components/ui/slider.js +107 -0
  210. package/dist/components/ui/slider.js.map +1 -0
  211. package/dist/components/ui/social-platform-badge.cjs +120 -0
  212. package/dist/components/ui/social-platform-badge.cjs.map +1 -0
  213. package/dist/components/ui/social-platform-badge.d.cts +21 -0
  214. package/dist/components/ui/social-platform-badge.d.ts +21 -0
  215. package/dist/components/ui/social-platform-badge.js +97 -0
  216. package/dist/components/ui/social-platform-badge.js.map +1 -0
  217. package/dist/components/ui/sonner.cjs +51 -0
  218. package/dist/components/ui/sonner.cjs.map +1 -0
  219. package/dist/components/ui/sonner.d.cts +13 -0
  220. package/dist/components/ui/sonner.d.ts +13 -0
  221. package/dist/components/ui/sonner.js +45 -0
  222. package/dist/components/ui/sonner.js.map +1 -0
  223. package/dist/components/ui/sparkline.cjs +159 -6
  224. package/dist/components/ui/sparkline.cjs.map +1 -1
  225. package/dist/components/ui/sparkline.js +142 -2
  226. package/dist/components/ui/sparkline.js.map +1 -1
  227. package/dist/components/ui/switch.cjs +96 -0
  228. package/dist/components/ui/switch.cjs.map +1 -0
  229. package/dist/components/ui/switch.d.cts +13 -0
  230. package/dist/components/ui/switch.d.ts +13 -0
  231. package/dist/components/ui/switch.js +73 -0
  232. package/dist/components/ui/switch.js.map +1 -0
  233. package/dist/components/ui/table.cjs +188 -0
  234. package/dist/components/ui/table.cjs.map +1 -0
  235. package/dist/components/ui/table.d.cts +59 -0
  236. package/dist/components/ui/table.d.ts +59 -0
  237. package/dist/components/ui/table.js +178 -0
  238. package/dist/components/ui/table.js.map +1 -0
  239. package/dist/components/ui/tabs.cjs +140 -0
  240. package/dist/components/ui/tabs.cjs.map +1 -0
  241. package/dist/components/ui/tabs.d.cts +21 -0
  242. package/dist/components/ui/tabs.d.ts +21 -0
  243. package/dist/components/ui/tabs.js +115 -0
  244. package/dist/components/ui/tabs.js.map +1 -0
  245. package/dist/components/ui/textarea.cjs +56 -0
  246. package/dist/components/ui/textarea.cjs.map +1 -0
  247. package/dist/components/ui/textarea.d.cts +5 -0
  248. package/dist/components/ui/textarea.d.ts +5 -0
  249. package/dist/components/ui/textarea.js +34 -0
  250. package/dist/components/ui/textarea.js.map +1 -0
  251. package/dist/components/ui/toggle-group.cjs +123 -0
  252. package/dist/components/ui/toggle-group.cjs.map +1 -0
  253. package/dist/components/ui/toggle-group.d.cts +7 -0
  254. package/dist/components/ui/toggle-group.d.ts +7 -0
  255. package/dist/components/ui/toggle-group.js +99 -0
  256. package/dist/components/ui/toggle-group.js.map +1 -0
  257. package/dist/components/ui/tooltip.cjs +77 -18
  258. package/dist/components/ui/tooltip.cjs.map +1 -1
  259. package/dist/components/ui/tooltip.js +56 -2
  260. package/dist/components/ui/tooltip.js.map +1 -1
  261. package/dist/{concept-card-RwPbqJ06.d.cts → concept-card-BXra9mr0.d.cts} +2 -2
  262. package/dist/{concept-card-CcOBb2Nz.d.ts → concept-card-BoJ5gIJD.d.ts} +2 -2
  263. package/dist/hooks/use-hotkey-registry.cjs +201 -14
  264. package/dist/hooks/use-hotkey-registry.cjs.map +1 -1
  265. package/dist/hooks/use-hotkey-registry.js +182 -2
  266. package/dist/hooks/use-hotkey-registry.js.map +1 -1
  267. package/dist/hooks/use-hotkeys.cjs +144 -9
  268. package/dist/hooks/use-hotkeys.cjs.map +1 -1
  269. package/dist/hooks/use-hotkeys.js +126 -1
  270. package/dist/hooks/use-hotkeys.js.map +1 -1
  271. package/dist/{i18n-CAd9wGOr.d.cts → i18n-BfRhV5aw.d.cts} +5 -3
  272. package/dist/{i18n-ArS3mqj0.d.ts → i18n-ewyqbKM-.d.ts} +5 -3
  273. package/dist/index.cjs +20906 -15706
  274. package/dist/index.cjs.map +1 -1
  275. package/dist/index.css +396 -69
  276. package/dist/index.d.cts +49 -490
  277. package/dist/index.d.ts +49 -490
  278. package/dist/index.js +7704 -2032
  279. package/dist/index.js.map +1 -1
  280. package/dist/{page-card-CmShVqG-.d.cts → page-card-C9XXXOVr.d.cts} +3 -20
  281. package/dist/{page-card-HBn-cy4J.d.ts → page-card-DAnbez_f.d.ts} +3 -20
  282. package/dist/toggle-group-B8r4LOQw.d.cts +26 -0
  283. package/dist/toggle-group-B8r4LOQw.d.ts +26 -0
  284. package/package.json +132 -2
  285. package/tailwind.config.ts +45 -0
  286. package/dist/chunk-2ACKKPWA.cjs +0 -112
  287. package/dist/chunk-2ACKKPWA.cjs.map +0 -1
  288. package/dist/chunk-2UD3LGVX.cjs +0 -316
  289. package/dist/chunk-2UD3LGVX.cjs.map +0 -1
  290. package/dist/chunk-3QYYPPFJ.js.map +0 -1
  291. package/dist/chunk-4SVQNEVH.js +0 -173
  292. package/dist/chunk-4SVQNEVH.js.map +0 -1
  293. package/dist/chunk-4WONHORR.cjs +0 -152
  294. package/dist/chunk-4WONHORR.cjs.map +0 -1
  295. package/dist/chunk-5HCXH6GS.js +0 -409
  296. package/dist/chunk-5HCXH6GS.js.map +0 -1
  297. package/dist/chunk-5JJSRGJD.js.map +0 -1
  298. package/dist/chunk-5K6E4ZSW.cjs +0 -77
  299. package/dist/chunk-5K6E4ZSW.cjs.map +0 -1
  300. package/dist/chunk-5NY26ULO.js +0 -89
  301. package/dist/chunk-5NY26ULO.js.map +0 -1
  302. package/dist/chunk-7RVPG3LE.cjs +0 -231
  303. package/dist/chunk-7RVPG3LE.cjs.map +0 -1
  304. package/dist/chunk-AYEK3WOM.js +0 -207
  305. package/dist/chunk-AYEK3WOM.js.map +0 -1
  306. package/dist/chunk-BRMBLIQG.js +0 -53
  307. package/dist/chunk-BRMBLIQG.js.map +0 -1
  308. package/dist/chunk-CAJKSTXX.cjs.map +0 -1
  309. package/dist/chunk-CKFWMHQU.js +0 -401
  310. package/dist/chunk-CKFWMHQU.js.map +0 -1
  311. package/dist/chunk-CV3N3HVK.js +0 -672
  312. package/dist/chunk-CV3N3HVK.js.map +0 -1
  313. package/dist/chunk-D2EBLE2B.cjs.map +0 -1
  314. package/dist/chunk-GCZ6YATL.js +0 -940
  315. package/dist/chunk-GCZ6YATL.js.map +0 -1
  316. package/dist/chunk-GKRAZGDI.cjs +0 -84
  317. package/dist/chunk-GKRAZGDI.cjs.map +0 -1
  318. package/dist/chunk-GPYJ66CG.js +0 -45
  319. package/dist/chunk-GPYJ66CG.js.map +0 -1
  320. package/dist/chunk-HF6XU5NI.js +0 -84
  321. package/dist/chunk-HF6XU5NI.js.map +0 -1
  322. package/dist/chunk-HJPDZOMJ.cjs +0 -87
  323. package/dist/chunk-HJPDZOMJ.cjs.map +0 -1
  324. package/dist/chunk-HS3XI3CC.cjs +0 -69
  325. package/dist/chunk-HS3XI3CC.cjs.map +0 -1
  326. package/dist/chunk-HUCC3QH5.cjs +0 -53
  327. package/dist/chunk-HUCC3QH5.cjs.map +0 -1
  328. package/dist/chunk-HYZ6BQPS.cjs +0 -425
  329. package/dist/chunk-HYZ6BQPS.cjs.map +0 -1
  330. package/dist/chunk-ISCSZMYW.cjs +0 -106
  331. package/dist/chunk-ISCSZMYW.cjs.map +0 -1
  332. package/dist/chunk-IXFEFIDO.js +0 -82
  333. package/dist/chunk-IXFEFIDO.js.map +0 -1
  334. package/dist/chunk-JCJLN437.js +0 -108
  335. package/dist/chunk-JCJLN437.js.map +0 -1
  336. package/dist/chunk-JMKNNH63.cjs +0 -982
  337. package/dist/chunk-JMKNNH63.cjs.map +0 -1
  338. package/dist/chunk-JUBHQAA2.js +0 -53
  339. package/dist/chunk-JUBHQAA2.js.map +0 -1
  340. package/dist/chunk-K6G63EED.cjs +0 -41
  341. package/dist/chunk-K6G63EED.cjs.map +0 -1
  342. package/dist/chunk-KCWRCSI7.js +0 -62
  343. package/dist/chunk-KCWRCSI7.js.map +0 -1
  344. package/dist/chunk-KYM7NIJO.cjs +0 -433
  345. package/dist/chunk-KYM7NIJO.cjs.map +0 -1
  346. package/dist/chunk-L2L5CKC2.js +0 -291
  347. package/dist/chunk-L2L5CKC2.js.map +0 -1
  348. package/dist/chunk-M5CHZ5BA.js +0 -124
  349. package/dist/chunk-M5CHZ5BA.js.map +0 -1
  350. package/dist/chunk-MEK4RSGC.js +0 -65
  351. package/dist/chunk-MEK4RSGC.js.map +0 -1
  352. package/dist/chunk-MEKWH3GS.js +0 -89
  353. package/dist/chunk-MEKWH3GS.js.map +0 -1
  354. package/dist/chunk-MFTX2DDQ.js +0 -27
  355. package/dist/chunk-MFTX2DDQ.js.map +0 -1
  356. package/dist/chunk-MMC6M35Q.cjs.map +0 -1
  357. package/dist/chunk-NMH43BDC.js +0 -130
  358. package/dist/chunk-NMH43BDC.js.map +0 -1
  359. package/dist/chunk-NORDUD2T.cjs +0 -135
  360. package/dist/chunk-NORDUD2T.cjs.map +0 -1
  361. package/dist/chunk-NV4JOKWL.cjs +0 -197
  362. package/dist/chunk-NV4JOKWL.cjs.map +0 -1
  363. package/dist/chunk-O2JG7WY5.cjs +0 -121
  364. package/dist/chunk-O2JG7WY5.cjs.map +0 -1
  365. package/dist/chunk-ONO2FTV4.cjs +0 -68
  366. package/dist/chunk-ONO2FTV4.cjs.map +0 -1
  367. package/dist/chunk-OQB6HIUL.cjs +0 -108
  368. package/dist/chunk-OQB6HIUL.cjs.map +0 -1
  369. package/dist/chunk-OS6CMYAS.cjs +0 -79
  370. package/dist/chunk-OS6CMYAS.cjs.map +0 -1
  371. package/dist/chunk-PYURPUTV.js +0 -402
  372. package/dist/chunk-PYURPUTV.js.map +0 -1
  373. package/dist/chunk-RJ3HYZ7S.js +0 -44
  374. package/dist/chunk-RJ3HYZ7S.js.map +0 -1
  375. package/dist/chunk-RZNRIOLT.js +0 -128
  376. package/dist/chunk-RZNRIOLT.js.map +0 -1
  377. package/dist/chunk-S3T2L6NA.js +0 -38
  378. package/dist/chunk-S3T2L6NA.js.map +0 -1
  379. package/dist/chunk-S5IPJQZ3.cjs +0 -161
  380. package/dist/chunk-S5IPJQZ3.cjs.map +0 -1
  381. package/dist/chunk-SB5DSYR5.js.map +0 -1
  382. package/dist/chunk-SFXV2DUH.js +0 -106
  383. package/dist/chunk-SFXV2DUH.js.map +0 -1
  384. package/dist/chunk-SXEPGD4Z.cjs +0 -152
  385. package/dist/chunk-SXEPGD4Z.cjs.map +0 -1
  386. package/dist/chunk-SXWSOU3Y.js +0 -89
  387. package/dist/chunk-SXWSOU3Y.js.map +0 -1
  388. package/dist/chunk-SZMVOHT7.cjs +0 -107
  389. package/dist/chunk-SZMVOHT7.cjs.map +0 -1
  390. package/dist/chunk-TWJXOV4C.js +0 -145
  391. package/dist/chunk-TWJXOV4C.js.map +0 -1
  392. package/dist/chunk-U3ADRIVO.cjs +0 -434
  393. package/dist/chunk-U3ADRIVO.cjs.map +0 -1
  394. package/dist/chunk-U5FLLCGC.cjs +0 -151
  395. package/dist/chunk-U5FLLCGC.cjs.map +0 -1
  396. package/dist/chunk-UOZN45G4.cjs +0 -130
  397. package/dist/chunk-UOZN45G4.cjs.map +0 -1
  398. package/dist/chunk-VHLDOG74.cjs +0 -167
  399. package/dist/chunk-VHLDOG74.cjs.map +0 -1
  400. package/dist/chunk-YC5KLN6I.js +0 -139
  401. package/dist/chunk-YC5KLN6I.js.map +0 -1
  402. package/dist/chunk-YENXXYUV.cjs +0 -111
  403. package/dist/chunk-YENXXYUV.cjs.map +0 -1
  404. package/dist/chunk-YFQWC2PW.js +0 -113
  405. package/dist/chunk-YFQWC2PW.js.map +0 -1
  406. package/dist/chunk-Z2TY4A75.cjs +0 -700
  407. package/dist/chunk-Z2TY4A75.cjs.map +0 -1
  408. package/dist/chunk-Z56O7UEU.cjs +0 -136
  409. package/dist/chunk-Z56O7UEU.cjs.map +0 -1
  410. package/dist/chunk-ZBZDR4ZC.js +0 -106
  411. package/dist/chunk-ZBZDR4ZC.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/utils.ts","../../../src/components/ui/social-platform-badge.tsx"],"names":[],"mappings":";;;;;;AAIO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;ACqBA,IAAM,aAAA,GAGF;AAAA,EACF,SAAA,EAAW;AAAA,IACT,KAAA,EAAO,WAAA;AAAA,IACP,MAAM,CAAC,EAAE,WAAU,qBACjB,GAAA,CAAC,SAAI,SAAA,EAAsB,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,gBAAe,aAAA,EAAY,MAAA,EAC7E,8BAAC,MAAA,EAAA,EAAK,CAAA,EAAE,kjCAAijC,CAAA,EAC3jC;AAAA,GAEJ;AAAA,EACA,OAAA,EAAS;AAAA,IACP,KAAA,EAAO,GAAA;AAAA,IACP,MAAM,CAAC,EAAE,WAAU,qBACjB,GAAA,CAAC,SAAI,SAAA,EAAsB,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,gBAAe,aAAA,EAAY,MAAA,EAC7E,8BAAC,MAAA,EAAA,EAAK,CAAA,EAAE,4KAA2K,CAAA,EACrL;AAAA,GAEJ;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,KAAA,EAAO,QAAA;AAAA,IACP,MAAM,CAAC,EAAE,WAAU,qBACjB,GAAA,CAAC,SAAI,SAAA,EAAsB,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,gBAAe,aAAA,EAAY,MAAA,EAC7E,8BAAC,MAAA,EAAA,EAAK,CAAA,EAAE,8SAA6S,CAAA,EACvT;AAAA,GAEJ;AAAA,EACA,OAAA,EAAS;AAAA,IACP,KAAA,EAAO,SAAA;AAAA,IACP,MAAM,CAAC,EAAE,WAAU,qBACjB,GAAA,CAAC,SAAI,SAAA,EAAsB,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,gBAAe,aAAA,EAAY,MAAA,EAC7E,8BAAC,MAAA,EAAA,EAAK,CAAA,EAAE,yVAAwV,CAAA,EAClW;AAAA,GAEJ;AAAA,EACA,QAAA,EAAU;AAAA,IACR,KAAA,EAAO,UAAA;AAAA,IACP,MAAM,CAAC,EAAE,WAAU,qBACjB,GAAA,CAAC,SAAI,SAAA,EAAsB,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,gBAAe,aAAA,EAAY,MAAA,EAC7E,8BAAC,MAAA,EAAA,EAAK,CAAA,EAAE,sbAAqb,CAAA,EAC/b;AAAA,GAEJ;AAAA,EACA,QAAA,EAAU;AAAA,IACR,KAAA,EAAO,UAAA;AAAA,IACP,MAAM,CAAC,EAAE,WAAU,qBACjB,GAAA,CAAC,SAAI,SAAA,EAAsB,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,gBAAe,aAAA,EAAY,MAAA,EAC7E,8BAAC,MAAA,EAAA,EAAK,CAAA,EAAE,+mBAA8mB,CAAA,EACxnB;AAAA,GAEJ;AAAA,EACA,OAAA,EAAS;AAAA,IACP,KAAA,EAAO,SAAA;AAAA,IACP,MAAM,CAAC,EAAE,WAAU,qBACjB,GAAA,CAAC,SAAI,SAAA,EAAsB,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,gBAAe,aAAA,EAAY,MAAA,EAC7E,8BAAC,MAAA,EAAA,EAAK,CAAA,EAAE,krCAAirC,CAAA,EAC3rC;AAAA,GAEJ;AAAA,EACA,QAAA,EAAU;AAAA,IACR,KAAA,EAAO,UAAA;AAAA,IACP,MAAM,CAAC,EAAE,WAAU,qBACjB,GAAA,CAAC,SAAI,SAAA,EAAsB,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,gBAAe,aAAA,EAAY,MAAA,EAC7E,8BAAC,MAAA,EAAA,EAAK,CAAA,EAAE,kSAAiS,CAAA,EAC3S;AAAA;AAGN,CAAA;AAEA,IAAM,2BAAA,GAA8B,IAAI,qEAAA,EAAuE;AAAA,EAC7G,QAAA,EAAU;AAAA,IACR,IAAA,EAAM;AAAA,MACJ,EAAA,EAAI,OAAA;AAAA,MACJ,EAAA,EAAI,SAAA;AAAA,MACJ,EAAA,EAAI,SAAA;AAAA,MACJ,EAAA,EAAI;AAAA,KACN;AAAA,IACA,OAAA,EAAS;AAAA,MACP,IAAA,EAAM,EAAA;AAAA,MACN,KAAA,EAAO;AAAA;AACT,GACF;AAAA,EACA,gBAAA,EAAkB;AAAA,IAChB,EAAE,OAAA,EAAS,OAAA,EAAS,IAAA,EAAM,IAAA,EAAM,WAAW,uBAAA,EAAwB;AAAA,IACnE,EAAE,OAAA,EAAS,OAAA,EAAS,IAAA,EAAM,IAAA,EAAM,WAAW,mBAAA,EAAoB;AAAA,IAC/D,EAAE,OAAA,EAAS,OAAA,EAAS,IAAA,EAAM,IAAA,EAAM,WAAW,wBAAA,EAAyB;AAAA,IACpE,EAAE,OAAA,EAAS,OAAA,EAAS,IAAA,EAAM,IAAA,EAAM,WAAW,wBAAA;AAAyB,GACtE;AAAA,EACA,eAAA,EAAiB,EAAE,IAAA,EAAM,IAAA,EAAM,SAAS,MAAA;AAC1C,CAAC;AAGD,IAAM,kBAAA,GAAqB;AAAA,EACzB,EAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAU,MAAM,SAAA,EAAU;AAAA,EACtC,EAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAU,MAAM,SAAA,EAAU;AAAA,EACtC,EAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAU,MAAM,SAAA,EAAU;AAAA,EACtC,EAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAU,MAAM,WAAA;AAC9B,CAAA;AAEA,IAAM,mBAAA,GAA4B,KAAA,CAAA,UAAA;AAAA,EAChC,CAAC,EAAE,SAAA,EAAW,QAAA,EAAU,OAAO,IAAA,EAAM,SAAA,GAAY,KAAA,EAAO,OAAA,GAAU,MAAA,EAAQ,KAAA,EAAO,GAAG,KAAA,IAAS,GAAA,KAAQ;AACnG,IAAA,MAAM,IAAA,GAAO,cAAc,QAAQ,CAAA;AACnC,IAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,IAAA,MAAM,WAAA,GAAc,mBAAmB,IAAI,CAAA;AAE3C,IAAA,uBACE,IAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,WAAA,EAAU,uBAAA;AAAA,QACV,SAAA,EAAW,GAAG,2BAAA,CAA4B,EAAE,MAAM,OAAA,EAAS,GAAG,SAAS,CAAA;AAAA,QACvE,KAAA;AAAA,QACC,GAAG,KAAA;AAAA,QAEJ,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAW,EAAA,CAAG,WAAA,CAAY,IAAA,EAAM,UAAU,CAAA,EAAG,KAAA,EAAO,EAAE,KAAA,EAAO,CAAA,sBAAA,EAAyB,QAAQ,KAAI,EAAG,CAAA;AAAA,UAC1G,SAAA,oBAAa,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,EAAA,CAAG,YAAY,IAAA,EAAM,uBAAuB,CAAA,EAAI,QAAA,EAAA,IAAA,CAAK,KAAA,EAAM;AAAA;AAAA;AAAA,KAC5F;AAAA,EAEJ;AACF;AAEA,mBAAA,CAAoB,WAAA,GAAc,qBAAA","file":"social-platform-badge.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\nimport { formatJalaliDate } from '@/lib/jalali-utils'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\nexport type SupportedLocale = 'fa' | 'ar' | 'en'\n\n/**\n * Convert digits in a string to Persian/Arabic numerals based on locale.\n * @example convertToLocalNumbers('123', 'fa') => '۱۲۳'\n * @example convertToLocalNumbers('123', 'en') => '123'\n */\nexport function convertToLocalNumbers(text: string | number, locale: SupportedLocale): string {\n if (locale === 'fa' || locale === 'ar') {\n const persianDigits = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']\n return String(text).replace(/\\d/g, (digit) => persianDigits[parseInt(digit)])\n }\n return String(text)\n}\n\n/**\n * Format large numbers with locale-aware suffixes (K/M/B).\n * @example formatLargeNumber(1500, 'fa') => '۱.۵ هزار'\n * @example formatLargeNumber(1500, 'en') => '1.5K'\n */\nexport function formatLargeNumber(num: number, locale: SupportedLocale): string {\n if (num >= 1_000_000_000) {\n const formatted = (num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'B' : ' میلیارد')\n }\n if (num >= 1_000_000) {\n const formatted = (num / 1_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'M' : ' میلیون')\n }\n if (num >= 1_000) {\n const formatted = (num / 1_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'K' : ' هزار')\n }\n return convertToLocalNumbers(num.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ','), locale)\n}\n\n/**\n * Format number to Instagram-style short format (English only).\n * @example formatNumber(123456, 'short') => '123K'\n * @example formatNumber(123456, 'exact') => '123,456'\n */\nexport function formatNumber(num: number | undefined, format: 'exact' | 'short' = 'exact'): string {\n if (num === undefined || num === null) return '0'\n\n if (format === 'exact') {\n return num.toLocaleString('en-US')\n }\n\n // Short format (Instagram style)\n if (num >= 1_000_000_000) {\n return `${(num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')}B`\n }\n if (num >= 1_000_000) {\n return `${(num / 1_000_000).toFixed(1).replace(/\\.0$/, '')}M`\n }\n if (num >= 1_000) {\n return `${(num / 1_000).toFixed(1).replace(/\\.0$/, '')}K`\n }\n return num.toString()\n}\n\n/**\n * Format date to relative time with absolute on hover (Persian)\n * @example formatRelativeTime(new Date()) => '۲ ساعت پیش'\n */\nexport function formatRelativeTime(date: Date | string | number): string {\n const now = new Date()\n const then = new Date(date)\n const diffInSeconds = Math.floor((now.getTime() - then.getTime()) / 1000)\n\n if (diffInSeconds < 60) {\n return 'همین الان'\n }\n\n const diffInMinutes = Math.floor(diffInSeconds / 60)\n if (diffInMinutes < 60) {\n return `${convertToLocalNumbers(diffInMinutes, 'fa')} دقیقه پیش`\n }\n\n const diffInHours = Math.floor(diffInMinutes / 60)\n if (diffInHours < 24) {\n return `${convertToLocalNumbers(diffInHours, 'fa')} ساعت پیش`\n }\n\n const diffInDays = Math.floor(diffInHours / 24)\n if (diffInDays < 7) {\n return `${convertToLocalNumbers(diffInDays, 'fa')} روز پیش`\n }\n\n const diffInWeeks = Math.floor(diffInDays / 7)\n if (diffInWeeks < 4) {\n return `${convertToLocalNumbers(diffInWeeks, 'fa')} هفته پیش`\n }\n\n const diffInMonths = Math.floor(diffInDays / 30)\n if (diffInMonths < 12) {\n return `${convertToLocalNumbers(diffInMonths, 'fa')} ماه پیش`\n }\n\n const diffInYears = Math.floor(diffInDays / 365)\n return `${convertToLocalNumbers(diffInYears, 'fa')} سال پیش`\n}\n\n/**\n * Format date to absolute format (Persian / Jalali)\n * Uses date-fns-jalali for accurate Jalali conversion.\n * @example formatAbsoluteTime(new Date()) => '۱۵ دی ۱۴۰۳، ۱۵:۳۰'\n */\nexport function formatAbsoluteTime(date: Date | string | number): string {\n const d = new Date(date)\n return formatJalaliDate(d, 'd MMMM yyyy، HH:mm')\n}\n","'use client'\n\nimport * as React from 'react'\nimport { cva } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\n\nexport type SocialPlatform =\n | 'instagram'\n | 'twitter'\n | 'tiktok'\n | 'youtube'\n | 'linkedin'\n | 'telegram'\n | 'threads'\n | 'facebook'\n\nexport interface SocialPlatformBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** The social media platform to display */\n platform: SocialPlatform\n /** Size of the badge */\n size?: 'xs' | 'sm' | 'md' | 'lg'\n /** Show the platform name label */\n showLabel?: boolean\n /** Visual style of the badge */\n variant?: 'flat' | 'badge'\n}\n\nconst PLATFORM_META: Record<\n SocialPlatform,\n { label: string; icon: React.FC<{ className?: string; style?: React.CSSProperties }> }\n> = {\n instagram: {\n label: 'Instagram',\n icon: ({ className }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z\" />\n </svg>\n ),\n },\n twitter: {\n label: 'X',\n icon: ({ className }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.744l7.737-8.835L1.254 2.25H8.08l4.259 5.63 5.905-5.63zm-1.161 17.52h1.833L7.084 4.126H5.117z\" />\n </svg>\n ),\n },\n tiktok: {\n label: 'TikTok',\n icon: ({ className }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M19.59 6.69a4.83 4.83 0 01-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 01-2.88 2.5 2.89 2.89 0 01-2.89-2.89 2.89 2.89 0 012.89-2.89c.28 0 .54.04.79.1V9.01a6.33 6.33 0 00-.79-.05 6.34 6.34 0 00-6.34 6.34 6.34 6.34 0 006.34 6.34 6.34 6.34 0 006.33-6.34V8.69a8.16 8.16 0 004.77 1.52V6.75a4.85 4.85 0 01-1-.06z\" />\n </svg>\n ),\n },\n youtube: {\n label: 'YouTube',\n icon: ({ className }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M23.498 6.186a3.016 3.016 0 00-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 00.502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 002.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 002.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z\" />\n </svg>\n ),\n },\n linkedin: {\n label: 'LinkedIn',\n icon: ({ className }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z\" />\n </svg>\n ),\n },\n telegram: {\n label: 'Telegram',\n icon: ({ className }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M11.944 0A12 12 0 000 12a12 12 0 0012 12 12 12 0 0012-12A12 12 0 0012 0a12 12 0 00-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 01.171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z\" />\n </svg>\n ),\n },\n threads: {\n label: 'Threads',\n icon: ({ className }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M12.186 24h-.007c-3.581-.024-6.334-1.205-8.184-3.509C2.35 18.44 1.5 15.586 1.472 12.01v-.017c.03-3.579.879-6.43 2.525-8.482C5.868 1.205 8.617.024 12.18 0h.014c2.746.02 5.043.725 6.826 2.098 1.677 1.29 2.858 3.13 3.509 5.467l-2.04.569c-1.104-3.96-3.898-5.984-8.304-6.015-2.91.022-5.11.936-6.54 2.717C4.307 6.504 3.616 8.914 3.589 12c.027 3.086.718 5.496 2.057 7.164 1.43 1.783 3.631 2.698 6.54 2.717 2.623-.02 4.358-.631 5.8-2.045 1.647-1.613 1.618-3.593 1.09-4.798-.31-.71-.873-1.3-1.634-1.75-.192 1.352-.622 2.446-1.284 3.272-.886 1.102-2.14 1.704-3.73 1.79-1.202.065-2.361-.218-3.259-.801-1.063-.689-1.685-1.749-1.752-2.98-.065-1.19.388-2.285 1.277-3.086.84-.754 2.02-1.164 3.43-1.19.954-.018 1.858.09 2.695.322-.082-.858-.372-1.502-.861-1.903-.529-.434-1.32-.658-2.332-.67-.884.01-1.63.23-2.22.65l-1.11-1.75c.97-.625 2.18-.95 3.6-.97h.022c1.63.02 2.976.497 3.898 1.385.955.92 1.444 2.25 1.51 3.95.23.073.46.149.682.232 1.69.64 2.847 1.635 3.406 2.946.859 2.002.86 5.139-1.773 7.674-1.797 1.742-3.993 2.525-6.935 2.545zm.098-10.02c-.745.01-1.377.186-1.882.523-.443.298-.706.733-.67 1.215.03.564.342 1.017.876 1.275.516.25 1.087.299 1.58.127.684-.24 1.34-.93 1.614-2.366a9.68 9.68 0 00-1.518-.774z\" />\n </svg>\n ),\n },\n facebook: {\n label: 'Facebook',\n icon: ({ className }) => (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.875v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z\" />\n </svg>\n ),\n },\n}\n\nconst socialPlatformBadgeVariants = cva('inline-flex items-center font-medium transition-colors duration-150', {\n variants: {\n size: {\n xs: 'gap-1',\n sm: 'gap-1.5',\n md: 'gap-1.5',\n lg: 'gap-2',\n },\n variant: {\n flat: '',\n badge: 'border border-border bg-surface-100',\n },\n },\n compoundVariants: [\n { variant: 'badge', size: 'xs', className: 'px-1.5 py-0.5 rounded' },\n { variant: 'badge', size: 'sm', className: 'px-2 py-1 rounded' },\n { variant: 'badge', size: 'md', className: 'px-2.5 py-1 rounded-md' },\n { variant: 'badge', size: 'lg', className: 'px-3 py-1.5 rounded-md' },\n ],\n defaultVariants: { size: 'sm', variant: 'flat' },\n})\n\n/** Size-specific classes for child elements (icon, text) */\nconst SIZE_CHILD_CLASSES = {\n xs: { icon: 'size-3', text: 'text-xs' },\n sm: { icon: 'size-4', text: 'text-xs' },\n md: { icon: 'size-5', text: 'text-sm' },\n lg: { icon: 'size-6', text: 'text-base' },\n}\n\nconst SocialPlatformBadge = React.forwardRef<HTMLSpanElement, SocialPlatformBadgeProps>(\n ({ className, platform, size = 'sm', showLabel = false, variant = 'flat', style, ...props }, ref) => {\n const meta = PLATFORM_META[platform]\n const Icon = meta.icon\n const sizeClasses = SIZE_CHILD_CLASSES[size]\n\n return (\n <span\n ref={ref}\n data-slot=\"social-platform-badge\"\n className={cn(socialPlatformBadgeVariants({ size, variant }), className)}\n style={style}\n {...props}\n >\n <Icon className={cn(sizeClasses.icon, 'shrink-0')} style={{ color: `var(--social-platform-${platform})` }} />\n {showLabel && <span className={cn(sizeClasses.text, 'text-foreground-light')}>{meta.label}</span>}\n </span>\n )\n }\n)\n\nSocialPlatformBadge.displayName = 'SocialPlatformBadge'\n\nexport { SocialPlatformBadge, socialPlatformBadgeVariants }\n"]}
@@ -0,0 +1,51 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ var sonner = require('sonner');
5
+ var clsx = require('clsx');
6
+ var tailwindMerge = require('tailwind-merge');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+
9
+ function cn(...inputs) {
10
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
11
+ }
12
+ var Toaster = ({ className, ...props }) => {
13
+ return /* @__PURE__ */ jsxRuntime.jsx(
14
+ sonner.Toaster,
15
+ {
16
+ "data-slot": "toaster",
17
+ className: cn("toaster group", className),
18
+ dir: "rtl",
19
+ position: "top-center",
20
+ closeButton: true,
21
+ toastOptions: {
22
+ classNames: {
23
+ toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg font-[var(--font-sans)]",
24
+ description: "group-[.toast]:text-muted-foreground",
25
+ actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
26
+ cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
27
+ success: "group-[.toaster]:border-[hsl(var(--brand-default)/0.4)] group-[.toaster]:bg-[hsl(var(--brand-default)/0.06)] group-[.toaster]:text-[hsl(var(--brand-600))]",
28
+ error: "group-[.toaster]:border-[hsl(var(--destructive-500)/0.4)] group-[.toaster]:bg-[hsl(var(--destructive-500)/0.06)] group-[.toaster]:text-[hsl(var(--destructive-600))]",
29
+ warning: "group-[.toaster]:border-[hsl(var(--warning-500)/0.4)] group-[.toaster]:bg-[hsl(var(--warning-500)/0.06)] group-[.toaster]:text-[hsl(var(--warning))]",
30
+ // 1.1.16 — `info` toast was pointing at --secondary-default
31
+ // (hue 247° purple, legacy Supabase token). info has its own
32
+ // semantic family now (--info-default, added 1.1.15), so wire
33
+ // the toast to it.
34
+ info: "group-[.toaster]:border-[hsl(var(--info-default)/0.4)] group-[.toaster]:bg-[hsl(var(--info-default)/0.06)] group-[.toaster]:text-[hsl(var(--info-default))]"
35
+ }
36
+ },
37
+ ...props
38
+ }
39
+ );
40
+ };
41
+ Toaster.displayName = "Toaster";
42
+ var SONNER_DEFAULT_DURATION = 4e3;
43
+
44
+ Object.defineProperty(exports, "toast", {
45
+ enumerable: true,
46
+ get: function () { return sonner.toast; }
47
+ });
48
+ exports.SONNER_DEFAULT_DURATION = SONNER_DEFAULT_DURATION;
49
+ exports.Toaster = Toaster;
50
+ //# sourceMappingURL=sonner.cjs.map
51
+ //# sourceMappingURL=sonner.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/utils.ts","../../../src/components/ui/sonner.tsx"],"names":["twMerge","clsx","jsx","Sonner"],"mappings":";;;;;;;AAIO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAOA,qBAAA,CAAQC,SAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;ACCA,IAAM,UAAU,CAAC,EAAE,SAAA,EAAW,GAAG,OAAM,KAAyB;AAC9D,EAAA,uBACEC,cAAA;AAAA,IAACC,cAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,SAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,eAAA,EAAiB,SAAS,CAAA;AAAA,MACxC,GAAA,EAAI,KAAA;AAAA,MACJ,QAAA,EAAS,YAAA;AAAA,MACT,WAAA,EAAW,IAAA;AAAA,MACX,YAAA,EAAc;AAAA,QACZ,UAAA,EAAY;AAAA,UACV,KAAA,EACE,+JAAA;AAAA,UACF,WAAA,EAAa,sCAAA;AAAA,UACb,YAAA,EAAc,kEAAA;AAAA,UACd,YAAA,EAAc,8DAAA;AAAA,UACd,OAAA,EACE,4JAAA;AAAA,UACF,KAAA,EACE,sKAAA;AAAA,UACF,OAAA,EACE,sJAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAKF,IAAA,EAAM;AAAA;AACR,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;AACA,OAAA,CAAQ,WAAA,GAAc,SAAA;AAIf,IAAM,uBAAA,GAA0B","file":"sonner.cjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\nimport { formatJalaliDate } from '@/lib/jalali-utils'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\nexport type SupportedLocale = 'fa' | 'ar' | 'en'\n\n/**\n * Convert digits in a string to Persian/Arabic numerals based on locale.\n * @example convertToLocalNumbers('123', 'fa') => '۱۲۳'\n * @example convertToLocalNumbers('123', 'en') => '123'\n */\nexport function convertToLocalNumbers(text: string | number, locale: SupportedLocale): string {\n if (locale === 'fa' || locale === 'ar') {\n const persianDigits = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']\n return String(text).replace(/\\d/g, (digit) => persianDigits[parseInt(digit)])\n }\n return String(text)\n}\n\n/**\n * Format large numbers with locale-aware suffixes (K/M/B).\n * @example formatLargeNumber(1500, 'fa') => '۱.۵ هزار'\n * @example formatLargeNumber(1500, 'en') => '1.5K'\n */\nexport function formatLargeNumber(num: number, locale: SupportedLocale): string {\n if (num >= 1_000_000_000) {\n const formatted = (num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'B' : ' میلیارد')\n }\n if (num >= 1_000_000) {\n const formatted = (num / 1_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'M' : ' میلیون')\n }\n if (num >= 1_000) {\n const formatted = (num / 1_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'K' : ' هزار')\n }\n return convertToLocalNumbers(num.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ','), locale)\n}\n\n/**\n * Format number to Instagram-style short format (English only).\n * @example formatNumber(123456, 'short') => '123K'\n * @example formatNumber(123456, 'exact') => '123,456'\n */\nexport function formatNumber(num: number | undefined, format: 'exact' | 'short' = 'exact'): string {\n if (num === undefined || num === null) return '0'\n\n if (format === 'exact') {\n return num.toLocaleString('en-US')\n }\n\n // Short format (Instagram style)\n if (num >= 1_000_000_000) {\n return `${(num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')}B`\n }\n if (num >= 1_000_000) {\n return `${(num / 1_000_000).toFixed(1).replace(/\\.0$/, '')}M`\n }\n if (num >= 1_000) {\n return `${(num / 1_000).toFixed(1).replace(/\\.0$/, '')}K`\n }\n return num.toString()\n}\n\n/**\n * Format date to relative time with absolute on hover (Persian)\n * @example formatRelativeTime(new Date()) => '۲ ساعت پیش'\n */\nexport function formatRelativeTime(date: Date | string | number): string {\n const now = new Date()\n const then = new Date(date)\n const diffInSeconds = Math.floor((now.getTime() - then.getTime()) / 1000)\n\n if (diffInSeconds < 60) {\n return 'همین الان'\n }\n\n const diffInMinutes = Math.floor(diffInSeconds / 60)\n if (diffInMinutes < 60) {\n return `${convertToLocalNumbers(diffInMinutes, 'fa')} دقیقه پیش`\n }\n\n const diffInHours = Math.floor(diffInMinutes / 60)\n if (diffInHours < 24) {\n return `${convertToLocalNumbers(diffInHours, 'fa')} ساعت پیش`\n }\n\n const diffInDays = Math.floor(diffInHours / 24)\n if (diffInDays < 7) {\n return `${convertToLocalNumbers(diffInDays, 'fa')} روز پیش`\n }\n\n const diffInWeeks = Math.floor(diffInDays / 7)\n if (diffInWeeks < 4) {\n return `${convertToLocalNumbers(diffInWeeks, 'fa')} هفته پیش`\n }\n\n const diffInMonths = Math.floor(diffInDays / 30)\n if (diffInMonths < 12) {\n return `${convertToLocalNumbers(diffInMonths, 'fa')} ماه پیش`\n }\n\n const diffInYears = Math.floor(diffInDays / 365)\n return `${convertToLocalNumbers(diffInYears, 'fa')} سال پیش`\n}\n\n/**\n * Format date to absolute format (Persian / Jalali)\n * Uses date-fns-jalali for accurate Jalali conversion.\n * @example formatAbsoluteTime(new Date()) => '۱۵ دی ۱۴۰۳، ۱۵:۳۰'\n */\nexport function formatAbsoluteTime(date: Date | string | number): string {\n const d = new Date(date)\n return formatJalaliDate(d, 'd MMMM yyyy، HH:mm')\n}\n","'use client'\n\nimport { Toaster as Sonner, type ToasterProps } from 'sonner'\nimport { cn } from '@/lib/utils'\n\nexport type PartoToasterProps = ToasterProps\n\nconst Toaster = ({ className, ...props }: PartoToasterProps) => {\n return (\n <Sonner\n data-slot=\"toaster\"\n className={cn('toaster group', className)}\n dir=\"rtl\"\n position=\"top-center\"\n closeButton\n toastOptions={{\n classNames: {\n toast:\n 'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg font-[var(--font-sans)]',\n description: 'group-[.toast]:text-muted-foreground',\n actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',\n cancelButton: 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',\n success:\n 'group-[.toaster]:border-[hsl(var(--brand-default)/0.4)] group-[.toaster]:bg-[hsl(var(--brand-default)/0.06)] group-[.toaster]:text-[hsl(var(--brand-600))]',\n error:\n 'group-[.toaster]:border-[hsl(var(--destructive-500)/0.4)] group-[.toaster]:bg-[hsl(var(--destructive-500)/0.06)] group-[.toaster]:text-[hsl(var(--destructive-600))]',\n warning:\n 'group-[.toaster]:border-[hsl(var(--warning-500)/0.4)] group-[.toaster]:bg-[hsl(var(--warning-500)/0.06)] group-[.toaster]:text-[hsl(var(--warning))]',\n // 1.1.16 — `info` toast was pointing at --secondary-default\n // (hue 247° purple, legacy Supabase token). info has its own\n // semantic family now (--info-default, added 1.1.15), so wire\n // the toast to it.\n info: 'group-[.toaster]:border-[hsl(var(--info-default)/0.4)] group-[.toaster]:bg-[hsl(var(--info-default)/0.06)] group-[.toaster]:text-[hsl(var(--info-default))]',\n },\n }}\n {...props}\n />\n )\n}\nToaster.displayName = 'Toaster'\n\nexport { Toaster }\nexport { toast } from 'sonner'\nexport const SONNER_DEFAULT_DURATION = 4000\n"]}
@@ -0,0 +1,13 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ToasterProps } from 'sonner';
3
+ export { toast } from 'sonner';
4
+
5
+ type PartoToasterProps = ToasterProps;
6
+ declare const Toaster: {
7
+ ({ className, ...props }: PartoToasterProps): react_jsx_runtime.JSX.Element;
8
+ displayName: string;
9
+ };
10
+
11
+ declare const SONNER_DEFAULT_DURATION = 4000;
12
+
13
+ export { type PartoToasterProps, SONNER_DEFAULT_DURATION, Toaster };
@@ -0,0 +1,13 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ToasterProps } from 'sonner';
3
+ export { toast } from 'sonner';
4
+
5
+ type PartoToasterProps = ToasterProps;
6
+ declare const Toaster: {
7
+ ({ className, ...props }: PartoToasterProps): react_jsx_runtime.JSX.Element;
8
+ displayName: string;
9
+ };
10
+
11
+ declare const SONNER_DEFAULT_DURATION = 4000;
12
+
13
+ export { type PartoToasterProps, SONNER_DEFAULT_DURATION, Toaster };
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+ import { Toaster as Toaster$1 } from 'sonner';
3
+ export { toast } from 'sonner';
4
+ import { clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { jsx } from 'react/jsx-runtime';
7
+
8
+ function cn(...inputs) {
9
+ return twMerge(clsx(inputs));
10
+ }
11
+ var Toaster = ({ className, ...props }) => {
12
+ return /* @__PURE__ */ jsx(
13
+ Toaster$1,
14
+ {
15
+ "data-slot": "toaster",
16
+ className: cn("toaster group", className),
17
+ dir: "rtl",
18
+ position: "top-center",
19
+ closeButton: true,
20
+ toastOptions: {
21
+ classNames: {
22
+ toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg font-[var(--font-sans)]",
23
+ description: "group-[.toast]:text-muted-foreground",
24
+ actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
25
+ cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
26
+ success: "group-[.toaster]:border-[hsl(var(--brand-default)/0.4)] group-[.toaster]:bg-[hsl(var(--brand-default)/0.06)] group-[.toaster]:text-[hsl(var(--brand-600))]",
27
+ error: "group-[.toaster]:border-[hsl(var(--destructive-500)/0.4)] group-[.toaster]:bg-[hsl(var(--destructive-500)/0.06)] group-[.toaster]:text-[hsl(var(--destructive-600))]",
28
+ warning: "group-[.toaster]:border-[hsl(var(--warning-500)/0.4)] group-[.toaster]:bg-[hsl(var(--warning-500)/0.06)] group-[.toaster]:text-[hsl(var(--warning))]",
29
+ // 1.1.16 — `info` toast was pointing at --secondary-default
30
+ // (hue 247° purple, legacy Supabase token). info has its own
31
+ // semantic family now (--info-default, added 1.1.15), so wire
32
+ // the toast to it.
33
+ info: "group-[.toaster]:border-[hsl(var(--info-default)/0.4)] group-[.toaster]:bg-[hsl(var(--info-default)/0.06)] group-[.toaster]:text-[hsl(var(--info-default))]"
34
+ }
35
+ },
36
+ ...props
37
+ }
38
+ );
39
+ };
40
+ Toaster.displayName = "Toaster";
41
+ var SONNER_DEFAULT_DURATION = 4e3;
42
+
43
+ export { SONNER_DEFAULT_DURATION, Toaster };
44
+ //# sourceMappingURL=sonner.js.map
45
+ //# sourceMappingURL=sonner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/lib/utils.ts","../../../src/components/ui/sonner.tsx"],"names":["Sonner"],"mappings":";;;;;;AAIO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;ACCA,IAAM,UAAU,CAAC,EAAE,SAAA,EAAW,GAAG,OAAM,KAAyB;AAC9D,EAAA,uBACE,GAAA;AAAA,IAACA,SAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,SAAA;AAAA,MACV,SAAA,EAAW,EAAA,CAAG,eAAA,EAAiB,SAAS,CAAA;AAAA,MACxC,GAAA,EAAI,KAAA;AAAA,MACJ,QAAA,EAAS,YAAA;AAAA,MACT,WAAA,EAAW,IAAA;AAAA,MACX,YAAA,EAAc;AAAA,QACZ,UAAA,EAAY;AAAA,UACV,KAAA,EACE,+JAAA;AAAA,UACF,WAAA,EAAa,sCAAA;AAAA,UACb,YAAA,EAAc,kEAAA;AAAA,UACd,YAAA,EAAc,8DAAA;AAAA,UACd,OAAA,EACE,4JAAA;AAAA,UACF,KAAA,EACE,sKAAA;AAAA,UACF,OAAA,EACE,sJAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAKF,IAAA,EAAM;AAAA;AACR,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;AACA,OAAA,CAAQ,WAAA,GAAc,SAAA;AAIf,IAAM,uBAAA,GAA0B","file":"sonner.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\nimport { formatJalaliDate } from '@/lib/jalali-utils'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\nexport type SupportedLocale = 'fa' | 'ar' | 'en'\n\n/**\n * Convert digits in a string to Persian/Arabic numerals based on locale.\n * @example convertToLocalNumbers('123', 'fa') => '۱۲۳'\n * @example convertToLocalNumbers('123', 'en') => '123'\n */\nexport function convertToLocalNumbers(text: string | number, locale: SupportedLocale): string {\n if (locale === 'fa' || locale === 'ar') {\n const persianDigits = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']\n return String(text).replace(/\\d/g, (digit) => persianDigits[parseInt(digit)])\n }\n return String(text)\n}\n\n/**\n * Format large numbers with locale-aware suffixes (K/M/B).\n * @example formatLargeNumber(1500, 'fa') => '۱.۵ هزار'\n * @example formatLargeNumber(1500, 'en') => '1.5K'\n */\nexport function formatLargeNumber(num: number, locale: SupportedLocale): string {\n if (num >= 1_000_000_000) {\n const formatted = (num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'B' : ' میلیارد')\n }\n if (num >= 1_000_000) {\n const formatted = (num / 1_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'M' : ' میلیون')\n }\n if (num >= 1_000) {\n const formatted = (num / 1_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'K' : ' هزار')\n }\n return convertToLocalNumbers(num.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ','), locale)\n}\n\n/**\n * Format number to Instagram-style short format (English only).\n * @example formatNumber(123456, 'short') => '123K'\n * @example formatNumber(123456, 'exact') => '123,456'\n */\nexport function formatNumber(num: number | undefined, format: 'exact' | 'short' = 'exact'): string {\n if (num === undefined || num === null) return '0'\n\n if (format === 'exact') {\n return num.toLocaleString('en-US')\n }\n\n // Short format (Instagram style)\n if (num >= 1_000_000_000) {\n return `${(num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')}B`\n }\n if (num >= 1_000_000) {\n return `${(num / 1_000_000).toFixed(1).replace(/\\.0$/, '')}M`\n }\n if (num >= 1_000) {\n return `${(num / 1_000).toFixed(1).replace(/\\.0$/, '')}K`\n }\n return num.toString()\n}\n\n/**\n * Format date to relative time with absolute on hover (Persian)\n * @example formatRelativeTime(new Date()) => '۲ ساعت پیش'\n */\nexport function formatRelativeTime(date: Date | string | number): string {\n const now = new Date()\n const then = new Date(date)\n const diffInSeconds = Math.floor((now.getTime() - then.getTime()) / 1000)\n\n if (diffInSeconds < 60) {\n return 'همین الان'\n }\n\n const diffInMinutes = Math.floor(diffInSeconds / 60)\n if (diffInMinutes < 60) {\n return `${convertToLocalNumbers(diffInMinutes, 'fa')} دقیقه پیش`\n }\n\n const diffInHours = Math.floor(diffInMinutes / 60)\n if (diffInHours < 24) {\n return `${convertToLocalNumbers(diffInHours, 'fa')} ساعت پیش`\n }\n\n const diffInDays = Math.floor(diffInHours / 24)\n if (diffInDays < 7) {\n return `${convertToLocalNumbers(diffInDays, 'fa')} روز پیش`\n }\n\n const diffInWeeks = Math.floor(diffInDays / 7)\n if (diffInWeeks < 4) {\n return `${convertToLocalNumbers(diffInWeeks, 'fa')} هفته پیش`\n }\n\n const diffInMonths = Math.floor(diffInDays / 30)\n if (diffInMonths < 12) {\n return `${convertToLocalNumbers(diffInMonths, 'fa')} ماه پیش`\n }\n\n const diffInYears = Math.floor(diffInDays / 365)\n return `${convertToLocalNumbers(diffInYears, 'fa')} سال پیش`\n}\n\n/**\n * Format date to absolute format (Persian / Jalali)\n * Uses date-fns-jalali for accurate Jalali conversion.\n * @example formatAbsoluteTime(new Date()) => '۱۵ دی ۱۴۰۳، ۱۵:۳۰'\n */\nexport function formatAbsoluteTime(date: Date | string | number): string {\n const d = new Date(date)\n return formatJalaliDate(d, 'd MMMM yyyy، HH:mm')\n}\n","'use client'\n\nimport { Toaster as Sonner, type ToasterProps } from 'sonner'\nimport { cn } from '@/lib/utils'\n\nexport type PartoToasterProps = ToasterProps\n\nconst Toaster = ({ className, ...props }: PartoToasterProps) => {\n return (\n <Sonner\n data-slot=\"toaster\"\n className={cn('toaster group', className)}\n dir=\"rtl\"\n position=\"top-center\"\n closeButton\n toastOptions={{\n classNames: {\n toast:\n 'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg font-[var(--font-sans)]',\n description: 'group-[.toast]:text-muted-foreground',\n actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',\n cancelButton: 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',\n success:\n 'group-[.toaster]:border-[hsl(var(--brand-default)/0.4)] group-[.toaster]:bg-[hsl(var(--brand-default)/0.06)] group-[.toaster]:text-[hsl(var(--brand-600))]',\n error:\n 'group-[.toaster]:border-[hsl(var(--destructive-500)/0.4)] group-[.toaster]:bg-[hsl(var(--destructive-500)/0.06)] group-[.toaster]:text-[hsl(var(--destructive-600))]',\n warning:\n 'group-[.toaster]:border-[hsl(var(--warning-500)/0.4)] group-[.toaster]:bg-[hsl(var(--warning-500)/0.06)] group-[.toaster]:text-[hsl(var(--warning))]',\n // 1.1.16 — `info` toast was pointing at --secondary-default\n // (hue 247° purple, legacy Supabase token). info has its own\n // semantic family now (--info-default, added 1.1.15), so wire\n // the toast to it.\n info: 'group-[.toaster]:border-[hsl(var(--info-default)/0.4)] group-[.toaster]:bg-[hsl(var(--info-default)/0.06)] group-[.toaster]:text-[hsl(var(--info-default))]',\n },\n }}\n {...props}\n />\n )\n}\nToaster.displayName = 'Toaster'\n\nexport { Toaster }\nexport { toast } from 'sonner'\nexport const SONNER_DEFAULT_DURATION = 4000\n"]}
@@ -1,13 +1,166 @@
1
+ 'use client';
1
2
  'use strict';
2
3
 
3
- var chunkS5IPJQZ3_cjs = require('../../chunk-S5IPJQZ3.cjs');
4
- require('../../chunk-NV4JOKWL.cjs');
4
+ var React = require('react');
5
+ var clsx = require('clsx');
6
+ var tailwindMerge = require('tailwind-merge');
7
+ var jsxRuntime = require('react/jsx-runtime');
5
8
 
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
6
26
 
27
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
7
28
 
8
- Object.defineProperty(exports, "Sparkline", {
9
- enumerable: true,
10
- get: function () { return chunkS5IPJQZ3_cjs.Sparkline; }
11
- });
29
+ function cn(...inputs) {
30
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
31
+ }
32
+ var TREND_CLASSES = {
33
+ up: "text-[hsl(var(--sentiment-positive))]",
34
+ down: "text-[hsl(var(--sentiment-negative))]",
35
+ neutral: "text-[hsl(var(--sentiment-neutral))]"
36
+ };
37
+ function resolveTrend(data, trend) {
38
+ if (trend !== "auto") return trend;
39
+ if (data.length < 2) return "neutral";
40
+ const first = data[0];
41
+ const last = data[data.length - 1];
42
+ if (last > first) return "up";
43
+ if (last < first) return "down";
44
+ return "neutral";
45
+ }
46
+ var Sparkline = React__namespace.forwardRef(
47
+ ({
48
+ className,
49
+ data,
50
+ variant = "line",
51
+ trend = "auto",
52
+ width = 80,
53
+ height = 24,
54
+ strokeWidth = 1.5,
55
+ showEndDot = false,
56
+ padding = 2,
57
+ color,
58
+ barGap = 1,
59
+ "aria-label": ariaLabel,
60
+ ...props
61
+ }, ref) => {
62
+ const effectiveTrend = resolveTrend(data, trend);
63
+ const trendColorClass = color ? void 0 : TREND_CLASSES[effectiveTrend];
64
+ if (data.length === 0) {
65
+ return /* @__PURE__ */ jsxRuntime.jsx(
66
+ "div",
67
+ {
68
+ ref,
69
+ "data-slot": "sparkline",
70
+ "data-empty": "true",
71
+ "aria-hidden": "true",
72
+ className: cn("inline-block", className),
73
+ style: { width, height },
74
+ ...props
75
+ }
76
+ );
77
+ }
78
+ const min = Math.min(...data);
79
+ const max = Math.max(...data);
80
+ const range = max - min || 1;
81
+ const innerW = width - padding * 2;
82
+ const innerH = height - padding * 2;
83
+ const stepX = data.length > 1 ? innerW / (data.length - 1) : 0;
84
+ const yFor = (v) => padding + innerH - (v - min) / range * innerH;
85
+ const xFor = (i) => padding + i * stepX;
86
+ const points = data.map((v, i) => ({ x: xFor(i), y: yFor(v) }));
87
+ const linePath = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(2)} ${p.y.toFixed(2)}`).join(" ");
88
+ const areaPath = `${linePath} L${points[points.length - 1].x.toFixed(2)} ${(height - padding).toFixed(
89
+ 2
90
+ )} L${points[0].x.toFixed(2)} ${(height - padding).toFixed(2)} Z`;
91
+ const stroke = color ?? "currentColor";
92
+ return /* @__PURE__ */ jsxRuntime.jsx(
93
+ "div",
94
+ {
95
+ ref,
96
+ "data-slot": "sparkline",
97
+ "data-variant": variant,
98
+ "data-trend": effectiveTrend,
99
+ role: ariaLabel ? "img" : void 0,
100
+ "aria-label": ariaLabel,
101
+ "aria-hidden": ariaLabel ? void 0 : true,
102
+ className: cn("inline-block align-middle", trendColorClass, className),
103
+ style: { width, height },
104
+ ...props,
105
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
106
+ "svg",
107
+ {
108
+ width,
109
+ height,
110
+ viewBox: `0 0 ${width} ${height}`,
111
+ preserveAspectRatio: "none",
112
+ focusable: "false",
113
+ children: [
114
+ variant === "area" && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: stroke, opacity: 0.18 }),
115
+ (variant === "line" || variant === "area") && /* @__PURE__ */ jsxRuntime.jsx(
116
+ "path",
117
+ {
118
+ d: linePath,
119
+ fill: "none",
120
+ stroke,
121
+ strokeWidth,
122
+ strokeLinecap: "round",
123
+ strokeLinejoin: "round",
124
+ vectorEffect: "non-scaling-stroke"
125
+ }
126
+ ),
127
+ variant === "bars" && data.map((v, i) => {
128
+ const gap = barGap;
129
+ const barW = Math.max(0, stepX - gap);
130
+ const y = yFor(v);
131
+ const barH = Math.max(1, height - padding - y);
132
+ const x = xFor(i) - barW / 2;
133
+ return /* @__PURE__ */ jsxRuntime.jsx(
134
+ "rect",
135
+ {
136
+ x: x.toFixed(2),
137
+ y: y.toFixed(2),
138
+ width: barW.toFixed(2),
139
+ height: barH.toFixed(2),
140
+ rx: Math.min(1, barW / 3),
141
+ fill: stroke
142
+ },
143
+ i
144
+ );
145
+ }),
146
+ showEndDot && variant !== "bars" && /* @__PURE__ */ jsxRuntime.jsx(
147
+ "circle",
148
+ {
149
+ cx: points[points.length - 1].x.toFixed(2),
150
+ cy: points[points.length - 1].y.toFixed(2),
151
+ r: strokeWidth + 0.5,
152
+ fill: stroke
153
+ }
154
+ )
155
+ ]
156
+ }
157
+ )
158
+ }
159
+ );
160
+ }
161
+ );
162
+ Sparkline.displayName = "Sparkline";
163
+
164
+ exports.Sparkline = Sparkline;
12
165
  //# sourceMappingURL=sparkline.cjs.map
13
166
  //# sourceMappingURL=sparkline.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"sparkline.cjs"}
1
+ {"version":3,"sources":["../../../src/lib/utils.ts","../../../src/components/ui/sparkline.tsx"],"names":["twMerge","clsx","React","jsx","jsxs"],"mappings":"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","file":"sparkline.cjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\nimport { formatJalaliDate } from '@/lib/jalali-utils'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\nexport type SupportedLocale = 'fa' | 'ar' | 'en'\n\n/**\n * Convert digits in a string to Persian/Arabic numerals based on locale.\n * @example convertToLocalNumbers('123', 'fa') => '۱۲۳'\n * @example convertToLocalNumbers('123', 'en') => '123'\n */\nexport function convertToLocalNumbers(text: string | number, locale: SupportedLocale): string {\n if (locale === 'fa' || locale === 'ar') {\n const persianDigits = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']\n return String(text).replace(/\\d/g, (digit) => persianDigits[parseInt(digit)])\n }\n return String(text)\n}\n\n/**\n * Format large numbers with locale-aware suffixes (K/M/B).\n * @example formatLargeNumber(1500, 'fa') => '۱.۵ هزار'\n * @example formatLargeNumber(1500, 'en') => '1.5K'\n */\nexport function formatLargeNumber(num: number, locale: SupportedLocale): string {\n if (num >= 1_000_000_000) {\n const formatted = (num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'B' : ' میلیارد')\n }\n if (num >= 1_000_000) {\n const formatted = (num / 1_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'M' : ' میلیون')\n }\n if (num >= 1_000) {\n const formatted = (num / 1_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'K' : ' هزار')\n }\n return convertToLocalNumbers(num.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ','), locale)\n}\n\n/**\n * Format number to Instagram-style short format (English only).\n * @example formatNumber(123456, 'short') => '123K'\n * @example formatNumber(123456, 'exact') => '123,456'\n */\nexport function formatNumber(num: number | undefined, format: 'exact' | 'short' = 'exact'): string {\n if (num === undefined || num === null) return '0'\n\n if (format === 'exact') {\n return num.toLocaleString('en-US')\n }\n\n // Short format (Instagram style)\n if (num >= 1_000_000_000) {\n return `${(num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')}B`\n }\n if (num >= 1_000_000) {\n return `${(num / 1_000_000).toFixed(1).replace(/\\.0$/, '')}M`\n }\n if (num >= 1_000) {\n return `${(num / 1_000).toFixed(1).replace(/\\.0$/, '')}K`\n }\n return num.toString()\n}\n\n/**\n * Format date to relative time with absolute on hover (Persian)\n * @example formatRelativeTime(new Date()) => '۲ ساعت پیش'\n */\nexport function formatRelativeTime(date: Date | string | number): string {\n const now = new Date()\n const then = new Date(date)\n const diffInSeconds = Math.floor((now.getTime() - then.getTime()) / 1000)\n\n if (diffInSeconds < 60) {\n return 'همین الان'\n }\n\n const diffInMinutes = Math.floor(diffInSeconds / 60)\n if (diffInMinutes < 60) {\n return `${convertToLocalNumbers(diffInMinutes, 'fa')} دقیقه پیش`\n }\n\n const diffInHours = Math.floor(diffInMinutes / 60)\n if (diffInHours < 24) {\n return `${convertToLocalNumbers(diffInHours, 'fa')} ساعت پیش`\n }\n\n const diffInDays = Math.floor(diffInHours / 24)\n if (diffInDays < 7) {\n return `${convertToLocalNumbers(diffInDays, 'fa')} روز پیش`\n }\n\n const diffInWeeks = Math.floor(diffInDays / 7)\n if (diffInWeeks < 4) {\n return `${convertToLocalNumbers(diffInWeeks, 'fa')} هفته پیش`\n }\n\n const diffInMonths = Math.floor(diffInDays / 30)\n if (diffInMonths < 12) {\n return `${convertToLocalNumbers(diffInMonths, 'fa')} ماه پیش`\n }\n\n const diffInYears = Math.floor(diffInDays / 365)\n return `${convertToLocalNumbers(diffInYears, 'fa')} سال پیش`\n}\n\n/**\n * Format date to absolute format (Persian / Jalali)\n * Uses date-fns-jalali for accurate Jalali conversion.\n * @example formatAbsoluteTime(new Date()) => '۱۵ دی ۱۴۰۳، ۱۵:۳۰'\n */\nexport function formatAbsoluteTime(date: Date | string | number): string {\n const d = new Date(date)\n return formatJalaliDate(d, 'd MMMM yyyy، HH:mm')\n}\n","'use client'\n\nimport * as React from 'react'\nimport { cn } from '@/lib/utils'\n\nexport type SparklineTrend = 'up' | 'down' | 'neutral' | 'auto'\nexport type SparklineVariant = 'line' | 'area' | 'bars'\n\nexport interface SparklineProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Array of numeric data points. Must have at least 2 items to render line/area. */\n data: number[]\n /** Visual style @default \"line\" */\n variant?: SparklineVariant\n /**\n * Trend colour. `\"auto\"` compares first and last point:\n * last > first → up, last < first → down, equal → neutral.\n * Pass an explicit value to override.\n * @default \"auto\"\n */\n trend?: SparklineTrend\n /** Width in px. Also used as SVG viewBox width — output scales to parent when CSS overrides. @default 80 */\n width?: number\n /** Height in px @default 24 */\n height?: number\n /** Line / bar stroke width @default 1.5 */\n strokeWidth?: number\n /** Show a filled dot at the last point */\n showEndDot?: boolean\n /** Padding inside the viewBox so strokes/dots are not clipped @default 2 */\n padding?: number\n /** Override color with any CSS value (e.g. `\"hsl(var(--brand))\"`). Takes precedence over `trend`. */\n color?: string\n /** For bars variant — gap between bars in user units @default 1 */\n barGap?: number\n /** aria-label for screen readers — describe the trend / metric */\n 'aria-label'?: string\n}\n\nconst TREND_CLASSES: Record<Exclude<SparklineTrend, 'auto'>, string> = {\n up: 'text-[hsl(var(--sentiment-positive))]',\n down: 'text-[hsl(var(--sentiment-negative))]',\n neutral: 'text-[hsl(var(--sentiment-neutral))]',\n}\n\nfunction resolveTrend(data: number[], trend: SparklineTrend): Exclude<SparklineTrend, 'auto'> {\n if (trend !== 'auto') return trend\n if (data.length < 2) return 'neutral'\n const first = data[0]\n const last = data[data.length - 1]\n if (last > first) return 'up'\n if (last < first) return 'down'\n return 'neutral'\n}\n\nconst Sparkline = React.forwardRef<HTMLDivElement, SparklineProps>(\n (\n {\n className,\n data,\n variant = 'line',\n trend = 'auto',\n width = 80,\n height = 24,\n strokeWidth = 1.5,\n showEndDot = false,\n padding = 2,\n color,\n barGap = 1,\n 'aria-label': ariaLabel,\n ...props\n },\n ref\n ) => {\n const effectiveTrend = resolveTrend(data, trend)\n const trendColorClass = color ? undefined : TREND_CLASSES[effectiveTrend]\n\n if (data.length === 0) {\n return (\n <div\n ref={ref}\n data-slot=\"sparkline\"\n data-empty=\"true\"\n aria-hidden=\"true\"\n className={cn('inline-block', className)}\n style={{ width, height }}\n {...props}\n />\n )\n }\n\n const min = Math.min(...data)\n const max = Math.max(...data)\n const range = max - min || 1\n const innerW = width - padding * 2\n const innerH = height - padding * 2\n const stepX = data.length > 1 ? innerW / (data.length - 1) : 0\n const yFor = (v: number) => padding + innerH - ((v - min) / range) * innerH\n const xFor = (i: number) => padding + i * stepX\n\n const points = data.map((v, i) => ({ x: xFor(i), y: yFor(v) }))\n const linePath = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x.toFixed(2)} ${p.y.toFixed(2)}`).join(' ')\n const areaPath = `${linePath} L${points[points.length - 1].x.toFixed(2)} ${(height - padding).toFixed(\n 2\n )} L${points[0].x.toFixed(2)} ${(height - padding).toFixed(2)} Z`\n\n const stroke = color ?? 'currentColor'\n\n return (\n <div\n ref={ref}\n data-slot=\"sparkline\"\n data-variant={variant}\n data-trend={effectiveTrend}\n role={ariaLabel ? 'img' : undefined}\n aria-label={ariaLabel}\n aria-hidden={ariaLabel ? undefined : true}\n className={cn('inline-block align-middle', trendColorClass, className)}\n style={{ width, height }}\n {...props}\n >\n <svg\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n >\n {variant === 'area' && <path d={areaPath} fill={stroke} opacity={0.18} />}\n {(variant === 'line' || variant === 'area') && (\n <path\n d={linePath}\n fill=\"none\"\n stroke={stroke}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n vectorEffect=\"non-scaling-stroke\"\n />\n )}\n {variant === 'bars' &&\n data.map((v, i) => {\n const gap = barGap\n const barW = Math.max(0, stepX - gap)\n const y = yFor(v)\n const barH = Math.max(1, height - padding - y)\n const x = xFor(i) - barW / 2\n return (\n <rect\n key={i}\n x={x.toFixed(2)}\n y={y.toFixed(2)}\n width={barW.toFixed(2)}\n height={barH.toFixed(2)}\n rx={Math.min(1, barW / 3)}\n fill={stroke}\n />\n )\n })}\n {showEndDot && variant !== 'bars' && (\n <circle\n cx={points[points.length - 1].x.toFixed(2)}\n cy={points[points.length - 1].y.toFixed(2)}\n r={strokeWidth + 0.5}\n fill={stroke}\n />\n )}\n </svg>\n </div>\n )\n }\n)\nSparkline.displayName = 'Sparkline'\n\nexport { Sparkline }\n"]}
@@ -1,4 +1,144 @@
1
- export { Sparkline } from '../../chunk-YC5KLN6I.js';
2
- import '../../chunk-4SVQNEVH.js';
1
+ 'use client';
2
+ import * as React from 'react';
3
+ import { clsx } from 'clsx';
4
+ import { twMerge } from 'tailwind-merge';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
+
7
+ function cn(...inputs) {
8
+ return twMerge(clsx(inputs));
9
+ }
10
+ var TREND_CLASSES = {
11
+ up: "text-[hsl(var(--sentiment-positive))]",
12
+ down: "text-[hsl(var(--sentiment-negative))]",
13
+ neutral: "text-[hsl(var(--sentiment-neutral))]"
14
+ };
15
+ function resolveTrend(data, trend) {
16
+ if (trend !== "auto") return trend;
17
+ if (data.length < 2) return "neutral";
18
+ const first = data[0];
19
+ const last = data[data.length - 1];
20
+ if (last > first) return "up";
21
+ if (last < first) return "down";
22
+ return "neutral";
23
+ }
24
+ var Sparkline = React.forwardRef(
25
+ ({
26
+ className,
27
+ data,
28
+ variant = "line",
29
+ trend = "auto",
30
+ width = 80,
31
+ height = 24,
32
+ strokeWidth = 1.5,
33
+ showEndDot = false,
34
+ padding = 2,
35
+ color,
36
+ barGap = 1,
37
+ "aria-label": ariaLabel,
38
+ ...props
39
+ }, ref) => {
40
+ const effectiveTrend = resolveTrend(data, trend);
41
+ const trendColorClass = color ? void 0 : TREND_CLASSES[effectiveTrend];
42
+ if (data.length === 0) {
43
+ return /* @__PURE__ */ jsx(
44
+ "div",
45
+ {
46
+ ref,
47
+ "data-slot": "sparkline",
48
+ "data-empty": "true",
49
+ "aria-hidden": "true",
50
+ className: cn("inline-block", className),
51
+ style: { width, height },
52
+ ...props
53
+ }
54
+ );
55
+ }
56
+ const min = Math.min(...data);
57
+ const max = Math.max(...data);
58
+ const range = max - min || 1;
59
+ const innerW = width - padding * 2;
60
+ const innerH = height - padding * 2;
61
+ const stepX = data.length > 1 ? innerW / (data.length - 1) : 0;
62
+ const yFor = (v) => padding + innerH - (v - min) / range * innerH;
63
+ const xFor = (i) => padding + i * stepX;
64
+ const points = data.map((v, i) => ({ x: xFor(i), y: yFor(v) }));
65
+ const linePath = points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x.toFixed(2)} ${p.y.toFixed(2)}`).join(" ");
66
+ const areaPath = `${linePath} L${points[points.length - 1].x.toFixed(2)} ${(height - padding).toFixed(
67
+ 2
68
+ )} L${points[0].x.toFixed(2)} ${(height - padding).toFixed(2)} Z`;
69
+ const stroke = color ?? "currentColor";
70
+ return /* @__PURE__ */ jsx(
71
+ "div",
72
+ {
73
+ ref,
74
+ "data-slot": "sparkline",
75
+ "data-variant": variant,
76
+ "data-trend": effectiveTrend,
77
+ role: ariaLabel ? "img" : void 0,
78
+ "aria-label": ariaLabel,
79
+ "aria-hidden": ariaLabel ? void 0 : true,
80
+ className: cn("inline-block align-middle", trendColorClass, className),
81
+ style: { width, height },
82
+ ...props,
83
+ children: /* @__PURE__ */ jsxs(
84
+ "svg",
85
+ {
86
+ width,
87
+ height,
88
+ viewBox: `0 0 ${width} ${height}`,
89
+ preserveAspectRatio: "none",
90
+ focusable: "false",
91
+ children: [
92
+ variant === "area" && /* @__PURE__ */ jsx("path", { d: areaPath, fill: stroke, opacity: 0.18 }),
93
+ (variant === "line" || variant === "area") && /* @__PURE__ */ jsx(
94
+ "path",
95
+ {
96
+ d: linePath,
97
+ fill: "none",
98
+ stroke,
99
+ strokeWidth,
100
+ strokeLinecap: "round",
101
+ strokeLinejoin: "round",
102
+ vectorEffect: "non-scaling-stroke"
103
+ }
104
+ ),
105
+ variant === "bars" && data.map((v, i) => {
106
+ const gap = barGap;
107
+ const barW = Math.max(0, stepX - gap);
108
+ const y = yFor(v);
109
+ const barH = Math.max(1, height - padding - y);
110
+ const x = xFor(i) - barW / 2;
111
+ return /* @__PURE__ */ jsx(
112
+ "rect",
113
+ {
114
+ x: x.toFixed(2),
115
+ y: y.toFixed(2),
116
+ width: barW.toFixed(2),
117
+ height: barH.toFixed(2),
118
+ rx: Math.min(1, barW / 3),
119
+ fill: stroke
120
+ },
121
+ i
122
+ );
123
+ }),
124
+ showEndDot && variant !== "bars" && /* @__PURE__ */ jsx(
125
+ "circle",
126
+ {
127
+ cx: points[points.length - 1].x.toFixed(2),
128
+ cy: points[points.length - 1].y.toFixed(2),
129
+ r: strokeWidth + 0.5,
130
+ fill: stroke
131
+ }
132
+ )
133
+ ]
134
+ }
135
+ )
136
+ }
137
+ );
138
+ }
139
+ );
140
+ Sparkline.displayName = "Sparkline";
141
+
142
+ export { Sparkline };
3
143
  //# sourceMappingURL=sparkline.js.map
4
144
  //# sourceMappingURL=sparkline.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"sparkline.js"}
1
+ {"version":3,"sources":["../../../src/lib/utils.ts","../../../src/components/ui/sparkline.tsx"],"names":[],"mappings":"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","file":"sparkline.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\nimport { formatJalaliDate } from '@/lib/jalali-utils'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\nexport type SupportedLocale = 'fa' | 'ar' | 'en'\n\n/**\n * Convert digits in a string to Persian/Arabic numerals based on locale.\n * @example convertToLocalNumbers('123', 'fa') => '۱۲۳'\n * @example convertToLocalNumbers('123', 'en') => '123'\n */\nexport function convertToLocalNumbers(text: string | number, locale: SupportedLocale): string {\n if (locale === 'fa' || locale === 'ar') {\n const persianDigits = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']\n return String(text).replace(/\\d/g, (digit) => persianDigits[parseInt(digit)])\n }\n return String(text)\n}\n\n/**\n * Format large numbers with locale-aware suffixes (K/M/B).\n * @example formatLargeNumber(1500, 'fa') => '۱.۵ هزار'\n * @example formatLargeNumber(1500, 'en') => '1.5K'\n */\nexport function formatLargeNumber(num: number, locale: SupportedLocale): string {\n if (num >= 1_000_000_000) {\n const formatted = (num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'B' : ' میلیارد')\n }\n if (num >= 1_000_000) {\n const formatted = (num / 1_000_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'M' : ' میلیون')\n }\n if (num >= 1_000) {\n const formatted = (num / 1_000).toFixed(1).replace(/\\.0$/, '')\n return convertToLocalNumbers(formatted, locale) + (locale === 'en' ? 'K' : ' هزار')\n }\n return convertToLocalNumbers(num.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ','), locale)\n}\n\n/**\n * Format number to Instagram-style short format (English only).\n * @example formatNumber(123456, 'short') => '123K'\n * @example formatNumber(123456, 'exact') => '123,456'\n */\nexport function formatNumber(num: number | undefined, format: 'exact' | 'short' = 'exact'): string {\n if (num === undefined || num === null) return '0'\n\n if (format === 'exact') {\n return num.toLocaleString('en-US')\n }\n\n // Short format (Instagram style)\n if (num >= 1_000_000_000) {\n return `${(num / 1_000_000_000).toFixed(1).replace(/\\.0$/, '')}B`\n }\n if (num >= 1_000_000) {\n return `${(num / 1_000_000).toFixed(1).replace(/\\.0$/, '')}M`\n }\n if (num >= 1_000) {\n return `${(num / 1_000).toFixed(1).replace(/\\.0$/, '')}K`\n }\n return num.toString()\n}\n\n/**\n * Format date to relative time with absolute on hover (Persian)\n * @example formatRelativeTime(new Date()) => '۲ ساعت پیش'\n */\nexport function formatRelativeTime(date: Date | string | number): string {\n const now = new Date()\n const then = new Date(date)\n const diffInSeconds = Math.floor((now.getTime() - then.getTime()) / 1000)\n\n if (diffInSeconds < 60) {\n return 'همین الان'\n }\n\n const diffInMinutes = Math.floor(diffInSeconds / 60)\n if (diffInMinutes < 60) {\n return `${convertToLocalNumbers(diffInMinutes, 'fa')} دقیقه پیش`\n }\n\n const diffInHours = Math.floor(diffInMinutes / 60)\n if (diffInHours < 24) {\n return `${convertToLocalNumbers(diffInHours, 'fa')} ساعت پیش`\n }\n\n const diffInDays = Math.floor(diffInHours / 24)\n if (diffInDays < 7) {\n return `${convertToLocalNumbers(diffInDays, 'fa')} روز پیش`\n }\n\n const diffInWeeks = Math.floor(diffInDays / 7)\n if (diffInWeeks < 4) {\n return `${convertToLocalNumbers(diffInWeeks, 'fa')} هفته پیش`\n }\n\n const diffInMonths = Math.floor(diffInDays / 30)\n if (diffInMonths < 12) {\n return `${convertToLocalNumbers(diffInMonths, 'fa')} ماه پیش`\n }\n\n const diffInYears = Math.floor(diffInDays / 365)\n return `${convertToLocalNumbers(diffInYears, 'fa')} سال پیش`\n}\n\n/**\n * Format date to absolute format (Persian / Jalali)\n * Uses date-fns-jalali for accurate Jalali conversion.\n * @example formatAbsoluteTime(new Date()) => '۱۵ دی ۱۴۰۳، ۱۵:۳۰'\n */\nexport function formatAbsoluteTime(date: Date | string | number): string {\n const d = new Date(date)\n return formatJalaliDate(d, 'd MMMM yyyy، HH:mm')\n}\n","'use client'\n\nimport * as React from 'react'\nimport { cn } from '@/lib/utils'\n\nexport type SparklineTrend = 'up' | 'down' | 'neutral' | 'auto'\nexport type SparklineVariant = 'line' | 'area' | 'bars'\n\nexport interface SparklineProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Array of numeric data points. Must have at least 2 items to render line/area. */\n data: number[]\n /** Visual style @default \"line\" */\n variant?: SparklineVariant\n /**\n * Trend colour. `\"auto\"` compares first and last point:\n * last > first → up, last < first → down, equal → neutral.\n * Pass an explicit value to override.\n * @default \"auto\"\n */\n trend?: SparklineTrend\n /** Width in px. Also used as SVG viewBox width — output scales to parent when CSS overrides. @default 80 */\n width?: number\n /** Height in px @default 24 */\n height?: number\n /** Line / bar stroke width @default 1.5 */\n strokeWidth?: number\n /** Show a filled dot at the last point */\n showEndDot?: boolean\n /** Padding inside the viewBox so strokes/dots are not clipped @default 2 */\n padding?: number\n /** Override color with any CSS value (e.g. `\"hsl(var(--brand))\"`). Takes precedence over `trend`. */\n color?: string\n /** For bars variant — gap between bars in user units @default 1 */\n barGap?: number\n /** aria-label for screen readers — describe the trend / metric */\n 'aria-label'?: string\n}\n\nconst TREND_CLASSES: Record<Exclude<SparklineTrend, 'auto'>, string> = {\n up: 'text-[hsl(var(--sentiment-positive))]',\n down: 'text-[hsl(var(--sentiment-negative))]',\n neutral: 'text-[hsl(var(--sentiment-neutral))]',\n}\n\nfunction resolveTrend(data: number[], trend: SparklineTrend): Exclude<SparklineTrend, 'auto'> {\n if (trend !== 'auto') return trend\n if (data.length < 2) return 'neutral'\n const first = data[0]\n const last = data[data.length - 1]\n if (last > first) return 'up'\n if (last < first) return 'down'\n return 'neutral'\n}\n\nconst Sparkline = React.forwardRef<HTMLDivElement, SparklineProps>(\n (\n {\n className,\n data,\n variant = 'line',\n trend = 'auto',\n width = 80,\n height = 24,\n strokeWidth = 1.5,\n showEndDot = false,\n padding = 2,\n color,\n barGap = 1,\n 'aria-label': ariaLabel,\n ...props\n },\n ref\n ) => {\n const effectiveTrend = resolveTrend(data, trend)\n const trendColorClass = color ? undefined : TREND_CLASSES[effectiveTrend]\n\n if (data.length === 0) {\n return (\n <div\n ref={ref}\n data-slot=\"sparkline\"\n data-empty=\"true\"\n aria-hidden=\"true\"\n className={cn('inline-block', className)}\n style={{ width, height }}\n {...props}\n />\n )\n }\n\n const min = Math.min(...data)\n const max = Math.max(...data)\n const range = max - min || 1\n const innerW = width - padding * 2\n const innerH = height - padding * 2\n const stepX = data.length > 1 ? innerW / (data.length - 1) : 0\n const yFor = (v: number) => padding + innerH - ((v - min) / range) * innerH\n const xFor = (i: number) => padding + i * stepX\n\n const points = data.map((v, i) => ({ x: xFor(i), y: yFor(v) }))\n const linePath = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x.toFixed(2)} ${p.y.toFixed(2)}`).join(' ')\n const areaPath = `${linePath} L${points[points.length - 1].x.toFixed(2)} ${(height - padding).toFixed(\n 2\n )} L${points[0].x.toFixed(2)} ${(height - padding).toFixed(2)} Z`\n\n const stroke = color ?? 'currentColor'\n\n return (\n <div\n ref={ref}\n data-slot=\"sparkline\"\n data-variant={variant}\n data-trend={effectiveTrend}\n role={ariaLabel ? 'img' : undefined}\n aria-label={ariaLabel}\n aria-hidden={ariaLabel ? undefined : true}\n className={cn('inline-block align-middle', trendColorClass, className)}\n style={{ width, height }}\n {...props}\n >\n <svg\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n preserveAspectRatio=\"none\"\n focusable=\"false\"\n >\n {variant === 'area' && <path d={areaPath} fill={stroke} opacity={0.18} />}\n {(variant === 'line' || variant === 'area') && (\n <path\n d={linePath}\n fill=\"none\"\n stroke={stroke}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n vectorEffect=\"non-scaling-stroke\"\n />\n )}\n {variant === 'bars' &&\n data.map((v, i) => {\n const gap = barGap\n const barW = Math.max(0, stepX - gap)\n const y = yFor(v)\n const barH = Math.max(1, height - padding - y)\n const x = xFor(i) - barW / 2\n return (\n <rect\n key={i}\n x={x.toFixed(2)}\n y={y.toFixed(2)}\n width={barW.toFixed(2)}\n height={barH.toFixed(2)}\n rx={Math.min(1, barW / 3)}\n fill={stroke}\n />\n )\n })}\n {showEndDot && variant !== 'bars' && (\n <circle\n cx={points[points.length - 1].x.toFixed(2)}\n cy={points[points.length - 1].y.toFixed(2)}\n r={strokeWidth + 0.5}\n fill={stroke}\n />\n )}\n </svg>\n </div>\n )\n }\n)\nSparkline.displayName = 'Sparkline'\n\nexport { Sparkline }\n"]}