love-ui 1.2.12 → 1.2.14

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 (988) hide show
  1. package/dist/index.js +8 -7
  2. package/dist/mcp-server.js +1 -1
  3. package/package.json +3 -2
  4. package/packages/loveui-skills/SKILL.md +99 -0
  5. package/packages/loveui-skills/agents/openai.yaml +11 -0
  6. package/packages/loveui-skills/references/design-directions.md +60 -0
  7. package/packages/loveui-skills/references/mcp-catalog-workflow.md +68 -0
  8. package/packages/loveui-skills/references/page-blueprints.md +76 -0
  9. package/packages/loveui-skills/references/quality-gates.md +51 -0
  10. package/public/r/accordion-controlled.json +1 -1
  11. package/public/r/accordion-demo.json +1 -1
  12. package/public/r/accordion-multiple.json +1 -1
  13. package/public/r/accordion-single.json +1 -1
  14. package/public/r/alert-demo.json +1 -1
  15. package/public/r/alert-dialog-demo.json +1 -1
  16. package/public/r/alert-error.json +1 -1
  17. package/public/r/alert-info.json +1 -1
  18. package/public/r/alert-success.json +1 -1
  19. package/public/r/alert-warning.json +1 -1
  20. package/public/r/alert-with-icon-action.json +1 -1
  21. package/public/r/alert-with-icon.json +1 -1
  22. package/public/r/announcement-tagless.json +1 -1
  23. package/public/r/announcement-themes.json +1 -1
  24. package/public/r/announcement.json +1 -1
  25. package/public/r/autocomplete-async.json +1 -1
  26. package/public/r/autocomplete-autohighlight.json +1 -1
  27. package/public/r/autocomplete-demo.json +1 -1
  28. package/public/r/autocomplete-disabled.json +1 -1
  29. package/public/r/autocomplete-form.json +1 -1
  30. package/public/r/autocomplete-grouped.json +1 -1
  31. package/public/r/autocomplete-inline.json +1 -1
  32. package/public/r/autocomplete-lg.json +1 -1
  33. package/public/r/autocomplete-limit.json +1 -1
  34. package/public/r/autocomplete-sm.json +1 -1
  35. package/public/r/autocomplete-with-clear.json +1 -1
  36. package/public/r/autocomplete-with-label.json +1 -1
  37. package/public/r/autocomplete-with-trigger-clear.json +1 -1
  38. package/public/r/avatar-demo.json +1 -1
  39. package/public/r/avatar-fallback.json +1 -1
  40. package/public/r/avatar-group.json +1 -1
  41. package/public/r/avatar-radius.json +1 -1
  42. package/public/r/avatar-size.json +1 -1
  43. package/public/r/avatar-stack-hover.json +1 -1
  44. package/public/r/avatar-stack.json +1 -1
  45. package/public/r/badge-demo.json +1 -1
  46. package/public/r/badge-destructive.json +1 -1
  47. package/public/r/badge-error.json +1 -1
  48. package/public/r/badge-info.json +1 -1
  49. package/public/r/badge-lg.json +1 -1
  50. package/public/r/badge-outline.json +1 -1
  51. package/public/r/badge-secondary.json +1 -1
  52. package/public/r/badge-sm.json +1 -1
  53. package/public/r/badge-success.json +1 -1
  54. package/public/r/badge-warning.json +1 -1
  55. package/public/r/badge-with-icon.json +1 -1
  56. package/public/r/badge-with-link.json +1 -1
  57. package/public/r/banner-inset.json +1 -1
  58. package/public/r/banner-themes.json +1 -1
  59. package/public/r/banner.json +1 -1
  60. package/public/r/bookmarks.json +206 -0
  61. package/public/r/breadcrumb-custom-separator.json +1 -1
  62. package/public/r/breadcrumb-demo.json +1 -1
  63. package/public/r/button-demo.json +1 -1
  64. package/public/r/button-destructive-outline.json +1 -1
  65. package/public/r/button-destructive.json +1 -1
  66. package/public/r/button-disabled.json +1 -1
  67. package/public/r/button-ghost.json +1 -1
  68. package/public/r/button-lg.json +1 -1
  69. package/public/r/button-link.json +1 -1
  70. package/public/r/button-loading.json +1 -1
  71. package/public/r/button-outline.json +1 -1
  72. package/public/r/button-secondary.json +1 -1
  73. package/public/r/button-sm.json +1 -1
  74. package/public/r/button-with-icon.json +1 -1
  75. package/public/r/button-with-link.json +1 -1
  76. package/public/r/button-xl.json +1 -1
  77. package/public/r/button-xs.json +1 -1
  78. package/public/r/calendar-headless.json +1 -1
  79. package/public/r/calendar-rac.json +16 -0
  80. package/public/r/calendar.json +1 -1
  81. package/public/r/card-demo.json +1 -1
  82. package/public/r/chart.json +15 -0
  83. package/public/r/checkbox-card.json +1 -1
  84. package/public/r/checkbox-demo.json +1 -1
  85. package/public/r/checkbox-disabled.json +1 -1
  86. package/public/r/checkbox-form.json +1 -1
  87. package/public/r/checkbox-group-demo.json +1 -1
  88. package/public/r/checkbox-group-disabled.json +1 -1
  89. package/public/r/checkbox-group-form.json +1 -1
  90. package/public/r/checkbox-group-nested-parent.json +1 -1
  91. package/public/r/checkbox-group-parent.json +1 -1
  92. package/public/r/checkbox-tree.json +12 -0
  93. package/public/r/checkbox-with-description.json +1 -1
  94. package/public/r/choicebox-inline.json +1 -1
  95. package/public/r/choicebox.json +1 -1
  96. package/public/r/codebase.json +1 -1
  97. package/public/r/collaborative-canvas.json +1 -1
  98. package/public/r/collapsible-demo.json +1 -1
  99. package/public/r/combobox-autohighlight.json +1 -1
  100. package/public/r/combobox-controlled.json +1 -1
  101. package/public/r/combobox-create-new.json +1 -1
  102. package/public/r/combobox-demo.json +1 -1
  103. package/public/r/combobox-disabled.json +1 -1
  104. package/public/r/combobox-fixed-width.json +1 -1
  105. package/public/r/combobox-form.json +1 -1
  106. package/public/r/combobox-grouped.json +1 -1
  107. package/public/r/combobox-lg.json +1 -1
  108. package/public/r/combobox-multiple-form.json +1 -1
  109. package/public/r/combobox-multiple.json +1 -1
  110. package/public/r/combobox-sm.json +1 -1
  111. package/public/r/combobox-with-clear.json +1 -1
  112. package/public/r/combobox-with-inner-input.json +1 -1
  113. package/public/r/combobox-with-label.json +1 -1
  114. package/public/r/command.json +18 -0
  115. package/public/r/comp-01.json +22 -0
  116. package/public/r/comp-02.json +23 -0
  117. package/public/r/comp-03.json +23 -0
  118. package/public/r/comp-04.json +23 -0
  119. package/public/r/comp-05.json +22 -0
  120. package/public/r/comp-06.json +23 -0
  121. package/public/r/comp-07.json +22 -0
  122. package/public/r/comp-08.json +23 -0
  123. package/public/r/comp-09.json +22 -0
  124. package/public/r/comp-10.json +22 -0
  125. package/public/r/comp-100.json +23 -0
  126. package/public/r/comp-101.json +23 -0
  127. package/public/r/comp-102.json +23 -0
  128. package/public/r/comp-103.json +23 -0
  129. package/public/r/comp-104.json +23 -0
  130. package/public/r/comp-105.json +23 -0
  131. package/public/r/comp-106.json +22 -0
  132. package/public/r/comp-107.json +22 -0
  133. package/public/r/comp-108.json +23 -0
  134. package/public/r/comp-109.json +22 -0
  135. package/public/r/comp-11.json +22 -0
  136. package/public/r/comp-110.json +22 -0
  137. package/public/r/comp-111.json +21 -0
  138. package/public/r/comp-112.json +21 -0
  139. package/public/r/comp-113.json +22 -0
  140. package/public/r/comp-114.json +23 -0
  141. package/public/r/comp-115.json +22 -0
  142. package/public/r/comp-116.json +22 -0
  143. package/public/r/comp-117.json +23 -0
  144. package/public/r/comp-118.json +23 -0
  145. package/public/r/comp-119.json +27 -0
  146. package/public/r/comp-12.json +22 -0
  147. package/public/r/comp-120.json +27 -0
  148. package/public/r/comp-121.json +27 -0
  149. package/public/r/comp-122.json +27 -0
  150. package/public/r/comp-123.json +22 -0
  151. package/public/r/comp-124.json +22 -0
  152. package/public/r/comp-125.json +31 -0
  153. package/public/r/comp-126.json +31 -0
  154. package/public/r/comp-127.json +21 -0
  155. package/public/r/comp-128.json +21 -0
  156. package/public/r/comp-129.json +24 -0
  157. package/public/r/comp-13.json +22 -0
  158. package/public/r/comp-130.json +23 -0
  159. package/public/r/comp-131.json +23 -0
  160. package/public/r/comp-132.json +23 -0
  161. package/public/r/comp-133.json +23 -0
  162. package/public/r/comp-134.json +23 -0
  163. package/public/r/comp-135.json +24 -0
  164. package/public/r/comp-136.json +23 -0
  165. package/public/r/comp-137.json +23 -0
  166. package/public/r/comp-138.json +25 -0
  167. package/public/r/comp-139.json +23 -0
  168. package/public/r/comp-14.json +22 -0
  169. package/public/r/comp-140.json +23 -0
  170. package/public/r/comp-141.json +23 -0
  171. package/public/r/comp-142.json +25 -0
  172. package/public/r/comp-143.json +23 -0
  173. package/public/r/comp-144.json +24 -0
  174. package/public/r/comp-145.json +24 -0
  175. package/public/r/comp-146.json +24 -0
  176. package/public/r/comp-147.json +24 -0
  177. package/public/r/comp-148.json +25 -0
  178. package/public/r/comp-149.json +24 -0
  179. package/public/r/comp-15.json +22 -0
  180. package/public/r/comp-150.json +21 -0
  181. package/public/r/comp-151.json +23 -0
  182. package/public/r/comp-152.json +23 -0
  183. package/public/r/comp-153.json +23 -0
  184. package/public/r/comp-154.json +23 -0
  185. package/public/r/comp-155.json +23 -0
  186. package/public/r/comp-156.json +25 -0
  187. package/public/r/comp-157.json +27 -0
  188. package/public/r/comp-158.json +24 -0
  189. package/public/r/comp-159.json +24 -0
  190. package/public/r/comp-16.json +22 -0
  191. package/public/r/comp-160.json +24 -0
  192. package/public/r/comp-161.json +24 -0
  193. package/public/r/comp-162.json +24 -0
  194. package/public/r/comp-163.json +28 -0
  195. package/public/r/comp-164.json +24 -0
  196. package/public/r/comp-165.json +24 -0
  197. package/public/r/comp-166.json +25 -0
  198. package/public/r/comp-167.json +24 -0
  199. package/public/r/comp-168.json +24 -0
  200. package/public/r/comp-169.json +23 -0
  201. package/public/r/comp-17.json +25 -0
  202. package/public/r/comp-170.json +25 -0
  203. package/public/r/comp-171.json +28 -0
  204. package/public/r/comp-172.json +23 -0
  205. package/public/r/comp-173.json +23 -0
  206. package/public/r/comp-174.json +23 -0
  207. package/public/r/comp-175.json +23 -0
  208. package/public/r/comp-176.json +23 -0
  209. package/public/r/comp-177.json +23 -0
  210. package/public/r/comp-178.json +23 -0
  211. package/public/r/comp-179.json +24 -0
  212. package/public/r/comp-18.json +25 -0
  213. package/public/r/comp-180.json +23 -0
  214. package/public/r/comp-181.json +25 -0
  215. package/public/r/comp-182.json +24 -0
  216. package/public/r/comp-183.json +25 -0
  217. package/public/r/comp-184.json +25 -0
  218. package/public/r/comp-185.json +24 -0
  219. package/public/r/comp-186.json +25 -0
  220. package/public/r/comp-187.json +25 -0
  221. package/public/r/comp-188.json +25 -0
  222. package/public/r/comp-189.json +23 -0
  223. package/public/r/comp-19.json +23 -0
  224. package/public/r/comp-190.json +23 -0
  225. package/public/r/comp-191.json +24 -0
  226. package/public/r/comp-192.json +23 -0
  227. package/public/r/comp-193.json +23 -0
  228. package/public/r/comp-194.json +24 -0
  229. package/public/r/comp-195.json +23 -0
  230. package/public/r/comp-196.json +24 -0
  231. package/public/r/comp-197.json +23 -0
  232. package/public/r/comp-198.json +23 -0
  233. package/public/r/comp-199.json +23 -0
  234. package/public/r/comp-20.json +23 -0
  235. package/public/r/comp-200.json +25 -0
  236. package/public/r/comp-201.json +22 -0
  237. package/public/r/comp-202.json +22 -0
  238. package/public/r/comp-203.json +23 -0
  239. package/public/r/comp-204.json +23 -0
  240. package/public/r/comp-205.json +23 -0
  241. package/public/r/comp-206.json +24 -0
  242. package/public/r/comp-207.json +23 -0
  243. package/public/r/comp-208.json +23 -0
  244. package/public/r/comp-209.json +23 -0
  245. package/public/r/comp-21.json +23 -0
  246. package/public/r/comp-210.json +24 -0
  247. package/public/r/comp-211.json +24 -0
  248. package/public/r/comp-212.json +23 -0
  249. package/public/r/comp-213.json +23 -0
  250. package/public/r/comp-214.json +23 -0
  251. package/public/r/comp-215.json +24 -0
  252. package/public/r/comp-216.json +22 -0
  253. package/public/r/comp-217.json +22 -0
  254. package/public/r/comp-218.json +25 -0
  255. package/public/r/comp-219.json +23 -0
  256. package/public/r/comp-22.json +23 -0
  257. package/public/r/comp-220.json +24 -0
  258. package/public/r/comp-221.json +23 -0
  259. package/public/r/comp-222.json +26 -0
  260. package/public/r/comp-223.json +26 -0
  261. package/public/r/comp-224.json +23 -0
  262. package/public/r/comp-225.json +24 -0
  263. package/public/r/comp-226.json +26 -0
  264. package/public/r/comp-227.json +26 -0
  265. package/public/r/comp-228.json +26 -0
  266. package/public/r/comp-229.json +30 -0
  267. package/public/r/comp-23.json +24 -0
  268. package/public/r/comp-230.json +30 -0
  269. package/public/r/comp-231.json +32 -0
  270. package/public/r/comp-232.json +31 -0
  271. package/public/r/comp-233.json +30 -0
  272. package/public/r/comp-234.json +28 -0
  273. package/public/r/comp-235.json +28 -0
  274. package/public/r/comp-236.json +24 -0
  275. package/public/r/comp-237.json +26 -0
  276. package/public/r/comp-238.json +26 -0
  277. package/public/r/comp-239.json +26 -0
  278. package/public/r/comp-24.json +23 -0
  279. package/public/r/comp-240.json +23 -0
  280. package/public/r/comp-241.json +24 -0
  281. package/public/r/comp-242.json +23 -0
  282. package/public/r/comp-243.json +23 -0
  283. package/public/r/comp-244.json +23 -0
  284. package/public/r/comp-245.json +23 -0
  285. package/public/r/comp-246.json +23 -0
  286. package/public/r/comp-247.json +23 -0
  287. package/public/r/comp-248.json +23 -0
  288. package/public/r/comp-249.json +24 -0
  289. package/public/r/comp-25.json +24 -0
  290. package/public/r/comp-250.json +25 -0
  291. package/public/r/comp-251.json +25 -0
  292. package/public/r/comp-252.json +25 -0
  293. package/public/r/comp-253.json +25 -0
  294. package/public/r/comp-254.json +35 -0
  295. package/public/r/comp-255.json +30 -0
  296. package/public/r/comp-256.json +25 -0
  297. package/public/r/comp-257.json +25 -0
  298. package/public/r/comp-258.json +32 -0
  299. package/public/r/comp-259.json +26 -0
  300. package/public/r/comp-26.json +24 -0
  301. package/public/r/comp-260.json +26 -0
  302. package/public/r/comp-261.json +24 -0
  303. package/public/r/comp-262.json +31 -0
  304. package/public/r/comp-263.json +25 -0
  305. package/public/r/comp-264.json +33 -0
  306. package/public/r/comp-265.json +32 -0
  307. package/public/r/comp-266.json +24 -0
  308. package/public/r/comp-267.json +19 -0
  309. package/public/r/comp-268.json +19 -0
  310. package/public/r/comp-269.json +19 -0
  311. package/public/r/comp-27.json +24 -0
  312. package/public/r/comp-270.json +19 -0
  313. package/public/r/comp-271.json +19 -0
  314. package/public/r/comp-272.json +19 -0
  315. package/public/r/comp-273.json +19 -0
  316. package/public/r/comp-274.json +19 -0
  317. package/public/r/comp-275.json +19 -0
  318. package/public/r/comp-276.json +19 -0
  319. package/public/r/comp-277.json +21 -0
  320. package/public/r/comp-278.json +21 -0
  321. package/public/r/comp-279.json +23 -0
  322. package/public/r/comp-28.json +24 -0
  323. package/public/r/comp-280.json +23 -0
  324. package/public/r/comp-281.json +23 -0
  325. package/public/r/comp-282.json +23 -0
  326. package/public/r/comp-283.json +23 -0
  327. package/public/r/comp-284.json +23 -0
  328. package/public/r/comp-285.json +23 -0
  329. package/public/r/comp-286.json +23 -0
  330. package/public/r/comp-287.json +24 -0
  331. package/public/r/comp-288.json +23 -0
  332. package/public/r/comp-289.json +24 -0
  333. package/public/r/comp-29.json +24 -0
  334. package/public/r/comp-290.json +24 -0
  335. package/public/r/comp-291.json +24 -0
  336. package/public/r/comp-292.json +24 -0
  337. package/public/r/comp-293.json +26 -0
  338. package/public/r/comp-294.json +24 -0
  339. package/public/r/comp-295.json +23 -0
  340. package/public/r/comp-296.json +23 -0
  341. package/public/r/comp-297.json +30 -0
  342. package/public/r/comp-298.json +26 -0
  343. package/public/r/comp-299.json +28 -0
  344. package/public/r/comp-30.json +23 -0
  345. package/public/r/comp-300.json +29 -0
  346. package/public/r/comp-301.json +24 -0
  347. package/public/r/comp-302.json +18 -0
  348. package/public/r/comp-303.json +18 -0
  349. package/public/r/comp-304.json +18 -0
  350. package/public/r/comp-305.json +21 -0
  351. package/public/r/comp-306.json +21 -0
  352. package/public/r/comp-307.json +21 -0
  353. package/public/r/comp-308.json +21 -0
  354. package/public/r/comp-309.json +21 -0
  355. package/public/r/comp-31.json +21 -0
  356. package/public/r/comp-310.json +23 -0
  357. package/public/r/comp-311.json +20 -0
  358. package/public/r/comp-312.json +21 -0
  359. package/public/r/comp-313.json +26 -0
  360. package/public/r/comp-314.json +26 -0
  361. package/public/r/comp-315.json +24 -0
  362. package/public/r/comp-316.json +25 -0
  363. package/public/r/comp-317.json +24 -0
  364. package/public/r/comp-318.json +24 -0
  365. package/public/r/comp-319.json +24 -0
  366. package/public/r/comp-32.json +21 -0
  367. package/public/r/comp-320.json +27 -0
  368. package/public/r/comp-321.json +28 -0
  369. package/public/r/comp-322.json +27 -0
  370. package/public/r/comp-323.json +30 -0
  371. package/public/r/comp-324.json +28 -0
  372. package/public/r/comp-325.json +29 -0
  373. package/public/r/comp-326.json +30 -0
  374. package/public/r/comp-327.json +30 -0
  375. package/public/r/comp-328.json +37 -0
  376. package/public/r/comp-329.json +38 -0
  377. package/public/r/comp-33.json +18 -0
  378. package/public/r/comp-330.json +27 -0
  379. package/public/r/comp-331.json +42 -0
  380. package/public/r/comp-332.json +25 -0
  381. package/public/r/comp-333.json +29 -0
  382. package/public/r/comp-334.json +22 -0
  383. package/public/r/comp-335.json +22 -0
  384. package/public/r/comp-336.json +22 -0
  385. package/public/r/comp-337.json +22 -0
  386. package/public/r/comp-338.json +22 -0
  387. package/public/r/comp-339.json +22 -0
  388. package/public/r/comp-34.json +27 -0
  389. package/public/r/comp-340.json +22 -0
  390. package/public/r/comp-341.json +22 -0
  391. package/public/r/comp-342.json +22 -0
  392. package/public/r/comp-343.json +22 -0
  393. package/public/r/comp-344.json +22 -0
  394. package/public/r/comp-345.json +22 -0
  395. package/public/r/comp-346.json +22 -0
  396. package/public/r/comp-347.json +22 -0
  397. package/public/r/comp-348.json +22 -0
  398. package/public/r/comp-349.json +22 -0
  399. package/public/r/comp-35.json +27 -0
  400. package/public/r/comp-350.json +22 -0
  401. package/public/r/comp-351.json +22 -0
  402. package/public/r/comp-352.json +24 -0
  403. package/public/r/comp-353.json +24 -0
  404. package/public/r/comp-354.json +23 -0
  405. package/public/r/comp-355.json +23 -0
  406. package/public/r/comp-356.json +23 -0
  407. package/public/r/comp-357.json +23 -0
  408. package/public/r/comp-358.json +23 -0
  409. package/public/r/comp-359.json +24 -0
  410. package/public/r/comp-36.json +26 -0
  411. package/public/r/comp-360.json +25 -0
  412. package/public/r/comp-361.json +23 -0
  413. package/public/r/comp-362.json +24 -0
  414. package/public/r/comp-363.json +27 -0
  415. package/public/r/comp-364.json +26 -0
  416. package/public/r/comp-365.json +24 -0
  417. package/public/r/comp-366.json +23 -0
  418. package/public/r/comp-367.json +23 -0
  419. package/public/r/comp-368.json +23 -0
  420. package/public/r/comp-369.json +23 -0
  421. package/public/r/comp-37.json +23 -0
  422. package/public/r/comp-370.json +23 -0
  423. package/public/r/comp-371.json +24 -0
  424. package/public/r/comp-372.json +24 -0
  425. package/public/r/comp-373.json +25 -0
  426. package/public/r/comp-374.json +26 -0
  427. package/public/r/comp-375.json +25 -0
  428. package/public/r/comp-376.json +26 -0
  429. package/public/r/comp-377.json +27 -0
  430. package/public/r/comp-378.json +24 -0
  431. package/public/r/comp-379.json +24 -0
  432. package/public/r/comp-38.json +23 -0
  433. package/public/r/comp-380.json +24 -0
  434. package/public/r/comp-381.json +26 -0
  435. package/public/r/comp-382.json +25 -0
  436. package/public/r/comp-383.json +26 -0
  437. package/public/r/comp-384.json +24 -0
  438. package/public/r/comp-385.json +24 -0
  439. package/public/r/comp-386.json +24 -0
  440. package/public/r/comp-387.json +28 -0
  441. package/public/r/comp-388.json +26 -0
  442. package/public/r/comp-389.json +24 -0
  443. package/public/r/comp-39.json +23 -0
  444. package/public/r/comp-390.json +23 -0
  445. package/public/r/comp-391.json +23 -0
  446. package/public/r/comp-392.json +23 -0
  447. package/public/r/comp-393.json +23 -0
  448. package/public/r/comp-394.json +24 -0
  449. package/public/r/comp-395.json +24 -0
  450. package/public/r/comp-396.json +24 -0
  451. package/public/r/comp-397.json +25 -0
  452. package/public/r/comp-398.json +26 -0
  453. package/public/r/comp-399.json +26 -0
  454. package/public/r/comp-40.json +23 -0
  455. package/public/r/comp-400.json +20 -0
  456. package/public/r/comp-401.json +19 -0
  457. package/public/r/comp-402.json +19 -0
  458. package/public/r/comp-403.json +19 -0
  459. package/public/r/comp-404.json +19 -0
  460. package/public/r/comp-405.json +19 -0
  461. package/public/r/comp-406.json +19 -0
  462. package/public/r/comp-407.json +19 -0
  463. package/public/r/comp-408.json +19 -0
  464. package/public/r/comp-409.json +22 -0
  465. package/public/r/comp-41.json +29 -0
  466. package/public/r/comp-410.json +22 -0
  467. package/public/r/comp-411.json +22 -0
  468. package/public/r/comp-412.json +19 -0
  469. package/public/r/comp-413.json +22 -0
  470. package/public/r/comp-414.json +22 -0
  471. package/public/r/comp-415.json +22 -0
  472. package/public/r/comp-416.json +23 -0
  473. package/public/r/comp-417.json +22 -0
  474. package/public/r/comp-418.json +23 -0
  475. package/public/r/comp-419.json +23 -0
  476. package/public/r/comp-42.json +30 -0
  477. package/public/r/comp-420.json +23 -0
  478. package/public/r/comp-421.json +23 -0
  479. package/public/r/comp-422.json +23 -0
  480. package/public/r/comp-423.json +24 -0
  481. package/public/r/comp-424.json +22 -0
  482. package/public/r/comp-425.json +23 -0
  483. package/public/r/comp-426.json +23 -0
  484. package/public/r/comp-427.json +23 -0
  485. package/public/r/comp-428.json +23 -0
  486. package/public/r/comp-429.json +23 -0
  487. package/public/r/comp-43.json +32 -0
  488. package/public/r/comp-430.json +23 -0
  489. package/public/r/comp-431.json +23 -0
  490. package/public/r/comp-432.json +23 -0
  491. package/public/r/comp-433.json +24 -0
  492. package/public/r/comp-434.json +24 -0
  493. package/public/r/comp-435.json +24 -0
  494. package/public/r/comp-436.json +24 -0
  495. package/public/r/comp-437.json +25 -0
  496. package/public/r/comp-438.json +23 -0
  497. package/public/r/comp-439.json +24 -0
  498. package/public/r/comp-44.json +25 -0
  499. package/public/r/comp-440.json +25 -0
  500. package/public/r/comp-441.json +25 -0
  501. package/public/r/comp-442.json +24 -0
  502. package/public/r/comp-443.json +24 -0
  503. package/public/r/comp-444.json +24 -0
  504. package/public/r/comp-445.json +24 -0
  505. package/public/r/comp-446.json +24 -0
  506. package/public/r/comp-447.json +25 -0
  507. package/public/r/comp-448.json +23 -0
  508. package/public/r/comp-449.json +23 -0
  509. package/public/r/comp-45.json +25 -0
  510. package/public/r/comp-450.json +23 -0
  511. package/public/r/comp-451.json +23 -0
  512. package/public/r/comp-452.json +23 -0
  513. package/public/r/comp-453.json +25 -0
  514. package/public/r/comp-454.json +22 -0
  515. package/public/r/comp-455.json +22 -0
  516. package/public/r/comp-456.json +22 -0
  517. package/public/r/comp-457.json +21 -0
  518. package/public/r/comp-458.json +22 -0
  519. package/public/r/comp-459.json +26 -0
  520. package/public/r/comp-46.json +26 -0
  521. package/public/r/comp-460.json +26 -0
  522. package/public/r/comp-461.json +27 -0
  523. package/public/r/comp-462.json +27 -0
  524. package/public/r/comp-463.json +30 -0
  525. package/public/r/comp-464.json +29 -0
  526. package/public/r/comp-465.json +29 -0
  527. package/public/r/comp-466.json +21 -0
  528. package/public/r/comp-467.json +23 -0
  529. package/public/r/comp-468.json +21 -0
  530. package/public/r/comp-469.json +21 -0
  531. package/public/r/comp-47.json +32 -0
  532. package/public/r/comp-470.json +21 -0
  533. package/public/r/comp-471.json +21 -0
  534. package/public/r/comp-472.json +23 -0
  535. package/public/r/comp-473.json +24 -0
  536. package/public/r/comp-474.json +22 -0
  537. package/public/r/comp-475.json +22 -0
  538. package/public/r/comp-476.json +21 -0
  539. package/public/r/comp-477.json +31 -0
  540. package/public/r/comp-478.json +36 -0
  541. package/public/r/comp-479.json +28 -0
  542. package/public/r/comp-48.json +32 -0
  543. package/public/r/comp-480.json +30 -0
  544. package/public/r/comp-481.json +34 -0
  545. package/public/r/comp-482.json +33 -0
  546. package/public/r/comp-483.json +37 -0
  547. package/public/r/comp-484.json +41 -0
  548. package/public/r/comp-485.json +43 -0
  549. package/public/r/comp-486.json +23 -0
  550. package/public/r/comp-487.json +26 -0
  551. package/public/r/comp-488.json +27 -0
  552. package/public/r/comp-489.json +28 -0
  553. package/public/r/comp-49.json +32 -0
  554. package/public/r/comp-490.json +23 -0
  555. package/public/r/comp-491.json +24 -0
  556. package/public/r/comp-492.json +25 -0
  557. package/public/r/comp-493.json +23 -0
  558. package/public/r/comp-494.json +23 -0
  559. package/public/r/comp-495.json +24 -0
  560. package/public/r/comp-496.json +23 -0
  561. package/public/r/comp-497.json +24 -0
  562. package/public/r/comp-498.json +24 -0
  563. package/public/r/comp-499.json +24 -0
  564. package/public/r/comp-50.json +32 -0
  565. package/public/r/comp-500.json +25 -0
  566. package/public/r/comp-501.json +25 -0
  567. package/public/r/comp-502.json +26 -0
  568. package/public/r/comp-503.json +27 -0
  569. package/public/r/comp-504.json +28 -0
  570. package/public/r/comp-505.json +28 -0
  571. package/public/r/comp-506.json +26 -0
  572. package/public/r/comp-507.json +27 -0
  573. package/public/r/comp-508.json +25 -0
  574. package/public/r/comp-509.json +25 -0
  575. package/public/r/comp-51.json +23 -0
  576. package/public/r/comp-510.json +24 -0
  577. package/public/r/comp-511.json +27 -0
  578. package/public/r/comp-512.json +27 -0
  579. package/public/r/comp-513.json +21 -0
  580. package/public/r/comp-514.json +21 -0
  581. package/public/r/comp-515.json +21 -0
  582. package/public/r/comp-516.json +22 -0
  583. package/public/r/comp-517.json +22 -0
  584. package/public/r/comp-518.json +21 -0
  585. package/public/r/comp-519.json +21 -0
  586. package/public/r/comp-52.json +23 -0
  587. package/public/r/comp-520.json +22 -0
  588. package/public/r/comp-521.json +22 -0
  589. package/public/r/comp-522.json +21 -0
  590. package/public/r/comp-523.json +21 -0
  591. package/public/r/comp-524.json +21 -0
  592. package/public/r/comp-525.json +21 -0
  593. package/public/r/comp-526.json +22 -0
  594. package/public/r/comp-527.json +23 -0
  595. package/public/r/comp-528.json +22 -0
  596. package/public/r/comp-529.json +22 -0
  597. package/public/r/comp-53.json +24 -0
  598. package/public/r/comp-530.json +22 -0
  599. package/public/r/comp-531.json +22 -0
  600. package/public/r/comp-532.json +22 -0
  601. package/public/r/comp-533.json +22 -0
  602. package/public/r/comp-534.json +22 -0
  603. package/public/r/comp-535.json +22 -0
  604. package/public/r/comp-536.json +22 -0
  605. package/public/r/comp-537.json +22 -0
  606. package/public/r/comp-538.json +22 -0
  607. package/public/r/comp-539.json +22 -0
  608. package/public/r/comp-54.json +26 -0
  609. package/public/r/comp-540.json +21 -0
  610. package/public/r/comp-541.json +21 -0
  611. package/public/r/comp-542.json +124 -0
  612. package/public/r/comp-543.json +29 -0
  613. package/public/r/comp-544.json +26 -0
  614. package/public/r/comp-545.json +29 -0
  615. package/public/r/comp-546.json +29 -0
  616. package/public/r/comp-547.json +29 -0
  617. package/public/r/comp-548.json +29 -0
  618. package/public/r/comp-549.json +29 -0
  619. package/public/r/comp-55.json +27 -0
  620. package/public/r/comp-550.json +29 -0
  621. package/public/r/comp-551.json +30 -0
  622. package/public/r/comp-552.json +29 -0
  623. package/public/r/comp-553.json +29 -0
  624. package/public/r/comp-554.json +36 -0
  625. package/public/r/comp-555.json +23 -0
  626. package/public/r/comp-556.json +23 -0
  627. package/public/r/comp-557.json +23 -0
  628. package/public/r/comp-558.json +23 -0
  629. package/public/r/comp-559.json +23 -0
  630. package/public/r/comp-56.json +26 -0
  631. package/public/r/comp-560.json +23 -0
  632. package/public/r/comp-561.json +25 -0
  633. package/public/r/comp-562.json +23 -0
  634. package/public/r/comp-563.json +23 -0
  635. package/public/r/comp-564.json +24 -0
  636. package/public/r/comp-565.json +20 -0
  637. package/public/r/comp-566.json +20 -0
  638. package/public/r/comp-567.json +20 -0
  639. package/public/r/comp-568.json +20 -0
  640. package/public/r/comp-569.json +20 -0
  641. package/public/r/comp-57.json +26 -0
  642. package/public/r/comp-570.json +20 -0
  643. package/public/r/comp-571.json +23 -0
  644. package/public/r/comp-572.json +23 -0
  645. package/public/r/comp-573.json +20 -0
  646. package/public/r/comp-574.json +22 -0
  647. package/public/r/comp-575.json +20 -0
  648. package/public/r/comp-576.json +21 -0
  649. package/public/r/comp-577.json +23 -0
  650. package/public/r/comp-578.json +28 -0
  651. package/public/r/comp-579.json +28 -0
  652. package/public/r/comp-58.json +25 -0
  653. package/public/r/comp-580.json +29 -0
  654. package/public/r/comp-581.json +45 -0
  655. package/public/r/comp-582.json +42 -0
  656. package/public/r/comp-583.json +41 -0
  657. package/public/r/comp-584.json +41 -0
  658. package/public/r/comp-585.json +41 -0
  659. package/public/r/comp-586.json +34 -0
  660. package/public/r/comp-587.json +29 -0
  661. package/public/r/comp-588.json +33 -0
  662. package/public/r/comp-589.json +37 -0
  663. package/public/r/comp-59.json +22 -0
  664. package/public/r/comp-590.json +40 -0
  665. package/public/r/comp-591.json +29 -0
  666. package/public/r/comp-592.json +41 -0
  667. package/public/r/comp-593.json +36 -0
  668. package/public/r/comp-594.json +33 -0
  669. package/public/r/comp-595.json +22 -0
  670. package/public/r/comp-596.json +26 -0
  671. package/public/r/comp-597.json +22 -0
  672. package/public/r/comp-598.json +22 -0
  673. package/public/r/comp-599.json +22 -0
  674. package/public/r/comp-60.json +23 -0
  675. package/public/r/comp-600.json +17 -0
  676. package/public/r/comp-601.json +20 -0
  677. package/public/r/comp-602.json +17 -0
  678. package/public/r/comp-603.json +20 -0
  679. package/public/r/comp-604.json +17 -0
  680. package/public/r/comp-605.json +17 -0
  681. package/public/r/comp-606.json +20 -0
  682. package/public/r/comp-607.json +20 -0
  683. package/public/r/comp-608.json +20 -0
  684. package/public/r/comp-609.json +20 -0
  685. package/public/r/comp-61.json +23 -0
  686. package/public/r/comp-610.json +23 -0
  687. package/public/r/comp-611.json +23 -0
  688. package/public/r/comp-612.json +17 -0
  689. package/public/r/comp-613.json +20 -0
  690. package/public/r/comp-614.json +17 -0
  691. package/public/r/comp-615.json +26 -0
  692. package/public/r/comp-616.json +26 -0
  693. package/public/r/comp-617.json +26 -0
  694. package/public/r/comp-62.json +23 -0
  695. package/public/r/comp-63.json +22 -0
  696. package/public/r/comp-64.json +23 -0
  697. package/public/r/comp-65.json +22 -0
  698. package/public/r/comp-66.json +22 -0
  699. package/public/r/comp-67.json +23 -0
  700. package/public/r/comp-68.json +24 -0
  701. package/public/r/comp-69.json +24 -0
  702. package/public/r/comp-70.json +24 -0
  703. package/public/r/comp-71.json +22 -0
  704. package/public/r/comp-72.json +21 -0
  705. package/public/r/comp-73.json +18 -0
  706. package/public/r/comp-74.json +27 -0
  707. package/public/r/comp-75.json +22 -0
  708. package/public/r/comp-76.json +23 -0
  709. package/public/r/comp-77.json +22 -0
  710. package/public/r/comp-78.json +21 -0
  711. package/public/r/comp-79.json +22 -0
  712. package/public/r/comp-80.json +21 -0
  713. package/public/r/comp-81.json +21 -0
  714. package/public/r/comp-82.json +22 -0
  715. package/public/r/comp-83.json +21 -0
  716. package/public/r/comp-84.json +21 -0
  717. package/public/r/comp-85.json +22 -0
  718. package/public/r/comp-86.json +22 -0
  719. package/public/r/comp-87.json +21 -0
  720. package/public/r/comp-88.json +22 -0
  721. package/public/r/comp-89.json +21 -0
  722. package/public/r/comp-90.json +22 -0
  723. package/public/r/comp-91.json +22 -0
  724. package/public/r/comp-92.json +22 -0
  725. package/public/r/comp-93.json +22 -0
  726. package/public/r/comp-94.json +24 -0
  727. package/public/r/comp-95.json +26 -0
  728. package/public/r/comp-96.json +21 -0
  729. package/public/r/comp-97.json +21 -0
  730. package/public/r/comp-98.json +22 -0
  731. package/public/r/comp-99.json +23 -0
  732. package/public/r/comparison-event-handlers.json +1 -1
  733. package/public/r/comparison-hover.json +1 -1
  734. package/public/r/comparison.json +1 -1
  735. package/public/r/context-menu.json +16 -0
  736. package/public/r/contribution-graph-custom-footer.json +1 -1
  737. package/public/r/credit-card-apple.json +1 -1
  738. package/public/r/credit-card-back.json +1 -1
  739. package/public/r/credit-card.json +1 -1
  740. package/public/r/cropper.json +15 -0
  741. package/public/r/cursor-color.json +1 -1
  742. package/public/r/cursor-message.json +1 -1
  743. package/public/r/cursor-name-message.json +1 -1
  744. package/public/r/cursor-name.json +1 -1
  745. package/public/r/cursor.json +1 -1
  746. package/public/r/dashboard-1.json +263 -0
  747. package/public/r/dashboard-2.json +264 -0
  748. package/public/r/dashboard-3.json +225 -0
  749. package/public/r/datefield-rac.json +15 -0
  750. package/public/r/deck-controlled.json +1 -1
  751. package/public/r/deck-product-cards.json +1 -1
  752. package/public/r/deck.json +1 -1
  753. package/public/r/dialog-close-confirmation.json +1 -1
  754. package/public/r/dialog-demo.json +1 -1
  755. package/public/r/dialog-from-menu.json +1 -1
  756. package/public/r/dialog-nested.json +1 -1
  757. package/public/r/dialog-stack-controlled.json +1 -1
  758. package/public/r/dialog-stack-navigation.json +1 -1
  759. package/public/r/dialog-stack-six.json +1 -1
  760. package/public/r/dialog-stack.json +1 -1
  761. package/public/r/dropdown-menu.json +15 -0
  762. package/public/r/dropzone-custom-empty-state.json +1 -1
  763. package/public/r/dropzone-image-preview.json +1 -1
  764. package/public/r/editor.json +1 -1
  765. package/public/r/emails.json +243 -0
  766. package/public/r/empty-demo.json +1 -1
  767. package/public/r/example-app-calendar.json +323 -0
  768. package/public/r/field-2.json +19 -0
  769. package/public/r/field-autocomplete.json +1 -1
  770. package/public/r/field-checkbox-group.json +1 -1
  771. package/public/r/field-checkbox.json +1 -1
  772. package/public/r/field-combobox-multiple.json +1 -1
  773. package/public/r/field-combobox.json +1 -1
  774. package/public/r/field-complete-form.json +1 -1
  775. package/public/r/field-demo.json +1 -1
  776. package/public/r/field-disabled.json +1 -1
  777. package/public/r/field-error.json +1 -1
  778. package/public/r/field-number-field.json +1 -1
  779. package/public/r/field-radio.json +1 -1
  780. package/public/r/field-required.json +1 -1
  781. package/public/r/field-select.json +1 -1
  782. package/public/r/field-slider.json +1 -1
  783. package/public/r/field-switch.json +1 -1
  784. package/public/r/field-textarea.json +1 -1
  785. package/public/r/field-validity.json +1 -1
  786. package/public/r/fieldset-demo.json +1 -1
  787. package/public/r/files.json +195 -0
  788. package/public/r/form-demo.json +1 -1
  789. package/public/r/form-zod.json +1 -1
  790. package/public/r/form.json +1 -1
  791. package/public/r/frame-demo.json +1 -1
  792. package/public/r/gantt-lanes.json +1 -1
  793. package/public/r/gantt-no-sidebar.json +1 -1
  794. package/public/r/gantt-read-only.json +1 -1
  795. package/public/r/gantt.json +1 -1
  796. package/public/r/glimpse-custom.json +1 -1
  797. package/public/r/glimpse.json +1 -1
  798. package/public/r/gooey-toast-demo.json +1 -1
  799. package/public/r/gooey-toast-promise.json +1 -1
  800. package/public/r/gooey-toast-states.json +1 -1
  801. package/public/r/gooey-toast-with-button.json +1 -1
  802. package/public/r/group-demo.json +1 -1
  803. package/public/r/group-with-input.json +1 -1
  804. package/public/r/hero.json +1 -1
  805. package/public/r/hover-card.json +15 -0
  806. package/public/r/image-crop-circular.json +1 -1
  807. package/public/r/image-crop-custom.json +1 -1
  808. package/public/r/image-crop.json +1 -1
  809. package/public/r/image-zoom-background.json +1 -1
  810. package/public/r/image-zoom-margin.json +1 -1
  811. package/public/r/image-zoom.json +1 -1
  812. package/public/r/input-demo.json +1 -1
  813. package/public/r/input-disabled.json +1 -1
  814. package/public/r/input-file.json +1 -1
  815. package/public/r/input-group.json +20 -0
  816. package/public/r/input-lg.json +1 -1
  817. package/public/r/input-sm.json +1 -1
  818. package/public/r/input-with-button.json +1 -1
  819. package/public/r/input-with-label.json +1 -1
  820. package/public/r/kanban-simple.json +1 -1
  821. package/public/r/kanban.json +1 -1
  822. package/public/r/kbd.json +12 -0
  823. package/public/r/leads.json +271 -0
  824. package/public/r/list-simple.json +1 -1
  825. package/public/r/list.json +1 -1
  826. package/public/r/maps.json +188 -0
  827. package/public/r/menu-checkbox.json +1 -1
  828. package/public/r/menu-close-on-click.json +1 -1
  829. package/public/r/menu-demo.json +1 -1
  830. package/public/r/menu-group-labels.json +1 -1
  831. package/public/r/menu-hover.json +1 -1
  832. package/public/r/menu-link.json +1 -1
  833. package/public/r/menu-nested.json +1 -1
  834. package/public/r/menu-radio-group.json +1 -1
  835. package/public/r/meter-demo.json +1 -1
  836. package/public/r/meter-with-formatted-value.json +1 -1
  837. package/public/r/meter-with-range.json +1 -1
  838. package/public/r/mini-calendar-controlled.json +1 -1
  839. package/public/r/multiselect.json +15 -0
  840. package/public/r/navigation-menu.json +12 -0
  841. package/public/r/number-field-form.json +1 -1
  842. package/public/r/number-field-with-label.json +1 -1
  843. package/public/r/number-field-with-scrub.json +1 -1
  844. package/public/r/number-field-with-step.json +1 -1
  845. package/public/r/pill-avatar-group.json +1 -1
  846. package/public/r/pill-delta.json +1 -1
  847. package/public/r/pill-icon.json +1 -1
  848. package/public/r/pill-indicator.json +1 -1
  849. package/public/r/pill-status.json +1 -1
  850. package/public/r/pill.json +1 -1
  851. package/public/r/popover-demo.json +1 -1
  852. package/public/r/popover-with-close.json +1 -1
  853. package/public/r/preview-card-demo.json +1 -1
  854. package/public/r/pricing.json +1 -1
  855. package/public/r/progress-with-formatted-value.json +1 -1
  856. package/public/r/progress-with-label-value.json +1 -1
  857. package/public/r/radio-group-card.json +1 -1
  858. package/public/r/radio-group-demo.json +1 -1
  859. package/public/r/radio-group-disabled.json +1 -1
  860. package/public/r/radio-group-form.json +1 -1
  861. package/public/r/radio-group-with-description.json +1 -1
  862. package/public/r/reel-custom.json +1 -1
  863. package/public/r/reel-images.json +1 -1
  864. package/public/r/reel-minimal.json +1 -1
  865. package/public/r/reel.json +1 -1
  866. package/public/r/registry.json +18217 -0
  867. package/public/r/relative-time-controlled.json +1 -1
  868. package/public/r/relative-time-format-date.json +1 -1
  869. package/public/r/relative-time-format-time.json +1 -1
  870. package/public/r/relative-time.json +1 -1
  871. package/public/r/rentals.json +187 -0
  872. package/public/r/roadmap.json +1 -1
  873. package/public/r/sandbox-no-file-explorer.json +1 -1
  874. package/public/r/sandbox.json +1 -1
  875. package/public/r/scroll-area-both.json +1 -1
  876. package/public/r/scroll-area-demo.json +1 -1
  877. package/public/r/scroll-area-horizontal.json +1 -1
  878. package/public/r/select-demo.json +1 -1
  879. package/public/r/select-disabled.json +1 -1
  880. package/public/r/select-form.json +1 -1
  881. package/public/r/select-lg.json +1 -1
  882. package/public/r/select-native.json +12 -0
  883. package/public/r/select-sm.json +1 -1
  884. package/public/r/select-with-groups.json +1 -1
  885. package/public/r/select-without-alignment.json +1 -1
  886. package/public/r/select.json +1 -1
  887. package/public/r/separator-demo.json +1 -1
  888. package/public/r/sheet-demo.json +1 -1
  889. package/public/r/sheet-position.json +1 -1
  890. package/public/r/sidebar-nav.json +22 -0
  891. package/public/r/skeleton-demo.json +1 -1
  892. package/public/r/skeleton.json +1 -1
  893. package/public/r/slider-form.json +1 -1
  894. package/public/r/slider-with-label-value.json +1 -1
  895. package/public/r/sonner.json +16 -0
  896. package/public/r/stats-card.json +22 -0
  897. package/public/r/status-custom.json +1 -1
  898. package/public/r/stepper.json +15 -0
  899. package/public/r/stories-images.json +1 -1
  900. package/public/r/switch-card.json +1 -1
  901. package/public/r/switch-demo.json +1 -1
  902. package/public/r/switch-disabled.json +1 -1
  903. package/public/r/switch-form.json +1 -1
  904. package/public/r/switch-with-description.json +1 -1
  905. package/public/r/table-demo.json +1 -1
  906. package/public/r/table-framed.json +1 -1
  907. package/public/r/table-simple.json +1 -1
  908. package/public/r/table.json +1 -1
  909. package/public/r/tabs-demo.json +1 -1
  910. package/public/r/tabs-underline-vertical.json +1 -1
  911. package/public/r/tabs-underline.json +1 -1
  912. package/public/r/tabs-vertical.json +1 -1
  913. package/public/r/tags-create.json +1 -1
  914. package/public/r/tags-filter.json +1 -1
  915. package/public/r/tags.json +1 -1
  916. package/public/r/template-auth-eight.json +28 -0
  917. package/public/r/template-auth-five.json +28 -0
  918. package/public/r/template-auth-four.json +29 -0
  919. package/public/r/template-auth-nine.json +28 -0
  920. package/public/r/template-auth-one.json +49 -0
  921. package/public/r/template-auth-seven.json +29 -0
  922. package/public/r/template-auth-six.json +28 -0
  923. package/public/r/template-auth-three.json +49 -0
  924. package/public/r/template-auth-two.json +44 -0
  925. package/public/r/template-hero-eight.json +83 -0
  926. package/public/r/template-hero-eleven.json +29 -0
  927. package/public/r/template-hero-five.json +35 -0
  928. package/public/r/template-hero-four.json +35 -0
  929. package/public/r/template-hero-fourteen.json +101 -0
  930. package/public/r/template-hero-nine.json +74 -0
  931. package/public/r/template-hero-one.json +90 -0
  932. package/public/r/template-hero-seven.json +83 -0
  933. package/public/r/template-hero-six.json +83 -0
  934. package/public/r/template-hero-ten.json +77 -0
  935. package/public/r/template-hero-thirteen.json +101 -0
  936. package/public/r/template-hero-three.json +35 -0
  937. package/public/r/template-hero-twelve.json +30 -0
  938. package/public/r/template-hero-two.json +96 -0
  939. package/public/r/template-logo-cloud-five.json +68 -0
  940. package/public/r/template-logo-cloud-four.json +71 -0
  941. package/public/r/template-logo-cloud-one.json +89 -0
  942. package/public/r/template-logo-cloud-three.json +71 -0
  943. package/public/r/template-logo-cloud-two.json +74 -0
  944. package/public/r/textarea-demo.json +1 -1
  945. package/public/r/textarea-disabled.json +1 -1
  946. package/public/r/textarea-form.json +1 -1
  947. package/public/r/textarea-lg.json +1 -1
  948. package/public/r/textarea-sm.json +1 -1
  949. package/public/r/textarea-with-label.json +1 -1
  950. package/public/r/ticker-inline.json +1 -1
  951. package/public/r/timeline.json +15 -0
  952. package/public/r/toast-demo.json +1 -1
  953. package/public/r/toast-heights.json +1 -1
  954. package/public/r/toast-loading.json +1 -1
  955. package/public/r/toast-promise.json +1 -1
  956. package/public/r/toast-with-action.json +1 -1
  957. package/public/r/toast-with-status.json +1 -1
  958. package/public/r/toggle-demo.json +1 -1
  959. package/public/r/toggle-disabled.json +1 -1
  960. package/public/r/toggle-group-demo.json +1 -1
  961. package/public/r/toggle-group-disabled.json +1 -1
  962. package/public/r/toggle-group-lg.json +1 -1
  963. package/public/r/toggle-group-multiple.json +1 -1
  964. package/public/r/toggle-group-outline-with-separator.json +1 -1
  965. package/public/r/toggle-group-outline.json +1 -1
  966. package/public/r/toggle-group-sm.json +1 -1
  967. package/public/r/toggle-group-with-disabled-item.json +1 -1
  968. package/public/r/toggle-icon-group.json +1 -1
  969. package/public/r/toggle-lg.json +1 -1
  970. package/public/r/toggle-outline.json +1 -1
  971. package/public/r/toggle-sm.json +1 -1
  972. package/public/r/toggle-with-icon.json +1 -1
  973. package/public/r/toolbar-demo.json +1 -1
  974. package/public/r/tooltip-demo.json +1 -1
  975. package/public/r/tooltip-grouped.json +1 -1
  976. package/public/r/tree-controlled.json +1 -1
  977. package/public/r/tree-custom-icons.json +1 -1
  978. package/public/r/tree-no-lines.json +1 -1
  979. package/public/r/tree-simple.json +1 -1
  980. package/public/r/tree.json +1 -1
  981. package/public/r/typography.json +1 -1
  982. package/public/r/ui.json +5 -0
  983. package/public/r/use-character-limit.json +12 -0
  984. package/public/r/use-file-upload.json +12 -0
  985. package/public/r/use-pagination.json +12 -0
  986. package/public/r/use-slider-with-input.json +12 -0
  987. package/public/r/use-toast.json +12 -0
  988. package/public/r/utils.json +16 -0
@@ -8,7 +8,7 @@
8
8
  "files": [
9
9
  {
10
10
  "path": "registry/default/examples/relative-time-controlled.tsx",
11
- "content": "\"use client\"\n\nimport { useEffect, useState } from \"react\"\n\nimport {\n RelativeTime,\n RelativeTimeZone,\n RelativeTimeZoneDate,\n RelativeTimeZoneDisplay,\n RelativeTimeZoneLabel,\n} from \"../../../../../packages/relative-time\"\n\nconst timezones = [\n { label: \"EST\", zone: \"America/New_York\" },\n { label: \"GMT\", zone: \"Europe/London\" },\n { label: \"JST\", zone: \"Asia/Tokyo\" },\n]\n\nconst Example = () => {\n const [time, setTime] = useState(new Date())\n\n useEffect(() => {\n const interval = setInterval(() => {\n setTime(new Date())\n }, 1000)\n return () => clearInterval(interval)\n }, [])\n\n return (\n <div className=\"rounded-md border bg-background p-4\">\n <RelativeTime onTimeChange={setTime} time={time}>\n {timezones.map(({ zone, label }) => (\n <RelativeTimeZone key={zone} zone={zone}>\n <RelativeTimeZoneLabel>{label}</RelativeTimeZoneLabel>\n <RelativeTimeZoneDate />\n <RelativeTimeZoneDisplay />\n </RelativeTimeZone>\n ))}\n </RelativeTime>\n </div>\n )\n}\n\nexport default Example\n",
11
+ "content": "\"use client\"\n\nimport { useEffect, useState } from \"react\"\n\nimport {\n RelativeTime,\n RelativeTimeZone,\n RelativeTimeZoneDate,\n RelativeTimeZoneDisplay,\n RelativeTimeZoneLabel,\n} from \"../../../../../packages/relative-time\"\n\nconst timezones = [\n { label: \"Updated EST\", zone: \"America/New_York\" },\n { label: \"Updated GMT\", zone: \"Europe/London\" },\n { label: \"Updated JST\", zone: \"Asia/Tokyo\" },\n]\n\nconst Example = () => {\n const [time, setTime] = useState(new Date())\n\n useEffect(() => {\n const interval = setInterval(() => {\n setTime(new Date())\n }, 1000)\n return () => clearInterval(interval)\n }, [])\n\n return (\n <div className=\"rounded-md border bg-background p-4\">\n <RelativeTime onTimeChange={setTime} time={time}>\n {timezones.map(({ zone, label }) => (\n <RelativeTimeZone key={zone} zone={zone}>\n <RelativeTimeZoneLabel>{label}</RelativeTimeZoneLabel>\n <RelativeTimeZoneDate />\n <RelativeTimeZoneDisplay />\n </RelativeTimeZone>\n ))}\n </RelativeTime>\n </div>\n )\n}\n\nexport default Example\n",
12
12
  "type": "registry:example"
13
13
  }
14
14
  ],
@@ -8,7 +8,7 @@
8
8
  "files": [
9
9
  {
10
10
  "path": "registry/default/examples/relative-time-format-date.tsx",
11
- "content": "\"use client\"\n\nimport {\n RelativeTime,\n RelativeTimeZone,\n RelativeTimeZoneDate,\n RelativeTimeZoneDisplay,\n RelativeTimeZoneLabel,\n} from \"../../../../../packages/relative-time\"\n\nconst timezones = [\n { label: \"EST\", zone: \"America/New_York\" },\n { label: \"GMT\", zone: \"Europe/London\" },\n { label: \"JST\", zone: \"Asia/Tokyo\" },\n]\n\nconst Example = () => (\n <div className=\"rounded-md border bg-background p-4\">\n <RelativeTime dateFormatOptions={{ dateStyle: \"full\" }}>\n {timezones.map(({ zone, label }) => (\n <RelativeTimeZone key={zone} zone={zone}>\n <RelativeTimeZoneLabel>{label}</RelativeTimeZoneLabel>\n <RelativeTimeZoneDate />\n <RelativeTimeZoneDisplay />\n </RelativeTimeZone>\n ))}\n </RelativeTime>\n </div>\n)\n\nexport default Example\n",
11
+ "content": "\"use client\"\n\nimport {\n RelativeTime,\n RelativeTimeZone,\n RelativeTimeZoneDate,\n RelativeTimeZoneDisplay,\n RelativeTimeZoneLabel,\n} from \"../../../../../packages/relative-time\"\n\nconst timezones = [\n { label: \"Updated EST\", zone: \"America/New_York\" },\n { label: \"Updated GMT\", zone: \"Europe/London\" },\n { label: \"Updated JST\", zone: \"Asia/Tokyo\" },\n]\n\nconst Example = () => (\n <div className=\"rounded-md border bg-background p-4\">\n <RelativeTime dateFormatOptions={{ dateStyle: \"full\" }}>\n {timezones.map(({ zone, label }) => (\n <RelativeTimeZone key={zone} zone={zone}>\n <RelativeTimeZoneLabel>{label}</RelativeTimeZoneLabel>\n <RelativeTimeZoneDate />\n <RelativeTimeZoneDisplay />\n </RelativeTimeZone>\n ))}\n </RelativeTime>\n </div>\n)\n\nexport default Example\n",
12
12
  "type": "registry:example"
13
13
  }
14
14
  ],
@@ -8,7 +8,7 @@
8
8
  "files": [
9
9
  {
10
10
  "path": "registry/default/examples/relative-time-format-time.tsx",
11
- "content": "\"use client\"\n\nimport {\n RelativeTime,\n RelativeTimeZone,\n RelativeTimeZoneDate,\n RelativeTimeZoneDisplay,\n RelativeTimeZoneLabel,\n} from \"../../../../../packages/relative-time\"\n\nconst timezones = [\n { label: \"EST\", zone: \"America/New_York\" },\n { label: \"GMT\", zone: \"Europe/London\" },\n { label: \"JST\", zone: \"Asia/Tokyo\" },\n]\n\nconst Example = () => (\n <div className=\"rounded-md border bg-background p-4\">\n <RelativeTime timeFormatOptions={{ hour: \"2-digit\", minute: \"2-digit\" }}>\n {timezones.map(({ zone, label }) => (\n <RelativeTimeZone key={zone} zone={zone}>\n <RelativeTimeZoneLabel>{label}</RelativeTimeZoneLabel>\n <RelativeTimeZoneDate />\n <RelativeTimeZoneDisplay />\n </RelativeTimeZone>\n ))}\n </RelativeTime>\n </div>\n)\n\nexport default Example\n",
11
+ "content": "\"use client\"\n\nimport {\n RelativeTime,\n RelativeTimeZone,\n RelativeTimeZoneDate,\n RelativeTimeZoneDisplay,\n RelativeTimeZoneLabel,\n} from \"../../../../../packages/relative-time\"\n\nconst timezones = [\n { label: \"Updated EST\", zone: \"America/New_York\" },\n { label: \"Updated GMT\", zone: \"Europe/London\" },\n { label: \"Updated JST\", zone: \"Asia/Tokyo\" },\n]\n\nconst Example = () => (\n <div className=\"rounded-md border bg-background p-4\">\n <RelativeTime timeFormatOptions={{ hour: \"2-digit\", minute: \"2-digit\" }}>\n {timezones.map(({ zone, label }) => (\n <RelativeTimeZone key={zone} zone={zone}>\n <RelativeTimeZoneLabel>{label}</RelativeTimeZoneLabel>\n <RelativeTimeZoneDate />\n <RelativeTimeZoneDisplay />\n </RelativeTimeZone>\n ))}\n </RelativeTime>\n </div>\n)\n\nexport default Example\n",
12
12
  "type": "registry:example"
13
13
  }
14
14
  ],
@@ -8,7 +8,7 @@
8
8
  "files": [
9
9
  {
10
10
  "path": "registry/default/examples/relative-time.tsx",
11
- "content": "\"use client\"\n\nimport {\n RelativeTime,\n RelativeTimeZone,\n RelativeTimeZoneDate,\n RelativeTimeZoneDisplay,\n RelativeTimeZoneLabel,\n} from \"../../../../../packages/relative-time\"\n\nconst timezones = [\n { label: \"EST\", zone: \"America/New_York\" },\n { label: \"GMT\", zone: \"Europe/London\" },\n { label: \"JST\", zone: \"Asia/Tokyo\" },\n]\n\nconst Example = () => (\n <div className=\"rounded-md border bg-background p-4\">\n <RelativeTime>\n {timezones.map(({ zone, label }) => (\n <RelativeTimeZone key={zone} zone={zone}>\n <RelativeTimeZoneLabel>{label}</RelativeTimeZoneLabel>\n <RelativeTimeZoneDate />\n <RelativeTimeZoneDisplay />\n </RelativeTimeZone>\n ))}\n </RelativeTime>\n </div>\n)\n\nexport default Example\n",
11
+ "content": "\"use client\"\n\nimport {\n RelativeTime,\n RelativeTimeZone,\n RelativeTimeZoneDate,\n RelativeTimeZoneDisplay,\n RelativeTimeZoneLabel,\n} from \"../../../../../packages/relative-time\"\n\nconst timezones = [\n { label: \"Updated EST\", zone: \"America/New_York\" },\n { label: \"Updated GMT\", zone: \"Europe/London\" },\n { label: \"Updated JST\", zone: \"Asia/Tokyo\" },\n]\n\nconst Example = () => (\n <div className=\"rounded-md border bg-background p-4\">\n <RelativeTime>\n {timezones.map(({ zone, label }) => (\n <RelativeTimeZone key={zone} zone={zone}>\n <RelativeTimeZoneLabel>{label}</RelativeTimeZoneLabel>\n <RelativeTimeZoneDate />\n <RelativeTimeZoneDisplay />\n </RelativeTimeZone>\n ))}\n </RelativeTime>\n </div>\n)\n\nexport default Example\n",
12
12
  "type": "registry:example"
13
13
  }
14
14
  ],
@@ -0,0 +1,187 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "rentals",
4
+ "type": "registry:block",
5
+ "title": "Gear Marketplace",
6
+ "description": "An e-commerce gear marketplace with map-based discovery, sorting, and favorites.",
7
+ "files": [
8
+ {
9
+ "path": "registry/example-apps/default/rentals/components/dashboard/listings-panel.tsx",
10
+ "type": "registry:component",
11
+ "target": "components/example-apps/rentals/components/dashboard/listings-panel.tsx",
12
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n ArrowUpDown,\n Check,\n DollarSign,\n Grid3x3,\n Heart,\n List,\n MapPin,\n MessageSquare,\n Search,\n Sparkles,\n Star,\n TrendingUp,\n X,\n} from \"lucide-react\"\nimport { useMediaQuery } from \"usehooks-ts\"\n\nimport { Badge } from \"@loveui/ui/ui/badge\"\nimport { Button } from \"@loveui/ui/ui/button\"\nimport { Input } from \"@loveui/ui/ui/input\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@loveui/ui/ui/menu\"\n\nimport { SidebarTrigger } from \"@/components/ui/sidebar\"\n\nimport { cn } from \"../../lib/utils\"\nimport { propertyTypeLabels, type Listing } from \"../../mock-data/listings\"\nimport { useRentalsStore } from \"../../store/rentals-store\"\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n} from \"../ui/carousel\"\n\ntype PanelMode = \"all\" | \"favorites\"\n\ninterface ListingsPanelProps {\n mode?: PanelMode\n}\n\nexport function ListingsPanel({ mode = \"all\" }: ListingsPanelProps) {\n const scrollContainerRef = React.useRef<HTMLDivElement>(null)\n const {\n selectedListingId,\n searchQuery,\n sortBy,\n selectListing,\n toggleFavorite,\n setSearchQuery,\n setSortBy,\n getFilteredListings,\n getFavoriteListings,\n setMapCenter,\n setMapZoom,\n setUserLocation,\n } = useRentalsStore()\n\n const isDesktop = useMediaQuery(\"(min-width: 640px)\")\n const [isPanelVisible, setIsPanelVisible] = React.useState(true)\n const [viewMode, setViewMode] = React.useState<\"grid\" | \"list\">(\"grid\")\n\n React.useEffect(() => {\n if (isDesktop && !isPanelVisible) {\n setIsPanelVisible(true)\n }\n }, [isDesktop, isPanelVisible])\n\n const getListings = () => {\n switch (mode) {\n case \"favorites\":\n return getFavoriteListings()\n default:\n return getFilteredListings()\n }\n }\n\n const listings = getListings()\n\n React.useEffect(() => {\n if (selectedListingId && scrollContainerRef.current) {\n scrollContainerRef.current.scrollTo({ top: 0, behavior: \"smooth\" })\n }\n }, [selectedListingId])\n\n const handleListingClick = (listing: Listing) => {\n if (selectedListingId === listing.id) {\n selectListing(null)\n } else {\n selectListing(listing.id)\n setMapCenter(listing.coordinates)\n setMapZoom(14)\n }\n }\n\n if (!isPanelVisible) {\n return (\n <Button\n variant=\"outline\"\n size=\"icon\"\n className=\"absolute top-4 left-4 z-20 size-10 bg-background shadow-xl sm:hidden\"\n onClick={() => setIsPanelVisible(true)}\n >\n <Search className=\"size-5\" />\n </Button>\n )\n }\n\n return (\n <div className=\"absolute top-4 bottom-4 left-4 z-20 flex w-80 flex-col overflow-hidden rounded-xl border bg-background shadow-xl sm:w-[420px]\">\n <div className=\"flex items-center justify-between border-b p-3\">\n <div>\n <h2 className=\"text-base font-semibold\">\n {mode === \"favorites\" ? \"Favorites\" : \"All Gear\"}\n </h2>\n <p className=\"text-xs text-muted-foreground\">\n {listings.length} {listings.length === 1 ? \"listing\" : \"listings\"}\n </p>\n </div>\n <div className=\"flex items-center gap-1\">\n <SidebarTrigger className=\"size-7\" />\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7 sm:hidden\"\n onClick={() => setIsPanelVisible(false)}\n >\n <X className=\"size-4\" />\n </Button>\n </div>\n </div>\n\n <div className=\"border-b p-2\">\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute top-1/2 left-2.5 z-10 size-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n placeholder=\"Search gear...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className={cn(\"h-9 pl-8\", searchQuery && \"pr-8\")}\n />\n {searchQuery && (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute top-1/2 right-1 size-7 -translate-y-1/2\"\n onClick={() => setSearchQuery(\"\")}\n >\n <X className=\"size-3.5\" />\n </Button>\n )}\n </div>\n <div className=\"flex items-center gap-1 rounded-lg border p-0.5\">\n <Button\n variant={viewMode === \"list\" ? \"default\" : \"ghost\"}\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={() => setViewMode(\"list\")}\n >\n <List className=\"h-3.5 w-3.5\" />\n </Button>\n <Button\n variant={viewMode === \"grid\" ? \"default\" : \"ghost\"}\n size=\"icon\"\n className=\"h-7 w-7\"\n onClick={() => setViewMode(\"grid\")}\n >\n <Grid3x3 className=\"h-3.5 w-3.5\" />\n </Button>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <Button\n variant=\"outline\"\n size=\"icon\"\n className=\"size-9 shrink-0\"\n >\n <ArrowUpDown className=\"size-4\" />\n </Button>\n }\n />\n <DropdownMenuContent align=\"end\" className=\"w-48\">\n <DropdownMenuGroup>\n <DropdownMenuItem\n onClick={() => setSortBy(\"price-low\")}\n className=\"gap-2\"\n >\n <DollarSign className=\"size-4\" />\n <span className=\"flex-1\">Price: Low to High</span>\n {sortBy === \"price-low\" && <Check className=\"size-4\" />}\n </DropdownMenuItem>\n <DropdownMenuItem\n onClick={() => setSortBy(\"price-high\")}\n className=\"gap-2\"\n >\n <TrendingUp className=\"size-4\" />\n <span className=\"flex-1\">Price: High to Low</span>\n {sortBy === \"price-high\" && <Check className=\"size-4\" />}\n </DropdownMenuItem>\n <DropdownMenuItem\n onClick={() => setSortBy(\"rating\")}\n className=\"gap-2\"\n >\n <Star className=\"size-4\" />\n <span className=\"flex-1\">Best rated</span>\n {sortBy === \"rating\" && <Check className=\"size-4\" />}\n </DropdownMenuItem>\n <DropdownMenuItem\n onClick={() => setSortBy(\"newest\")}\n className=\"gap-2\"\n >\n <Sparkles className=\"size-4\" />\n <span className=\"flex-1\">Newest first</span>\n {sortBy === \"newest\" && <Check className=\"size-4\" />}\n </DropdownMenuItem>\n <DropdownMenuItem\n onClick={() => setSortBy(\"reviews\")}\n className=\"gap-2\"\n >\n <MessageSquare className=\"size-4\" />\n <span className=\"flex-1\">Most reviews</span>\n {sortBy === \"reviews\" && <Check className=\"size-4\" />}\n </DropdownMenuItem>\n <DropdownMenuItem\n onClick={() => {\n if (!navigator.geolocation) {\n alert(\"Geolocation is not supported by your browser.\")\n return\n }\n navigator.geolocation.getCurrentPosition(\n (position) => {\n const location = {\n lat: position.coords.latitude,\n lng: position.coords.longitude,\n }\n setUserLocation(location)\n setSortBy(\"nearest\")\n },\n () => {\n alert(\n \"Unable to get your location. Please try again later.\"\n )\n },\n {\n enableHighAccuracy: false,\n timeout: 5000,\n maximumAge: 300000,\n }\n )\n }}\n className=\"gap-2\"\n >\n <MapPin className=\"size-4\" />\n <span className=\"flex-1\">Nearest to me</span>\n {sortBy === \"nearest\" && <Check className=\"size-4\" />}\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n\n <div ref={scrollContainerRef} className=\"flex-1 overflow-y-auto\">\n {listings.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <Search className=\"mb-2 size-8 text-muted-foreground\" />\n <p className=\"text-sm font-medium\">No products found</p>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n Try adjusting your search or filters\n </p>\n </div>\n ) : viewMode === \"grid\" ? (\n <div className=\"grid grid-cols-1 gap-3 p-2\">\n {listings.map((listing) => {\n const isSelected = selectedListingId === listing.id\n\n return (\n <div\n key={listing.id}\n onClick={() => handleListingClick(listing)}\n className={cn(\n \"group cursor-pointer overflow-hidden rounded-xl border bg-card transition-all hover:shadow-lg\",\n isSelected &&\n \"border-primary shadow-lg ring-2 ring-primary/20\"\n )}\n >\n <div className=\"relative aspect-4/3 overflow-hidden\">\n <Carousel className=\"h-full w-full\">\n <CarouselContent className=\"h-full\">\n {listing.images.map((image, imageIndex) => (\n <CarouselItem key={imageIndex} className=\"h-full\">\n <img\n src={image}\n alt={`${listing.title} - Image ${imageIndex + 1}`}\n className=\"h-full w-full object-cover\"\n onError={(e) => {\n const target = e.target as HTMLImageElement\n target.src =\n \"https://images.unsplash.com/photo-1516035069371-29a1b244cc32?w=800&h=600&fit=crop\"\n }}\n />\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious className=\"left-2 h-8 w-8 bg-white/90 opacity-0! transition-opacity group-hover:opacity-100! hover:bg-white\" />\n <CarouselNext className=\"right-2 h-8 w-8 bg-white/90 opacity-0! transition-opacity group-hover:opacity-100! hover:bg-white\" />\n </Carousel>\n <div className=\"absolute top-2 right-2 z-10\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 rounded-full bg-background/80 backdrop-blur-sm hover:bg-background\"\n onClick={(e) => {\n e.stopPropagation()\n toggleFavorite(listing.id)\n }}\n >\n <Heart\n className={cn(\n \"h-4 w-4 transition-colors\",\n listing.isFavorite\n ? \"fill-destructive text-destructive\"\n : \"text-foreground\"\n )}\n />\n </Button>\n </div>\n {listing.isNew && (\n <div className=\"absolute top-2 left-2 z-10\">\n <Badge\n variant=\"default\"\n className=\"bg-primary text-xs text-primary-foreground\"\n >\n New\n </Badge>\n </div>\n )}\n {listing.instantBook && (\n <div className=\"absolute bottom-2 left-2 z-10\">\n <Badge\n variant=\"secondary\"\n className=\"bg-background/80 text-xs backdrop-blur-sm\"\n >\n Fast Checkout\n </Badge>\n </div>\n )}\n </div>\n <div className=\"p-3\">\n <div className=\"mb-1 flex items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"mb-1 truncate text-sm font-semibold\">\n {listing.title}\n </h3>\n <div className=\"mb-1 flex items-center gap-1 text-xs text-muted-foreground\">\n <MapPin className=\"h-3 w-3\" />\n <span className=\"truncate\">\n {listing.city}, {listing.country}\n </span>\n </div>\n </div>\n </div>\n <div className=\"mb-2 flex items-center gap-3 text-xs\">\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-3.5 w-3.5 fill-yellow-400 text-yellow-400\" />\n <span className=\"font-medium\">\n {listing.rating.toFixed(1)}\n </span>\n <span className=\"text-muted-foreground\">\n ({listing.reviewCount})\n </span>\n </div>\n <span className=\"text-muted-foreground\">•</span>\n <span className=\"text-muted-foreground\">\n {propertyTypeLabels[listing.propertyType]}\n </span>\n </div>\n <div className=\"flex items-center justify-between\">\n <div>\n <span className=\"text-base font-semibold\">\n ${listing.pricePerNight}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n {\" \"}\n / day\n </span>\n </div>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n {listing.bedrooms > 0 && (\n <span>\n {listing.bedrooms} kit\n {listing.bedrooms > 1 ? \"s\" : \"\"}\n </span>\n )}\n {listing.bathrooms > 0 && (\n <span>\n • {listing.bathrooms} add-on\n {listing.bathrooms > 1 ? \"s\" : \"\"}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n )\n })}\n </div>\n ) : (\n <div className=\"space-y-3 p-2\">\n {listings.map((listing) => {\n const isSelected = selectedListingId === listing.id\n\n return (\n <div\n key={listing.id}\n onClick={() => handleListingClick(listing)}\n className={cn(\n \"group cursor-pointer overflow-hidden rounded-xl border bg-card transition-all hover:shadow-lg\",\n isSelected &&\n \"border-primary shadow-lg ring-2 ring-primary/20\",\n \"flex flex-col sm:flex-row\"\n )}\n >\n <div className=\"relative h-48 w-full flex-shrink-0 overflow-hidden sm:h-32 sm:w-32 md:h-40 md:w-40\">\n <img\n src={listing.images[0]}\n alt={listing.title}\n className=\"h-full w-full object-cover transition-transform group-hover:scale-105\"\n onError={(e) => {\n const target = e.target as HTMLImageElement\n target.src =\n \"https://images.unsplash.com/photo-1516035069371-29a1b244cc32?w=800&h=600&fit=crop\"\n }}\n />\n <div className=\"absolute top-2 right-2\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-7 w-7 rounded-full bg-background/80 backdrop-blur-sm hover:bg-background sm:h-6 sm:w-6\"\n onClick={(e) => {\n e.stopPropagation()\n toggleFavorite(listing.id)\n }}\n >\n <Heart\n className={cn(\n \"h-3.5 w-3.5 transition-colors sm:h-3 sm:w-3\",\n listing.isFavorite\n ? \"fill-destructive text-destructive\"\n : \"text-foreground\"\n )}\n />\n </Button>\n </div>\n {listing.isNew && (\n <div className=\"absolute top-2 left-2\">\n <Badge\n variant=\"default\"\n className=\"bg-primary px-1.5 py-0.5 text-[10px] text-primary-foreground\"\n >\n New\n </Badge>\n </div>\n )}\n </div>\n <div className=\"flex min-w-0 flex-1 flex-col justify-between p-3 sm:p-2.5\">\n <div className=\"flex-1\">\n <div className=\"mb-1.5 sm:mb-1\">\n <h3 className=\"mb-1 line-clamp-2 text-sm font-semibold sm:line-clamp-1 sm:text-xs\">\n {listing.title}\n </h3>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <MapPin className=\"h-3 w-3 flex-shrink-0\" />\n <span className=\"truncate\">\n {listing.city}, {listing.country}\n </span>\n </div>\n </div>\n <div className=\"mb-2 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs\">\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 fill-yellow-400 text-yellow-400\" />\n <span className=\"font-medium\">\n {listing.rating.toFixed(1)}\n </span>\n <span className=\"text-muted-foreground\">\n ({listing.reviewCount})\n </span>\n </div>\n <span className=\"hidden text-muted-foreground sm:inline\">\n •\n </span>\n <span className=\"text-muted-foreground\">\n {propertyTypeLabels[listing.propertyType]}\n </span>\n {listing.instantBook && (\n <>\n <span className=\"hidden text-muted-foreground sm:inline\">\n •\n </span>\n <Badge\n variant=\"secondary\"\n className=\"px-1.5 py-0 text-[10px]\"\n >\n Fast\n </Badge>\n </>\n )}\n </div>\n </div>\n <div className=\"flex items-center justify-between gap-2 border-t pt-2 sm:border-t-0 sm:pt-0\">\n <div className=\"flex-shrink-0\">\n <span className=\"text-base font-semibold sm:text-sm\">\n ${listing.pricePerNight}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n {\" \"}\n / day\n </span>\n </div>\n <div className=\"flex flex-shrink-0 items-center gap-1.5 text-xs text-muted-foreground sm:gap-2\">\n {listing.bedrooms > 0 && (\n <span className=\"whitespace-nowrap\">\n {listing.bedrooms} kit\n {listing.bedrooms > 1 ? \"s\" : \"\"}\n </span>\n )}\n {listing.bathrooms > 0 && (\n <>\n <span className=\"hidden sm:inline\">•</span>\n <span className=\"whitespace-nowrap\">\n {listing.bathrooms} add-on\n {listing.bathrooms > 1 ? \"s\" : \"\"}\n </span>\n </>\n )}\n </div>\n </div>\n </div>\n </div>\n )\n })}\n </div>\n )}\n </div>\n </div>\n )\n}\n"
13
+ },
14
+ {
15
+ "path": "registry/example-apps/default/rentals/components/dashboard/map-controls.tsx",
16
+ "type": "registry:component",
17
+ "target": "components/example-apps/rentals/components/dashboard/map-controls.tsx",
18
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n Circle,\n Layers,\n Map,\n Mountain,\n Navigation,\n Satellite,\n ZoomIn,\n ZoomOut,\n} from \"lucide-react\"\n\nimport { Button } from \"@loveui/ui/ui/button\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@loveui/ui/ui/menu\"\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@loveui/ui/ui/tooltip\"\n\nimport { cn } from \"../../lib/utils\"\nimport { useRentalsStore } from \"../../store/rentals-store\"\nimport { ThemeToggle } from \"../theme-toggle\"\n\nconst mapStyles = [\n {\n id: \"default\",\n name: \"Default\",\n icon: Circle,\n description: \"Follows theme\",\n },\n { id: \"streets\", name: \"Streets\", icon: Map, description: \"Detailed roads\" },\n {\n id: \"outdoors\",\n name: \"Outdoors\",\n icon: Mountain,\n description: \"Terrain & trails\",\n },\n {\n id: \"satellite\",\n name: \"Satellite\",\n icon: Satellite,\n description: \"Aerial view\",\n },\n] as const\n\nexport function MapControls() {\n const {\n mapZoom,\n setMapZoom,\n setMapCenter,\n setUserLocation,\n mapStyle,\n setMapStyle,\n } = useRentalsStore()\n\n const handleZoomIn = () => {\n setMapZoom(Math.min(mapZoom + 1, 18))\n }\n\n const handleZoomOut = () => {\n setMapZoom(Math.max(mapZoom - 1, 3))\n }\n\n const handleLocate = () => {\n if (\"geolocation\" in navigator) {\n navigator.geolocation.getCurrentPosition(\n (position) => {\n const location = {\n lat: position.coords.latitude,\n lng: position.coords.longitude,\n }\n setUserLocation(location)\n setMapCenter(location)\n setMapZoom(15)\n },\n () => {\n alert(\"Unable to get your location. Please try again later.\")\n },\n { enableHighAccuracy: false, timeout: 5000, maximumAge: 300000 }\n )\n } else {\n alert(\"Geolocation is not supported by your browser.\")\n }\n }\n\n return (\n <div className=\"absolute top-4 right-4 z-20 flex flex-col gap-2\">\n <div className=\"flex flex-col gap-2 rounded-lg border bg-background p-1 shadow-lg\">\n <DropdownMenu>\n <Tooltip>\n <TooltipTrigger\n render={\n <DropdownMenuTrigger\n render={\n <Button variant=\"ghost\" size=\"icon\" className=\"h-9 w-9\">\n <Layers className=\"h-4 w-4\" />\n </Button>\n }\n />\n }\n />\n <TooltipContent>Map style</TooltipContent>\n </Tooltip>\n <DropdownMenuContent align=\"end\" className=\"w-48\">\n {mapStyles.map((style) => {\n const Icon = style.icon\n return (\n <DropdownMenuItem\n key={style.id}\n onClick={() =>\n setMapStyle(\n style.id as\n | \"default\"\n | \"streets\"\n | \"outdoors\"\n | \"satellite\"\n )\n }\n className={cn(\"gap-3\", mapStyle === style.id && \"bg-accent\")}\n >\n <Icon className=\"size-4 shrink-0\" />\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{style.name}</span>\n <span className=\"text-xs text-muted-foreground\">\n {style.description}\n </span>\n </div>\n </DropdownMenuItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n <Tooltip>\n <TooltipTrigger\n render={\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={handleZoomIn}\n className=\"h-9 w-9\"\n >\n <ZoomIn className=\"h-4 w-4\" />\n </Button>\n }\n />\n <TooltipContent>Zoom in</TooltipContent>\n </Tooltip>\n\n <Tooltip>\n <TooltipTrigger\n render={\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={handleZoomOut}\n className=\"h-9 w-9\"\n >\n <ZoomOut className=\"h-4 w-4\" />\n </Button>\n }\n />\n <TooltipContent>Zoom out</TooltipContent>\n </Tooltip>\n\n <Tooltip>\n <TooltipTrigger\n render={\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={handleLocate}\n className=\"h-9 w-9\"\n >\n <Navigation className=\"h-4 w-4\" />\n </Button>\n }\n />\n <TooltipContent>Locate me</TooltipContent>\n </Tooltip>\n </div>\n\n <div className=\"flex flex-col gap-2 rounded-lg border bg-background p-1 shadow-lg\">\n <ThemeToggle />\n </div>\n </div>\n )\n}\n"
19
+ },
20
+ {
21
+ "path": "registry/example-apps/default/rentals/components/dashboard/map-view.tsx",
22
+ "type": "registry:component",
23
+ "target": "components/example-apps/rentals/components/dashboard/map-view.tsx",
24
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport maplibregl from \"maplibre-gl\"\n\nimport \"maplibre-gl/dist/maplibre-gl.css\"\n\nimport { useTheme } from \"next-themes\"\n\nimport { propertyTypeLabels } from \"../../mock-data/listings\"\nimport { useRentalsStore } from \"../../store/rentals-store\"\n\nconst MAP_STYLES = {\n light: \"https://basemaps.cartocdn.com/gl/positron-gl-style/style.json\",\n dark: \"https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json\",\n streets: \"https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json\",\n outdoors: \"https://tiles.stadiamaps.com/styles/outdoors.json\",\n satellite: \"https://tiles.stadiamaps.com/styles/alidade_satellite.json\",\n}\n\nexport function MapView() {\n const containerRef = React.useRef<HTMLDivElement>(null)\n const mapRef = React.useRef<maplibregl.Map | null>(null)\n const markersRef = React.useRef<Map<string, maplibregl.Marker>>(new Map())\n const popupRef = React.useRef<maplibregl.Popup | null>(null)\n const isAnimatingRef = React.useRef(false)\n const { resolvedTheme } = useTheme()\n\n const {\n mapCenter,\n mapZoom,\n mapStyle,\n setMapCenter,\n setMapZoom,\n selectListing,\n selectedListingId,\n getFilteredListings,\n } = useRentalsStore()\n\n const listings = getFilteredListings()\n\n const getMapStyleUrl = React.useCallback(() => {\n if (mapStyle === \"default\") {\n return resolvedTheme === \"dark\" ? MAP_STYLES.dark : MAP_STYLES.light\n }\n return MAP_STYLES[mapStyle]\n }, [mapStyle, resolvedTheme])\n\n React.useEffect(() => {\n if (!containerRef.current || mapRef.current) return\n\n const map = new maplibregl.Map({\n container: containerRef.current,\n style: getMapStyleUrl(),\n center: [mapCenter.lng, mapCenter.lat],\n zoom: mapZoom,\n minZoom: 3,\n maxZoom: 18,\n attributionControl: false,\n })\n\n map.addControl(\n new maplibregl.AttributionControl({ compact: true }),\n \"bottom-right\"\n )\n\n map.on(\"moveend\", () => {\n if (isAnimatingRef.current) {\n isAnimatingRef.current = false\n return\n }\n const center = map.getCenter()\n const zoom = map.getZoom()\n setMapCenter({ lat: center.lat, lng: center.lng })\n setMapZoom(zoom)\n })\n\n mapRef.current = map\n\n const handleMapClick = (e: maplibregl.MapMouseEvent) => {\n if (popupRef.current) {\n const popupElement = popupRef.current.getElement()\n if (\n popupElement &&\n !popupElement.contains(e.originalEvent.target as Node)\n ) {\n const target = e.originalEvent.target as HTMLElement\n if (!target.closest(\".listing-marker-container\")) {\n popupRef.current.remove()\n popupRef.current = null\n selectListing(null)\n }\n }\n }\n }\n\n map.on(\"click\", handleMapClick)\n\n return () => {\n map.off(\"click\", handleMapClick)\n map.remove()\n mapRef.current = null\n }\n }, [selectListing])\n\n React.useEffect(() => {\n if (!mapRef.current) return\n mapRef.current.setStyle(getMapStyleUrl())\n }, [mapStyle, resolvedTheme, getMapStyleUrl])\n\n React.useEffect(() => {\n if (!mapRef.current) return\n\n markersRef.current.forEach((marker) => marker.remove())\n markersRef.current.clear()\n\n listings.forEach((listing) => {\n const isSelected = selectedListingId === listing.id\n\n const el = document.createElement(\"div\")\n el.className = \"listing-marker-container\"\n const priceText = `$${listing.pricePerNight}`\n el.innerHTML = `\n <div class=\"relative cursor-pointer transition-all ${\n isSelected ? \"scale-110 z-10\" : \"hover:scale-105\"\n }\">\n <div class=\"px-2.5 py-1.5 rounded-lg bg-card border-2 ${\n isSelected\n ? \"border-primary shadow-xl\"\n : \"border-border shadow-lg hover:shadow-xl\"\n } flex items-center justify-center min-w-[60px]\">\n <span class=\"text-sm font-semibold text-card-foreground whitespace-nowrap\">${priceText}</span>\n </div>\n ${\n isSelected\n ? '<div class=\"absolute -bottom-1 left-1/2 -translate-x-1/2 w-2 h-2 rounded-full bg-primary animate-ping\"></div>'\n : \"\"\n }\n </div>\n `\n\n el.addEventListener(\"click\", (e) => {\n e.stopPropagation()\n\n if (popupRef.current) {\n const currentPopup = popupRef.current\n const currentLngLat = currentPopup.getLngLat()\n if (\n currentLngLat.lng === listing.coordinates.lng &&\n currentLngLat.lat === listing.coordinates.lat\n ) {\n currentPopup.remove()\n popupRef.current = null\n selectListing(null)\n return\n }\n currentPopup.remove()\n }\n\n if (!mapRef.current) return\n\n const popupContent = `\n <div class=\"listing-popup-content\">\n <div class=\"relative w-full h-64 mb-4 rounded-t-lg overflow-hidden\">\n <img \n src=\"${listing.images[0]}\" \n alt=\"${listing.title}\"\n class=\"w-full h-full object-cover\"\n onerror=\"this.src='https://images.unsplash.com/photo-1516035069371-29a1b244cc32?w=600&h=400&fit=crop'\"\n />\n <button \n class=\"close-popup-btn absolute top-3 right-3 w-8 h-8 rounded-full bg-white/95 backdrop-blur-sm hover:bg-white flex items-center justify-center transition-all shadow-md hover:shadow-lg z-10\"\n aria-label=\"Close\"\n >\n <svg class=\"w-4 h-4 text-gray-700\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n <div class=\"px-4 pb-4\">\n <div class=\"flex items-start justify-between mb-2\">\n <div class=\"flex-1 min-w-0\">\n <h3 class=\"font-semibold text-base mb-1\">${\n propertyTypeLabels[listing.propertyType]\n } • ${listing.city}</h3>\n <p class=\"text-sm text-muted-foreground mb-2 line-clamp-2\">${\n listing.title\n }</p>\n </div>\n <div class=\"flex items-center gap-1 ml-2 shrink-0\">\n <svg class=\"w-4 h-4 fill-yellow-400 text-yellow-400\" viewBox=\"0 0 20 20\">\n <path d=\"M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z\" />\n </svg>\n <span class=\"text-sm font-medium\">${listing.rating.toFixed(\n 1\n )}</span>\n <span class=\"text-xs text-muted-foreground\">(${\n listing.reviewCount\n })</span>\n </div>\n </div>\n <div class=\"flex items-center gap-2 text-sm text-muted-foreground mb-3\">\n ${\n listing.bedrooms > 0\n ? `<span>${listing.bedrooms} kit${\n listing.bedrooms > 1 ? \"s\" : \"\"\n }</span>`\n : \"\"\n }\n ${\n listing.bedrooms > 0 && listing.bathrooms > 0\n ? \"<span>•</span>\"\n : \"\"\n }\n ${\n listing.bathrooms > 0\n ? `<span>${listing.bathrooms} add-on${\n listing.bathrooms > 1 ? \"s\" : \"\"\n }</span>`\n : \"\"\n }\n </div>\n <div class=\"flex items-baseline gap-2\">\n <span class=\"text-xl font-semibold\">$${\n listing.pricePerNight\n }</span>\n <span class=\"text-sm text-muted-foreground\">/ day</span>\n </div>\n </div>\n </div>\n `\n\n const point = mapRef.current.project([\n listing.coordinates.lng,\n listing.coordinates.lat,\n ])\n const mapHeight = mapRef.current.getContainer().clientHeight\n const mapWidth = mapRef.current.getContainer().clientWidth\n\n const isNearBottom = point.y > mapHeight * 0.7\n const isNearTop = point.y < mapHeight * 0.3\n const isNearRight = point.x > mapWidth * 0.7\n const isNearLeft = point.x < mapWidth * 0.3\n\n let offsetX = 0\n let offsetY = -30\n\n if (isNearBottom) {\n offsetY = 20\n } else if (isNearTop) {\n offsetY = -60\n }\n\n if (isNearRight) {\n offsetX = -20\n } else if (isNearLeft) {\n offsetX = 20\n }\n\n const popup = new maplibregl.Popup({\n offset: [offsetX, offsetY],\n closeButton: false,\n closeOnClick: false,\n className: \"listing-popup\",\n maxWidth: \"400px\",\n })\n .setLngLat([listing.coordinates.lng, listing.coordinates.lat])\n .setHTML(popupContent)\n .addTo(mapRef.current!)\n\n const popupElement = popup.getElement()\n if (popupElement) {\n popupElement.style.zIndex = \"1000\"\n\n const closeButton = popupElement.querySelector(\".close-popup-btn\")\n if (closeButton) {\n closeButton.addEventListener(\"click\", (e) => {\n e.stopPropagation()\n popup.remove()\n popupRef.current = null\n selectListing(null)\n })\n }\n\n popupElement.addEventListener(\"click\", (e) => {\n e.stopPropagation()\n if (mapRef.current) {\n isAnimatingRef.current = true\n mapRef.current.flyTo({\n center: [listing.coordinates.lng, listing.coordinates.lat],\n zoom: Math.max(mapRef.current.getZoom(), 14),\n essential: true,\n })\n }\n })\n }\n\n popupRef.current = popup\n selectListing(listing.id)\n })\n\n const marker = new maplibregl.Marker({ element: el })\n .setLngLat([listing.coordinates.lng, listing.coordinates.lat])\n .addTo(mapRef.current!)\n\n markersRef.current.set(listing.id, marker)\n })\n }, [listings, selectedListingId, selectListing])\n\n const lastCenterRef = React.useRef({\n lat: mapCenter.lat,\n lng: mapCenter.lng,\n })\n const lastZoomRef = React.useRef(mapZoom)\n\n React.useEffect(() => {\n if (!mapRef.current) return\n\n const centerChanged =\n Math.abs(lastCenterRef.current.lat - mapCenter.lat) > 0.0001 ||\n Math.abs(lastCenterRef.current.lng - mapCenter.lng) > 0.0001\n const zoomChanged = Math.abs(lastZoomRef.current - mapZoom) > 0.1\n\n if (centerChanged || zoomChanged) {\n isAnimatingRef.current = true\n mapRef.current.flyTo({\n center: [mapCenter.lng, mapCenter.lat],\n zoom: mapZoom,\n essential: true,\n })\n lastCenterRef.current = { lat: mapCenter.lat, lng: mapCenter.lng }\n lastZoomRef.current = mapZoom\n }\n }, [mapCenter, mapZoom])\n\n return <div ref={containerRef} className=\"absolute inset-0 h-full w-full\" />\n}\n"
25
+ },
26
+ {
27
+ "path": "registry/example-apps/default/rentals/components/dashboard/sidebar.tsx",
28
+ "type": "registry:component",
29
+ "target": "components/example-apps/rentals/components/dashboard/sidebar.tsx",
30
+ "content": "\"use client\"\n\nimport Link from \"next/link\"\nimport { usePathname } from \"next/navigation\"\nimport {\n ChevronsUpDown,\n Heart,\n Home,\n LogOut,\n Minus,\n Plus,\n Search,\n Settings,\n} from \"lucide-react\"\n\nimport { Button } from \"@loveui/ui/ui/button\"\nimport { Input } from \"@loveui/ui/ui/input\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@loveui/ui/ui/menu\"\nimport { Separator } from \"@loveui/ui/ui/separator\"\nimport { Slider } from \"@loveui/ui/ui/slider\"\n\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n} from \"@/components/ui/sidebar\"\n\nimport { cn } from \"../../lib/utils\"\nimport { propertyTypeLabels, type PropertyType } from \"../../mock-data/listings\"\nimport { useRentalsStore } from \"../../store/rentals-store\"\n\nconst navItems = [\n { id: \"all\", title: \"All Gear\", icon: Home, href: \"/\" },\n { id: \"favorites\", title: \"Favorites\", icon: Heart, href: \"/favorites\" },\n]\n\nconst propertyTypes: PropertyType[] = [\n \"apartment\",\n \"house\",\n \"villa\",\n \"studio\",\n \"loft\",\n \"cottage\",\n]\n\nexport function RentalsSidebar({\n ...props\n}: React.ComponentProps<typeof Sidebar>) {\n const pathname = usePathname()\n const {\n listings,\n searchQuery,\n setSearchQuery,\n selectedPropertyTypes,\n togglePropertyType,\n priceRange,\n setPriceRange,\n bedrooms,\n setBedrooms,\n bathrooms,\n setBathrooms,\n getFilteredListings,\n getFavoriteListings,\n resetFilters,\n } = useRentalsStore()\n\n const favoriteCount = listings.filter((l) => l.isFavorite).length\n const allCount = listings.length\n const filteredCount = getFilteredListings().length\n\n const activeFiltersCount =\n selectedPropertyTypes.length +\n (priceRange[0] !== 0 || priceRange[1] !== 500 ? 1 : 0) +\n (bedrooms !== null ? 1 : 0) +\n (bathrooms !== null ? 1 : 0)\n\n return (\n <Sidebar collapsible=\"offcanvas\" {...props}>\n <SidebarHeader className=\"px-2.5 py-3\">\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <button className=\"-m-1 flex w-full shrink-0 items-center gap-2.5 rounded-md p-1 transition-colors hover:bg-sidebar-accent\">\n <div className=\"flex size-7 shrink-0 items-center justify-center rounded-lg bg-primary text-primary-foreground\">\n <Home className=\"size-4\" />\n </div>\n <div className=\"flex items-center gap-1 group-data-[collapsible=icon]:hidden\">\n <span className=\"text-sm font-medium\">\n LoveUI - Gear Market\n </span>\n <ChevronsUpDown className=\"size-3 text-muted-foreground\" />\n </div>\n </button>\n }\n />\n <DropdownMenuContent align=\"start\" className=\"w-56\">\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <Settings className=\"size-4\" />\n <span>Settings</span>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem className=\"text-destructive focus:text-destructive\">\n <LogOut className=\"size-4\" />\n <span>Log out</span>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarHeader>\n\n <SidebarContent className=\"px-2.5\">\n <SidebarGroup className=\"p-0\">\n <SidebarGroupContent>\n <SidebarMenu>\n {navItems.map((item) => {\n const isActive = pathname === item.href\n let badge: number | undefined\n if (item.id === \"favorites\") badge = favoriteCount\n if (item.id === \"all\") badge = allCount\n\n return (\n <SidebarMenuItem key={item.id}>\n <SidebarMenuButton\n render={<Link href={item.href} />}\n isActive={isActive}\n className=\"h-8\"\n >\n <item.icon className=\"size-4\" />\n <span className=\"text-sm\">{item.title}</span>\n </SidebarMenuButton>\n {badge !== undefined && badge > 0 && (\n <SidebarMenuBadge>{badge}</SidebarMenuBadge>\n )}\n </SidebarMenuItem>\n )\n })}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n\n <SidebarGroup className=\"mt-4 p-0\">\n <SidebarGroupLabel className=\"h-6 px-0\">\n <span className=\"text-[10px] font-medium tracking-wider text-muted-foreground uppercase\">\n Search\n </span>\n </SidebarGroupLabel>\n <SidebarGroupContent>\n <div className=\"px-2 pb-2\">\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute top-1/2 left-2 z-10 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n type=\"text\"\n placeholder=\"Search products...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"h-8 pl-7 text-sm\"\n />\n </div>\n </div>\n </SidebarGroupContent>\n </SidebarGroup>\n\n <SidebarGroup className=\"mt-4 p-0\">\n <SidebarGroupLabel className=\"flex h-6 items-center justify-between px-0\">\n <span className=\"text-[10px] font-medium tracking-wider text-muted-foreground uppercase\">\n Filters\n </span>\n {activeFiltersCount > 0 && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-5 px-1.5 text-[10px]\"\n onClick={resetFilters}\n >\n Clear\n </Button>\n )}\n </SidebarGroupLabel>\n <SidebarGroupContent>\n <div className=\"space-y-4 px-2\">\n <div>\n <p className=\"mb-2 text-xs font-medium text-sidebar-foreground\">\n Category\n </p>\n <div className=\"flex flex-wrap gap-1.5\">\n {propertyTypes.map((type) => (\n <Button\n key={type}\n variant={\n selectedPropertyTypes.includes(type)\n ? \"default\"\n : \"outline\"\n }\n size=\"sm\"\n onClick={() => togglePropertyType(type)}\n className={cn(\n \"h-7 px-2 text-xs\",\n selectedPropertyTypes.includes(type) &&\n \"bg-primary text-primary-foreground\"\n )}\n >\n {propertyTypeLabels[type]}\n </Button>\n ))}\n </div>\n </div>\n\n <Separator />\n\n <div>\n <p className=\"mb-2 text-xs font-medium text-sidebar-foreground\">\n Daily rate\n </p>\n <div className=\"space-y-2\">\n <div className=\"px-2\">\n <Slider\n value={[priceRange[0], priceRange[1]]}\n onValueChange={(value) => {\n const range = (\n Array.isArray(value) ? value : [value, value]\n ) as readonly number[]\n setPriceRange([\n range[0] ?? 0,\n range[1] ?? range[0] ?? 0,\n ])\n }}\n min={0}\n max={500}\n step={10}\n className=\"w-full\"\n />\n <div className=\"mt-2 flex items-center justify-between\">\n <span className=\"text-xs text-muted-foreground\">\n ${priceRange[0]}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n ${priceRange[1]}\n </span>\n </div>\n </div>\n </div>\n </div>\n\n <Separator />\n\n <div>\n <p className=\"mb-2 text-xs font-medium text-sidebar-foreground\">\n Inventory\n </p>\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-sidebar-foreground\">\n Kits\n </span>\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={() =>\n setBedrooms(\n bedrooms !== null && bedrooms > 0\n ? bedrooms - 1\n : null\n )\n }\n >\n <Minus className=\"h-3 w-3\" />\n </Button>\n <span className=\"w-6 text-center text-xs\">\n {bedrooms ?? \"Any\"}\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={() => setBedrooms((bedrooms ?? 0) + 1)}\n >\n <Plus className=\"h-3 w-3\" />\n </Button>\n </div>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-sidebar-foreground\">\n Add-ons\n </span>\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={() =>\n setBathrooms(\n bathrooms !== null && bathrooms > 0\n ? bathrooms - 1\n : null\n )\n }\n >\n <Minus className=\"h-3 w-3\" />\n </Button>\n <span className=\"w-6 text-center text-xs\">\n {bathrooms ?? \"Any\"}\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={() => setBathrooms((bathrooms ?? 0) + 1)}\n >\n <Plus className=\"h-3 w-3\" />\n </Button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </SidebarGroupContent>\n </SidebarGroup>\n </SidebarContent>\n </Sidebar>\n )\n}\n"
31
+ },
32
+ {
33
+ "path": "registry/example-apps/default/rentals/components/theme-provider.tsx",
34
+ "type": "registry:component",
35
+ "target": "components/example-apps/rentals/components/theme-provider.tsx",
36
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { ThemeProvider as NextThemesProvider } from \"next-themes\"\n\nexport function ThemeProvider({\n children,\n ...props\n}: React.ComponentProps<typeof NextThemesProvider>) {\n return <NextThemesProvider {...props}>{children}</NextThemesProvider>\n}\n"
37
+ },
38
+ {
39
+ "path": "registry/example-apps/default/rentals/components/theme-toggle.tsx",
40
+ "type": "registry:component",
41
+ "target": "components/example-apps/rentals/components/theme-toggle.tsx",
42
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Moon, Sun } from \"lucide-react\"\nimport { useTheme } from \"next-themes\"\n\nimport { Button } from \"@loveui/ui/ui/button\"\n\ninterface ThemeToggleProps {\n className?: string\n}\n\nexport function ThemeToggle({ className }: ThemeToggleProps) {\n const { setTheme, theme } = useTheme()\n\n return (\n <Button\n variant=\"outline\"\n size=\"icon\"\n className={className}\n onClick={() => setTheme(theme === \"light\" ? \"dark\" : \"light\")}\n >\n <Sun className=\"size-5 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90\" />\n <Moon className=\"absolute size-5 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0\" />\n <span className=\"sr-only\">Toggle theme</span>\n </Button>\n )\n}\n"
43
+ },
44
+ {
45
+ "path": "registry/example-apps/default/rentals/components/ui/badge.tsx",
46
+ "type": "registry:ui",
47
+ "target": "components/example-apps/rentals/components/ui/badge.tsx",
48
+ "content": "import { mergeProps } from \"@base-ui/react/merge-props\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../../lib/utils\"\n\nconst badgeVariants = cva(\n \"group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all transition-colors focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n secondary:\n \"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80\",\n destructive:\n \"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20\",\n outline:\n \"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground\",\n ghost:\n \"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Badge({\n className,\n variant = \"default\",\n render,\n ...props\n}: useRender.ComponentProps<\"span\"> & VariantProps<typeof badgeVariants>) {\n return useRender({\n defaultTagName: \"span\",\n props: mergeProps<\"span\">(\n {\n className: cn(badgeVariants({ className, variant })),\n },\n props\n ),\n render,\n state: {\n slot: \"badge\",\n variant,\n },\n })\n}\n\nexport { Badge, badgeVariants }\n"
49
+ },
50
+ {
51
+ "path": "registry/example-apps/default/rentals/components/ui/button.tsx",
52
+ "type": "registry:ui",
53
+ "target": "components/example-apps/rentals/components/ui/button.tsx",
54
+ "content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../../lib/utils\"\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 cursor-pointer items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/80\",\n outline:\n \"border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n xs: \"h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5\",\n lg: \"h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3\",\n icon: \"size-9\",\n \"icon-xs\":\n \"size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\":\n \"size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean\n}\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n ...props\n}: ButtonProps) {\n const Comp: any = asChild ? Slot : \"button\"\n return (\n <Comp\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...(props as any)}\n />\n )\n}\n\nexport { Button, buttonVariants }\n"
55
+ },
56
+ {
57
+ "path": "registry/example-apps/default/rentals/components/ui/carousel.tsx",
58
+ "type": "registry:ui",
59
+ "target": "components/example-apps/rentals/components/ui/carousel.tsx",
60
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport useEmblaCarousel, {\n type UseEmblaCarouselType,\n} from \"embla-carousel-react\"\nimport { ArrowLeft, ArrowRight } from \"lucide-react\"\n\nimport { cn } from \"../../lib/utils\"\nimport { Button } from \"./button\"\n\ntype CarouselApi = UseEmblaCarouselType[1]\ntype UseCarouselParameters = Parameters<typeof useEmblaCarousel>\ntype CarouselOptions = UseCarouselParameters[0]\ntype CarouselPlugin = UseCarouselParameters[1]\n\ntype CarouselProps = {\n opts?: CarouselOptions\n plugins?: CarouselPlugin\n orientation?: \"horizontal\" | \"vertical\"\n setApi?: (api: CarouselApi) => void\n}\n\ntype CarouselContextProps = {\n carouselRef: ReturnType<typeof useEmblaCarousel>[0]\n api: ReturnType<typeof useEmblaCarousel>[1]\n scrollPrev: () => void\n scrollNext: () => void\n canScrollPrev: boolean\n canScrollNext: boolean\n} & CarouselProps\n\nconst CarouselContext = React.createContext<CarouselContextProps | null>(null)\n\nfunction useCarousel() {\n const context = React.useContext(CarouselContext)\n\n if (!context) {\n throw new Error(\"useCarousel must be used within a <Carousel />\")\n }\n\n return context\n}\n\nfunction Carousel({\n orientation = \"horizontal\",\n opts,\n setApi,\n plugins,\n className,\n children,\n ...props\n}: React.ComponentProps<\"div\"> & CarouselProps) {\n const [carouselRef, api] = useEmblaCarousel(\n {\n ...opts,\n axis: orientation === \"horizontal\" ? \"x\" : \"y\",\n },\n plugins\n )\n const [canScrollPrev, setCanScrollPrev] = React.useState(false)\n const [canScrollNext, setCanScrollNext] = React.useState(false)\n\n const onSelect = React.useCallback((api: CarouselApi) => {\n if (!api) return\n setCanScrollPrev(api.canScrollPrev())\n setCanScrollNext(api.canScrollNext())\n }, [])\n\n const scrollPrev = React.useCallback(() => {\n api?.scrollPrev()\n }, [api])\n\n const scrollNext = React.useCallback(() => {\n api?.scrollNext()\n }, [api])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"ArrowLeft\") {\n event.preventDefault()\n scrollPrev()\n } else if (event.key === \"ArrowRight\") {\n event.preventDefault()\n scrollNext()\n }\n },\n [scrollPrev, scrollNext]\n )\n\n React.useEffect(() => {\n if (!api || !setApi) return\n setApi(api)\n }, [api, setApi])\n\n React.useEffect(() => {\n if (!api) return\n onSelect(api)\n api.on(\"reInit\", onSelect)\n api.on(\"select\", onSelect)\n\n return () => {\n api?.off(\"select\", onSelect)\n }\n }, [api, onSelect])\n\n return (\n <CarouselContext.Provider\n value={{\n carouselRef,\n api: api,\n opts,\n orientation:\n orientation || (opts?.axis === \"y\" ? \"vertical\" : \"horizontal\"),\n scrollPrev,\n scrollNext,\n canScrollPrev,\n canScrollNext,\n }}\n >\n <div\n onKeyDownCapture={handleKeyDown}\n className={cn(\"relative\", className)}\n role=\"region\"\n aria-roledescription=\"carousel\"\n data-slot=\"carousel\"\n {...props}\n >\n {children}\n </div>\n </CarouselContext.Provider>\n )\n}\n\nfunction CarouselContent({ className, ...props }: React.ComponentProps<\"div\">) {\n const { carouselRef, orientation } = useCarousel()\n\n return (\n <div\n ref={carouselRef}\n className=\"overflow-hidden\"\n data-slot=\"carousel-content\"\n >\n <div\n className={cn(\n \"flex\",\n orientation === \"horizontal\" ? \"-ml-4\" : \"-mt-4 flex-col\",\n className\n )}\n {...props}\n />\n </div>\n )\n}\n\nfunction CarouselItem({ className, ...props }: React.ComponentProps<\"div\">) {\n const { orientation } = useCarousel()\n\n return (\n <div\n role=\"group\"\n aria-roledescription=\"slide\"\n data-slot=\"carousel-item\"\n className={cn(\n \"min-w-0 shrink-0 grow-0 basis-full\",\n orientation === \"horizontal\" ? \"pl-4\" : \"pt-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CarouselPrevious({\n className,\n variant = \"outline\",\n size = \"icon\",\n ...props\n}: React.ComponentProps<typeof Button>) {\n const { orientation, scrollPrev, canScrollPrev } = useCarousel()\n\n return (\n <>\n {canScrollPrev && (\n <Button\n data-slot=\"carousel-previous\"\n variant={variant}\n size={size}\n className={cn(\n \"absolute size-8 rounded-full\",\n orientation === \"horizontal\"\n ? \"top-1/2 -left-12 -translate-y-1/2\"\n : \"-top-12 left-1/2 -translate-x-1/2 rotate-90\",\n className\n )}\n onClick={(e) => {\n e.stopPropagation()\n scrollPrev()\n }}\n {...props}\n >\n <ArrowLeft className=\"size-4\" />\n <span className=\"sr-only\">Previous slide</span>\n </Button>\n )}\n </>\n )\n}\n\nfunction CarouselNext({\n className,\n variant = \"outline\",\n size = \"icon\",\n ...props\n}: React.ComponentProps<typeof Button>) {\n const { orientation, scrollNext, canScrollNext } = useCarousel()\n\n return (\n <>\n {canScrollNext && (\n <Button\n data-slot=\"carousel-next\"\n variant={variant}\n size={size}\n className={cn(\n \"absolute size-8 rounded-full\",\n orientation === \"horizontal\"\n ? \"top-1/2 -right-12 -translate-y-1/2\"\n : \"-bottom-12 left-1/2 -translate-x-1/2 rotate-90\",\n className\n )}\n onClick={(e) => {\n e.stopPropagation()\n scrollNext()\n }}\n {...props}\n >\n <ArrowRight className=\"size-4\" />\n <span className=\"sr-only\">Next slide</span>\n </Button>\n )}\n </>\n )\n}\n\nexport {\n type CarouselApi,\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselPrevious,\n CarouselNext,\n}\n"
61
+ },
62
+ {
63
+ "path": "registry/example-apps/default/rentals/components/ui/dropdown-menu.tsx",
64
+ "type": "registry:ui",
65
+ "target": "components/example-apps/rentals/components/ui/dropdown-menu.tsx",
66
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\"\nimport { Check, ChevronRight } from \"lucide-react\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {\n return <MenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\n\nfunction DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {\n return <MenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />\n}\n\nfunction DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {\n return <MenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />\n}\n\nfunction DropdownMenuContent({\n align = \"start\",\n alignOffset = 0,\n side = \"bottom\",\n sideOffset = 4,\n className,\n ...props\n}: MenuPrimitive.Popup.Props &\n Pick<\n MenuPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.Positioner\n className=\"isolate z-50 outline-none\"\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n >\n <MenuPrimitive.Popup\n data-slot=\"dropdown-menu-content\"\n className={cn(\n \"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-closed:overflow-hidden\",\n className\n )}\n {...props}\n />\n </MenuPrimitive.Positioner>\n </MenuPrimitive.Portal>\n )\n}\n\nfunction DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {\n return <MenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: MenuPrimitive.GroupLabel.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.GroupLabel\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(\n \"px-2 py-1.5 text-xs font-medium text-muted-foreground data-[inset]:pl-8\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: MenuPrimitive.Item.Props & {\n inset?: boolean\n variant?: \"default\" | \"destructive\"\n}) {\n return (\n <MenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"group/dropdown-menu-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {\n return <MenuPrimitive.SubmenuRoot data-slot=\"dropdown-menu-sub\" {...props} />\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: MenuPrimitive.SubmenuTrigger.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.SubmenuTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" />\n </MenuPrimitive.SubmenuTrigger>\n )\n}\n\nfunction DropdownMenuSubContent({\n align = \"start\",\n alignOffset = -3,\n side = \"right\",\n sideOffset = 0,\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuContent>) {\n return (\n <DropdownMenuContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n \"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 w-auto min-w-[96px] rounded-md bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100\",\n className\n )}\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: MenuPrimitive.CheckboxItem.Props) {\n return (\n <MenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span\n className=\"pointer-events-none absolute right-2 flex items-center justify-center\"\n data-slot=\"dropdown-menu-checkbox-item-indicator\"\n >\n <MenuPrimitive.CheckboxItemIndicator>\n <Check className=\"size-4\" />\n </MenuPrimitive.CheckboxItemIndicator>\n </span>\n {children}\n </MenuPrimitive.CheckboxItem>\n )\n}\n\nfunction DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {\n return (\n <MenuPrimitive.RadioGroup\n data-slot=\"dropdown-menu-radio-group\"\n {...props}\n />\n )\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n ...props\n}: MenuPrimitive.RadioItem.Props) {\n return (\n <MenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <span\n className=\"pointer-events-none absolute right-2 flex items-center justify-center\"\n data-slot=\"dropdown-menu-radio-item-indicator\"\n >\n <MenuPrimitive.RadioItemIndicator>\n <Check className=\"size-4\" />\n </MenuPrimitive.RadioItemIndicator>\n </span>\n {children}\n </MenuPrimitive.RadioItem>\n )\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: MenuPrimitive.Separator.Props) {\n return (\n <MenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(\n \"ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n}\n"
67
+ },
68
+ {
69
+ "path": "registry/example-apps/default/rentals/components/ui/input.tsx",
70
+ "type": "registry:ui",
71
+ "target": "components/example-apps/rentals/components/ui/input.tsx",
72
+ "content": "import * as React from \"react\"\nimport { Input as InputPrimitive } from \"@base-ui/react/input\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n return (\n <InputPrimitive\n type={type}\n data-slot=\"input\"\n className={cn(\n \"h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-2.5 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-[3px] aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Input }\n"
73
+ },
74
+ {
75
+ "path": "registry/example-apps/default/rentals/components/ui/separator.tsx",
76
+ "type": "registry:ui",
77
+ "target": "components/example-apps/rentals/components/ui/separator.tsx",
78
+ "content": "\"use client\"\n\nimport { Separator as SeparatorPrimitive } from \"@base-ui/react/separator\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Separator({\n className,\n orientation = \"horizontal\",\n ...props\n}: SeparatorPrimitive.Props) {\n return (\n <SeparatorPrimitive\n data-slot=\"separator\"\n orientation={orientation}\n className={cn(\n \"shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Separator }\n"
79
+ },
80
+ {
81
+ "path": "registry/example-apps/default/rentals/components/ui/sheet.tsx",
82
+ "type": "registry:ui",
83
+ "target": "components/example-apps/rentals/components/ui/sheet.tsx",
84
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Dialog as SheetPrimitive } from \"@base-ui/react/dialog\"\nimport { X } from \"lucide-react\"\n\nimport { cn } from \"../../lib/utils\"\nimport { Button } from \"./button\"\n\nfunction Sheet({ ...props }: SheetPrimitive.Root.Props) {\n return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />\n}\n\nfunction SheetTrigger({ ...props }: SheetPrimitive.Trigger.Props) {\n return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />\n}\n\nfunction SheetClose({ ...props }: SheetPrimitive.Close.Props) {\n return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />\n}\n\nfunction SheetPortal({ ...props }: SheetPrimitive.Portal.Props) {\n return <SheetPrimitive.Portal data-slot=\"sheet-portal\" {...props} />\n}\n\nfunction SheetOverlay({ className, ...props }: SheetPrimitive.Backdrop.Props) {\n return (\n <SheetPrimitive.Backdrop\n data-slot=\"sheet-overlay\"\n className={cn(\n \"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 bg-black/10 duration-100 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction SheetContent({\n className,\n children,\n side = \"right\",\n showCloseButton = true,\n ...props\n}: SheetPrimitive.Popup.Props & {\n side?: \"top\" | \"right\" | \"bottom\" | \"left\"\n showCloseButton?: boolean\n}) {\n return (\n <SheetPortal>\n <SheetOverlay />\n <SheetPrimitive.Popup\n data-slot=\"sheet-content\"\n data-side={side}\n className={cn(\n \"data-open:animate-in data-closed:animate-out data-[side=right]:data-closed:slide-out-to-right-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=top]:data-closed:slide-out-to-top-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:fade-out-0 data-open:fade-in-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=bottom]:data-open:slide-in-from-bottom-10 fixed z-50 flex flex-col gap-4 bg-background bg-clip-padding text-sm shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm\",\n className\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <SheetPrimitive.Close\n data-slot=\"sheet-close\"\n render={\n <Button\n variant=\"ghost\"\n className=\"absolute top-4 right-4\"\n size=\"icon-sm\"\n />\n }\n >\n <X className=\"size-4\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n )}\n </SheetPrimitive.Popup>\n </SheetPortal>\n )\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sheet-header\"\n className={cn(\"flex flex-col gap-1.5 p-4\", className)}\n {...props}\n />\n )\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sheet-footer\"\n className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n {...props}\n />\n )\n}\n\nfunction SheetTitle({ className, ...props }: SheetPrimitive.Title.Props) {\n return (\n <SheetPrimitive.Title\n data-slot=\"sheet-title\"\n className={cn(\"font-medium text-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction SheetDescription({\n className,\n ...props\n}: SheetPrimitive.Description.Props) {\n return (\n <SheetPrimitive.Description\n data-slot=\"sheet-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Sheet,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n}\n"
85
+ },
86
+ {
87
+ "path": "registry/example-apps/default/rentals/components/ui/sidebar.tsx",
88
+ "type": "registry:ui",
89
+ "target": "components/example-apps/rentals/components/ui/sidebar.tsx",
90
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { mergeProps } from \"@base-ui/react/merge-props\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { PanelLeft } from \"lucide-react\"\n\nimport { useIsMobile } from \"../../hooks/use-mobile\"\nimport { cn } from \"../../lib/utils\"\nimport { Button } from \"./button\"\nimport { Input } from \"./input\"\nimport { Separator } from \"./separator\"\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from \"./sheet\"\nimport { Skeleton } from \"./skeleton\"\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"./tooltip\"\n\nconst SIDEBAR_COOKIE_NAME = \"sidebar_state\"\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7\nconst SIDEBAR_WIDTH = \"16rem\"\nconst SIDEBAR_WIDTH_MOBILE = \"18rem\"\nconst SIDEBAR_WIDTH_ICON = \"3rem\"\nconst SIDEBAR_KEYBOARD_SHORTCUT = \"b\"\n\ntype SidebarContextProps = {\n state: \"expanded\" | \"collapsed\"\n open: boolean\n setOpen: (open: boolean) => void\n openMobile: boolean\n setOpenMobile: (open: boolean) => void\n isMobile: boolean\n toggleSidebar: () => void\n}\n\nconst SidebarContext = React.createContext<SidebarContextProps | null>(null)\n\nfunction useSidebar() {\n const context = React.useContext(SidebarContext)\n if (!context) {\n throw new Error(\"useSidebar must be used within a SidebarProvider.\")\n }\n\n return context\n}\n\nfunction SidebarProvider({\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n className,\n style,\n children,\n ...props\n}: React.ComponentProps<\"div\"> & {\n defaultOpen?: boolean\n open?: boolean\n onOpenChange?: (open: boolean) => void\n}) {\n const isMobile = useIsMobile()\n const [openMobile, setOpenMobile] = React.useState(false)\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen)\n const open = openProp ?? _open\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === \"function\" ? value(open) : value\n if (setOpenProp) {\n setOpenProp(openState)\n } else {\n _setOpen(openState)\n }\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n },\n [setOpenProp, open]\n )\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)\n }, [isMobile, setOpen, setOpenMobile])\n\n // Adds a keyboard shortcut to toggle the sidebar.\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (\n event.key === SIDEBAR_KEYBOARD_SHORTCUT &&\n (event.metaKey || event.ctrlKey)\n ) {\n event.preventDefault()\n toggleSidebar()\n }\n }\n\n window.addEventListener(\"keydown\", handleKeyDown)\n return () => window.removeEventListener(\"keydown\", handleKeyDown)\n }, [toggleSidebar])\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? \"expanded\" : \"collapsed\"\n\n const contextValue = React.useMemo<SidebarContextProps>(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n }),\n [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]\n )\n\n return (\n <SidebarContext.Provider value={contextValue}>\n <div\n data-slot=\"sidebar-wrapper\"\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH,\n \"--sidebar-width-icon\": SIDEBAR_WIDTH_ICON,\n ...style,\n } as any\n }\n className={cn(\n \"group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n </SidebarContext.Provider>\n )\n}\n\nfunction Sidebar({\n side = \"left\",\n variant = \"sidebar\",\n collapsible = \"offcanvas\",\n className,\n children,\n ...props\n}: React.ComponentProps<\"div\"> & {\n side?: \"left\" | \"right\"\n variant?: \"sidebar\" | \"floating\" | \"inset\"\n collapsible?: \"offcanvas\" | \"icon\" | \"none\"\n}) {\n const { isMobile, state, openMobile, setOpenMobile } = useSidebar()\n\n if (collapsible === \"none\") {\n return (\n <div\n data-slot=\"sidebar\"\n className={cn(\n \"flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n )\n }\n\n if (isMobile) {\n return (\n <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>\n <SheetContent\n data-sidebar=\"sidebar\"\n data-slot=\"sidebar\"\n data-mobile=\"true\"\n className=\"top-[var(--sidebar-top-offset,0px)] h-[calc(100svh-var(--sidebar-top-offset,0px))] w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden\"\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH_MOBILE,\n } as any\n }\n side={side}\n >\n <SheetHeader className=\"sr-only\">\n <SheetTitle>Sidebar</SheetTitle>\n <SheetDescription>Displays the mobile sidebar.</SheetDescription>\n </SheetHeader>\n <div className=\"flex h-full w-full flex-col\">{children}</div>\n </SheetContent>\n </Sheet>\n )\n }\n\n return (\n <div\n className=\"group peer hidden text-sidebar-foreground md:block\"\n data-state={state}\n data-collapsible={state === \"collapsed\" ? collapsible : \"\"}\n data-variant={variant}\n data-side={side}\n data-slot=\"sidebar\"\n >\n {/* This is what handles the sidebar gap on desktop */}\n <div\n data-slot=\"sidebar-gap\"\n className={cn(\n \"relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear\",\n \"group-data-[collapsible=offcanvas]:w-0\",\n \"group-data-[side=right]:rotate-180\",\n variant === \"floating\" || variant === \"inset\"\n ? \"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]\"\n : \"group-data-[collapsible=icon]:w-(--sidebar-width-icon)\"\n )}\n />\n <div\n data-slot=\"sidebar-container\"\n className={cn(\n \"fixed top-[var(--sidebar-top-offset,0px)] bottom-0 z-10 hidden h-[calc(100svh-var(--sidebar-top-offset,0px))] w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex\",\n side === \"left\"\n ? \"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]\"\n : \"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]\",\n // Adjust the padding for floating and inset variants.\n variant === \"floating\" || variant === \"inset\"\n ? \"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]\"\n : \"group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l\",\n className\n )}\n {...props}\n >\n <div\n data-sidebar=\"sidebar\"\n data-slot=\"sidebar-inner\"\n className=\"flex size-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1 group-data-[variant=floating]:ring-sidebar-border\"\n >\n {children}\n </div>\n </div>\n </div>\n )\n}\n\nfunction SidebarTrigger({\n className,\n onClick,\n ...props\n}: React.ComponentProps<typeof Button>) {\n const { toggleSidebar } = useSidebar()\n\n return (\n <Button\n data-sidebar=\"trigger\"\n data-slot=\"sidebar-trigger\"\n variant=\"ghost\"\n size=\"icon-sm\"\n className={cn(className)}\n onClick={(event) => {\n onClick?.(event)\n toggleSidebar()\n }}\n {...props}\n >\n <PanelLeft className=\"size-4\" />\n <span className=\"sr-only\">Toggle Sidebar</span>\n </Button>\n )\n}\n\nfunction SidebarRail({ className, ...props }: React.ComponentProps<\"button\">) {\n const { toggleSidebar } = useSidebar()\n\n return (\n <button\n data-sidebar=\"rail\"\n data-slot=\"sidebar-rail\"\n aria-label=\"Toggle Sidebar\"\n tabIndex={-1}\n onClick={toggleSidebar}\n title=\"Toggle Sidebar\"\n className={cn(\n \"absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex\",\n \"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize\",\n \"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize\",\n \"group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar\",\n \"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2\",\n \"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction SidebarInset({ className, ...props }: React.ComponentProps<\"main\">) {\n return (\n <main\n data-slot=\"sidebar-inset\"\n className={cn(\n \"relative flex w-full flex-1 flex-col bg-background md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction SidebarInput({\n className,\n ...props\n}: React.ComponentProps<typeof Input>) {\n return (\n <Input\n data-slot=\"sidebar-input\"\n data-sidebar=\"input\"\n className={cn(\"h-8 w-full bg-background shadow-none\", className)}\n {...props}\n />\n )\n}\n\nfunction SidebarHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-header\"\n data-sidebar=\"header\"\n className={cn(\"flex flex-col gap-2 p-2\", className)}\n {...props}\n />\n )\n}\n\nfunction SidebarFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-footer\"\n data-sidebar=\"footer\"\n className={cn(\"flex flex-col gap-2 p-2\", className)}\n {...props}\n />\n )\n}\n\nfunction SidebarSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"sidebar-separator\"\n data-sidebar=\"separator\"\n className={cn(\"mx-2 w-auto bg-sidebar-border\", className)}\n {...props}\n />\n )\n}\n\nfunction SidebarContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-content\"\n data-sidebar=\"content\"\n className={cn(\n \"no-scrollbar flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction SidebarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-group\"\n data-sidebar=\"group\"\n className={cn(\"relative flex w-full min-w-0 flex-col p-2\", className)}\n {...props}\n />\n )\n}\n\nfunction SidebarGroupLabel({\n className,\n render,\n ...props\n}: useRender.ComponentProps<\"div\"> & React.ComponentProps<\"div\">) {\n return useRender({\n defaultTagName: \"div\",\n props: mergeProps<\"div\">(\n {\n className: cn(\n \"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n className\n ),\n },\n props\n ),\n render,\n state: {\n slot: \"sidebar-group-label\",\n sidebar: \"group-label\",\n },\n })\n}\n\nfunction SidebarGroupAction({\n className,\n render,\n ...props\n}: useRender.ComponentProps<\"button\"> & React.ComponentProps<\"button\">) {\n return useRender({\n defaultTagName: \"button\",\n props: mergeProps<\"button\">(\n {\n className: cn(\n \"absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 md:after:hidden [&>svg]:size-4 [&>svg]:shrink-0\",\n className\n ),\n },\n props\n ),\n render,\n state: {\n slot: \"sidebar-group-action\",\n sidebar: \"group-action\",\n },\n })\n}\n\nfunction SidebarGroupContent({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-group-content\"\n data-sidebar=\"group-content\"\n className={cn(\"w-full text-sm\", className)}\n {...props}\n />\n )\n}\n\nfunction SidebarMenu({ className, ...props }: React.ComponentProps<\"ul\">) {\n return (\n <ul\n data-slot=\"sidebar-menu\"\n data-sidebar=\"menu\"\n className={cn(\"flex w-full min-w-0 flex-col gap-1\", className)}\n {...props}\n />\n )\n}\n\nfunction SidebarMenuItem({ className, ...props }: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"sidebar-menu-item\"\n data-sidebar=\"menu-item\"\n className={cn(\"group/menu-item relative\", className)}\n {...props}\n />\n )\n}\n\nconst sidebarMenuButtonVariants = cva(\n \"peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate\",\n {\n variants: {\n variant: {\n default: \"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\",\n outline:\n \"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]\",\n },\n size: {\n default: \"h-8 text-sm\",\n sm: \"h-7 text-xs\",\n lg: \"h-12 text-sm group-data-[collapsible=icon]:p-0!\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction SidebarMenuButton({\n render,\n isActive = false,\n variant = \"default\",\n size = \"default\",\n tooltip,\n className,\n ...props\n}: useRender.ComponentProps<\"button\"> &\n React.ComponentProps<\"button\"> & {\n isActive?: boolean\n tooltip?: string | React.ComponentProps<typeof TooltipContent>\n } & VariantProps<typeof sidebarMenuButtonVariants>) {\n const { isMobile, state } = useSidebar()\n const comp = useRender({\n defaultTagName: \"button\",\n props: mergeProps<\"button\">(\n {\n className: cn(sidebarMenuButtonVariants({ variant, size }), className),\n },\n props\n ),\n render: !tooltip ? render : TooltipTrigger,\n state: {\n slot: \"sidebar-menu-button\",\n sidebar: \"menu-button\",\n size,\n active: isActive,\n },\n })\n\n if (!tooltip) {\n return comp\n }\n\n if (typeof tooltip === \"string\") {\n tooltip = {\n children: tooltip,\n }\n }\n\n return (\n <Tooltip>\n {comp}\n <TooltipContent\n side=\"right\"\n align=\"center\"\n hidden={state !== \"collapsed\" || isMobile}\n {...tooltip}\n />\n </Tooltip>\n )\n}\n\nfunction SidebarMenuAction({\n className,\n render,\n showOnHover = false,\n ...props\n}: useRender.ComponentProps<\"button\"> &\n React.ComponentProps<\"button\"> & {\n showOnHover?: boolean\n }) {\n return useRender({\n defaultTagName: \"button\",\n props: mergeProps<\"button\">(\n {\n className: cn(\n \"absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform group-data-[collapsible=icon]:hidden peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 after:absolute after:-inset-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 md:after:hidden [&>svg]:size-4 [&>svg]:shrink-0\",\n showOnHover &&\n \"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-active/menu-button:text-sidebar-accent-foreground data-open:opacity-100 md:opacity-0\",\n className\n ),\n },\n props\n ),\n render,\n state: {\n slot: \"sidebar-menu-action\",\n sidebar: \"menu-action\",\n },\n })\n}\n\nfunction SidebarMenuBadge({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-menu-badge\"\n data-sidebar=\"menu-badge\"\n className={cn(\n \"pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium text-sidebar-foreground tabular-nums select-none group-data-[collapsible=icon]:hidden peer-hover/menu-button:text-sidebar-accent-foreground peer-data-active/menu-button:text-sidebar-accent-foreground peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction SidebarMenuSkeleton({\n className,\n showIcon = false,\n ...props\n}: React.ComponentProps<\"div\"> & {\n showIcon?: boolean\n}) {\n // Random width between 50 to 90%.\n const [width] = React.useState(() => {\n return `${Math.floor(Math.random() * 40) + 50}%`\n })\n\n return (\n <div\n data-slot=\"sidebar-menu-skeleton\"\n data-sidebar=\"menu-skeleton\"\n className={cn(\"flex h-8 items-center gap-2 rounded-md px-2\", className)}\n {...props}\n >\n {showIcon && (\n <Skeleton\n className=\"size-4 rounded-md\"\n data-sidebar=\"menu-skeleton-icon\"\n />\n )}\n <Skeleton\n className=\"h-4 max-w-(--skeleton-width) flex-1\"\n data-sidebar=\"menu-skeleton-text\"\n style={\n {\n \"--skeleton-width\": width,\n } as any\n }\n />\n </div>\n )\n}\n\nfunction SidebarMenuSub({ className, ...props }: React.ComponentProps<\"ul\">) {\n return (\n <ul\n data-slot=\"sidebar-menu-sub\"\n data-sidebar=\"menu-sub\"\n className={cn(\n \"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5 group-data-[collapsible=icon]:hidden\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction SidebarMenuSubItem({\n className,\n ...props\n}: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"sidebar-menu-sub-item\"\n data-sidebar=\"menu-sub-item\"\n className={cn(\"group/menu-sub-item relative\", className)}\n {...props}\n />\n )\n}\n\nfunction SidebarMenuSubButton({\n render,\n size = \"md\",\n isActive = false,\n className,\n ...props\n}: useRender.ComponentProps<\"a\"> &\n React.ComponentProps<\"a\"> & {\n size?: \"sm\" | \"md\"\n isActive?: boolean\n }) {\n return useRender({\n defaultTagName: \"a\",\n props: mergeProps<\"a\">(\n {\n className: cn(\n \"flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground ring-sidebar-ring outline-hidden group-data-[collapsible=icon]:hidden hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground data-[size=md]:text-sm data-[size=sm]:text-xs [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground\",\n className\n ),\n },\n props\n ),\n render,\n state: {\n slot: \"sidebar-menu-sub-button\",\n sidebar: \"menu-sub-button\",\n size,\n active: isActive,\n },\n })\n}\n\nexport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInput,\n SidebarInset,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarProvider,\n SidebarRail,\n SidebarSeparator,\n SidebarTrigger,\n useSidebar,\n}\n"
91
+ },
92
+ {
93
+ "path": "registry/example-apps/default/rentals/components/ui/skeleton.tsx",
94
+ "type": "registry:ui",
95
+ "target": "components/example-apps/rentals/components/ui/skeleton.tsx",
96
+ "content": "import type { ComponentPropsWithoutRef } from \"react\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Skeleton({ className, ...props }: ComponentPropsWithoutRef<\"div\">) {\n return (\n <div\n data-slot=\"skeleton\"\n className={cn(\"animate-pulse rounded-md bg-muted\", className)}\n {...props}\n />\n )\n}\n\nexport { Skeleton }\n"
97
+ },
98
+ {
99
+ "path": "registry/example-apps/default/rentals/components/ui/slider.tsx",
100
+ "type": "registry:ui",
101
+ "target": "components/example-apps/rentals/components/ui/slider.tsx",
102
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as SliderPrimitive from \"@radix-ui/react-slider\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction Slider({\n className,\n defaultValue,\n value,\n min = 0,\n max = 100,\n ...props\n}: React.ComponentProps<typeof SliderPrimitive.Root>) {\n const _values = React.useMemo(\n () =>\n Array.isArray(value)\n ? value\n : Array.isArray(defaultValue)\n ? defaultValue\n : [min, max],\n [value, defaultValue, min, max]\n )\n\n return (\n <SliderPrimitive.Root\n data-slot=\"slider\"\n defaultValue={defaultValue}\n value={value}\n min={min}\n max={max}\n className={cn(\n \"relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col\",\n className\n )}\n {...props}\n >\n <SliderPrimitive.Track\n data-slot=\"slider-track\"\n className={cn(\n \"relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5\"\n )}\n >\n <SliderPrimitive.Range\n data-slot=\"slider-range\"\n className={cn(\n \"absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full\"\n )}\n />\n </SliderPrimitive.Track>\n {Array.from({ length: _values.length }, (_, index) => (\n <SliderPrimitive.Thumb\n data-slot=\"slider-thumb\"\n key={index}\n className=\"block size-4 shrink-0 rounded-full border border-primary bg-white shadow-sm ring-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50\"\n />\n ))}\n </SliderPrimitive.Root>\n )\n}\n\nexport { Slider }\n"
103
+ },
104
+ {
105
+ "path": "registry/example-apps/default/rentals/components/ui/tooltip.tsx",
106
+ "type": "registry:ui",
107
+ "target": "components/example-apps/rentals/components/ui/tooltip.tsx",
108
+ "content": "\"use client\"\n\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\"\n\nimport { cn } from \"../../lib/utils\"\n\nfunction TooltipProvider({\n delay = 0,\n ...props\n}: TooltipPrimitive.Provider.Props) {\n return (\n <TooltipPrimitive.Provider\n data-slot=\"tooltip-provider\"\n delay={delay}\n {...props}\n />\n )\n}\n\nfunction Tooltip({ ...props }: TooltipPrimitive.Root.Props) {\n return (\n <TooltipProvider>\n <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />\n </TooltipProvider>\n )\n}\n\nfunction TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />\n}\n\nfunction TooltipContent({\n className,\n side = \"top\",\n sideOffset = 4,\n align = \"center\",\n alignOffset = 0,\n children,\n ...props\n}: TooltipPrimitive.Popup.Props &\n Pick<\n TooltipPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\n <TooltipPrimitive.Popup\n data-slot=\"tooltip-content\"\n className={cn(\n \"data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit max-w-xs origin-(--transform-origin) rounded-md bg-foreground px-3 py-1.5 text-xs text-background\",\n className\n )}\n {...props}\n >\n {children}\n <TooltipPrimitive.Arrow className=\"z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5\" />\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n )\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }\n"
109
+ },
110
+ {
111
+ "path": "registry/example-apps/default/rentals/hooks/use-mobile.ts",
112
+ "type": "registry:hook",
113
+ "target": "components/example-apps/rentals/hooks/use-mobile.ts",
114
+ "content": "import * as React from \"react\"\n\nconst MOBILE_BREAKPOINT = 768\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)\n\n React.useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n }\n mql.addEventListener(\"change\", onChange)\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n return () => mql.removeEventListener(\"change\", onChange)\n }, [])\n\n return !!isMobile\n}\n"
115
+ },
116
+ {
117
+ "path": "registry/example-apps/default/rentals/index.tsx",
118
+ "type": "registry:file",
119
+ "target": "components/example-apps/rentals/index.tsx",
120
+ "content": "/**\n * Wrapper export for embedding the app in the docs app\n */\n\"use client\"\n\nimport { SidebarInset, SidebarProvider } from \"@/components/ui/sidebar\"\n\nimport { ListingsPanel } from \"./components/dashboard/listings-panel\"\nimport { MapControls } from \"./components/dashboard/map-controls\"\nimport { MapView } from \"./components/dashboard/map-view\"\nimport { RentalsSidebar } from \"./components/dashboard/sidebar\"\n\nexport default function RentalsWrapper() {\n return (\n <SidebarProvider>\n <RentalsSidebar />\n <SidebarInset className=\"overflow-hidden\">\n <div className=\"relative h-full w-full overflow-hidden\">\n <MapView />\n <ListingsPanel />\n <MapControls />\n </div>\n </SidebarInset>\n </SidebarProvider>\n )\n}\n"
121
+ },
122
+ {
123
+ "path": "registry/example-apps/default/rentals/lib/utils.ts",
124
+ "type": "registry:lib",
125
+ "target": "components/example-apps/rentals/lib/utils.ts",
126
+ "content": "import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n"
127
+ },
128
+ {
129
+ "path": "registry/example-apps/default/rentals/mock-data/listings.ts",
130
+ "type": "registry:lib",
131
+ "target": "components/example-apps/rentals/mock-data/listings.ts",
132
+ "content": "export type PropertyType =\n | \"apartment\"\n | \"house\"\n | \"villa\"\n | \"studio\"\n | \"loft\"\n | \"cottage\"\n\nexport type Listing = {\n id: string\n title: string\n description: string\n address: string\n city: string\n country: string\n coordinates: {\n lat: number\n lng: number\n }\n pricePerNight: number\n propertyType: PropertyType\n bedrooms: number\n beds: number\n bathrooms: number\n guests: number\n rating: number\n reviewCount: number\n images: string[]\n amenities: string[]\n host: {\n name: string\n avatar: string\n isSuperhost: boolean\n }\n isFavorite: boolean\n isNew: boolean\n instantBook: boolean\n}\n\nconst cameraImages = [\n \"https://images.unsplash.com/photo-1516035069371-29a1b244cc32?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1495707902641-75cac588d2e9?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1502982720700-bfff97f2ecac?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1452780212940-6f5c0d14d848?w=900&h=700&fit=crop\",\n]\n\nconst audioImages = [\n \"https://images.unsplash.com/photo-1511379938547-c1f69419868d?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1484704849700-f032a568e944?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1589903308904-1010c2294adc?w=900&h=700&fit=crop\",\n]\n\nconst cyclingImages = [\n \"https://images.unsplash.com/photo-1511994298241-608e28f14fde?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1532298229144-0ec0c57515c7?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1529422643029-d4585747aaf2?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1485965120184-e220f721d03e?w=900&h=700&fit=crop\",\n]\n\nconst campingImages = [\n \"https://images.unsplash.com/photo-1504851149312-7a075b496cc7?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1478131143081-80f7f84ca84d?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1470246973918-29a93221c455?w=900&h=700&fit=crop\",\n]\n\nconst droneImages = [\n \"https://images.unsplash.com/photo-1508614589041-895b88991e3e?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1521405924368-64c5b84bec60?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1524143986875-3b098d78b363?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1527977966376-1c8408f9f108?w=900&h=700&fit=crop\",\n]\n\nconst gamingImages = [\n \"https://images.unsplash.com/photo-1542751371-adc38448a05e?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1545239351-1141bd82e8a6?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1612287230202-1ff1d85d1bdf?w=900&h=700&fit=crop\",\n \"https://images.unsplash.com/photo-1598550476439-6847785fcea6?w=900&h=700&fit=crop\",\n]\n\nexport const listings: Listing[] = [\n {\n id: \"gear-1\",\n title: \"Sony FX3 Creator Cinema Kit\",\n description:\n \"Full-frame camera kit with cage, monitor, and dual batteries for short-form shoots.\",\n address: \"1141 W Colfax Ave\",\n city: \"Denver\",\n country: \"USA\",\n coordinates: { lat: 39.7392, lng: -104.9903 },\n pricePerNight: 185,\n propertyType: \"apartment\",\n bedrooms: 3,\n beds: 5,\n bathrooms: 2,\n guests: 6,\n rating: 4.9,\n reviewCount: 132,\n images: cameraImages,\n amenities: [\n \"Damage waiver\",\n \"Same-day pickup\",\n \"Tripod included\",\n \"ND filters\",\n ],\n host: {\n name: \"Mia Park\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=MiaPark\",\n isSuperhost: true,\n },\n isFavorite: true,\n isNew: false,\n instantBook: true,\n },\n {\n id: \"gear-2\",\n title: \"Canon R6 Mark II Event Bundle\",\n description:\n \"Low-light camera setup with two lenses and flash for events and portraits.\",\n address: \"219 SW Pine St\",\n city: \"Portland\",\n country: \"USA\",\n coordinates: { lat: 45.5152, lng: -122.6784 },\n pricePerNight: 165,\n propertyType: \"apartment\",\n bedrooms: 2,\n beds: 4,\n bathrooms: 2,\n guests: 4,\n rating: 4.8,\n reviewCount: 88,\n images: cameraImages,\n amenities: [\"Insurance included\", \"Lens cleaning kit\", \"Express return\"],\n host: {\n name: \"Noah Kim\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=NoahKim\",\n isSuperhost: true,\n },\n isFavorite: false,\n isNew: true,\n instantBook: true,\n },\n {\n id: \"gear-3\",\n title: \"Rode Podcast Studio Rack\",\n description:\n \"Two-mic recording station with interface, acoustic panels, and backup recorder.\",\n address: \"802 E 6th St\",\n city: \"Austin\",\n country: \"USA\",\n coordinates: { lat: 30.2672, lng: -97.7431 },\n pricePerNight: 95,\n propertyType: \"house\",\n bedrooms: 2,\n beds: 4,\n bathrooms: 3,\n guests: 5,\n rating: 4.7,\n reviewCount: 61,\n images: audioImages,\n amenities: [\"On-site sound check\", \"USB-C cables\", \"Pop filters\"],\n host: {\n name: \"Camden Lee\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=CamdenLee\",\n isSuperhost: false,\n },\n isFavorite: true,\n isNew: false,\n instantBook: true,\n },\n {\n id: \"gear-4\",\n title: \"Pioneer DJ Booth Starter Set\",\n description:\n \"Controller, monitors, and lighting for club practice sessions and pop-up sets.\",\n address: \"1430 2nd Ave\",\n city: \"Seattle\",\n country: \"USA\",\n coordinates: { lat: 47.6062, lng: -122.3321 },\n pricePerNight: 140,\n propertyType: \"house\",\n bedrooms: 3,\n beds: 5,\n bathrooms: 4,\n guests: 8,\n rating: 4.9,\n reviewCount: 109,\n images: audioImages,\n amenities: [\"Speaker stands\", \"MIDI cables\", \"Late-night pickup\"],\n host: {\n name: \"Zara Patel\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=ZaraPatel\",\n isSuperhost: true,\n },\n isFavorite: false,\n isNew: true,\n instantBook: false,\n },\n {\n id: \"gear-5\",\n title: \"Trek Domane Carbon Road Package\",\n description:\n \"Race-ready road bike with helmet, meter pedals, and roadside repair kit.\",\n address: \"1745 28th St\",\n city: \"Boulder\",\n country: \"USA\",\n coordinates: { lat: 40.015, lng: -105.2705 },\n pricePerNight: 125,\n propertyType: \"villa\",\n bedrooms: 2,\n beds: 3,\n bathrooms: 2,\n guests: 2,\n rating: 4.8,\n reviewCount: 73,\n images: cyclingImages,\n amenities: [\"Bike fit included\", \"Tube pack\", \"GPS mount\"],\n host: {\n name: \"Ethan Ruiz\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=EthanRuiz\",\n isSuperhost: true,\n },\n isFavorite: true,\n isNew: false,\n instantBook: true,\n },\n {\n id: \"gear-6\",\n title: \"Specialized Trail e-MTB Set\",\n description:\n \"Electric mountain bike package with charger, pads, and hydration vest.\",\n address: \"5025 N Harbor Dr\",\n city: \"San Diego\",\n country: \"USA\",\n coordinates: { lat: 32.7157, lng: -117.1611 },\n pricePerNight: 160,\n propertyType: \"villa\",\n bedrooms: 2,\n beds: 3,\n bathrooms: 3,\n guests: 2,\n rating: 4.9,\n reviewCount: 96,\n images: cyclingImages,\n amenities: [\"Helmet included\", \"Trail map pack\", \"Battery swap option\"],\n host: {\n name: \"Ava Brooks\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=AvaBrooks\",\n isSuperhost: true,\n },\n isFavorite: false,\n isNew: true,\n instantBook: true,\n },\n {\n id: \"gear-7\",\n title: \"4-Person Basecamp Weekend Kit\",\n description:\n \"Tent, stove, lanterns, and insulated sleeping system for quick camp escapes.\",\n address: \"8812 N 3rd St\",\n city: \"Phoenix\",\n country: \"USA\",\n coordinates: { lat: 33.4484, lng: -112.074 },\n pricePerNight: 84,\n propertyType: \"studio\",\n bedrooms: 4,\n beds: 8,\n bathrooms: 4,\n guests: 6,\n rating: 4.6,\n reviewCount: 57,\n images: campingImages,\n amenities: [\"Cooler included\", \"Fuel canister\", \"Camp chairs\"],\n host: {\n name: \"Leo Clark\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=LeoClark\",\n isSuperhost: false,\n },\n isFavorite: false,\n isNew: false,\n instantBook: true,\n },\n {\n id: \"gear-8\",\n title: \"Winter Touring Shelter Bundle\",\n description:\n \"Cold-weather tent system, avalanche beacons, and insulated cook station.\",\n address: \"311 W 200 S\",\n city: \"Salt Lake City\",\n country: \"USA\",\n coordinates: { lat: 40.7608, lng: -111.891 },\n pricePerNight: 112,\n propertyType: \"studio\",\n bedrooms: 3,\n beds: 7,\n bathrooms: 5,\n guests: 5,\n rating: 4.7,\n reviewCount: 48,\n images: campingImages,\n amenities: [\"Emergency beacon\", \"Snow stakes\", \"Warm liner set\"],\n host: {\n name: \"Iris Shaw\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=IrisShaw\",\n isSuperhost: true,\n },\n isFavorite: true,\n isNew: false,\n instantBook: false,\n },\n {\n id: \"gear-9\",\n title: \"DJI Mavic 3 Fly More Pack\",\n description:\n \"Long-range drone bundle with ND set, charging dock, and dual operator screens.\",\n address: \"810 Broadway\",\n city: \"Nashville\",\n country: \"USA\",\n coordinates: { lat: 36.1627, lng: -86.7816 },\n pricePerNight: 210,\n propertyType: \"loft\",\n bedrooms: 2,\n beds: 4,\n bathrooms: 3,\n guests: 3,\n rating: 4.9,\n reviewCount: 143,\n images: droneImages,\n amenities: [\"Flight insurance\", \"Landing pad\", \"48-hour support\"],\n host: {\n name: \"Remy Foster\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=RemyFoster\",\n isSuperhost: true,\n },\n isFavorite: true,\n isNew: true,\n instantBook: true,\n },\n {\n id: \"gear-10\",\n title: \"FPV Racing Drone Starter Crate\",\n description:\n \"Complete FPV setup with goggles, spare props, and training simulator access.\",\n address: \"155 NE 40th St\",\n city: \"Miami\",\n country: \"USA\",\n coordinates: { lat: 25.7617, lng: -80.1918 },\n pricePerNight: 132,\n propertyType: \"loft\",\n bedrooms: 3,\n beds: 5,\n bathrooms: 4,\n guests: 4,\n rating: 4.7,\n reviewCount: 77,\n images: droneImages,\n amenities: [\"Extra propellers\", \"Practice gates\", \"Battery bag\"],\n host: {\n name: \"Skye Morgan\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=SkyeMorgan\",\n isSuperhost: false,\n },\n isFavorite: false,\n isNew: false,\n instantBook: true,\n },\n {\n id: \"gear-11\",\n title: \"Pro Streaming Battle Station\",\n description:\n \"Dual-PC gaming setup with capture card, scene lights, and creator mic arm.\",\n address: \"227 W Hubbard St\",\n city: \"Chicago\",\n country: \"USA\",\n coordinates: { lat: 41.8781, lng: -87.6298 },\n pricePerNight: 118,\n propertyType: \"cottage\",\n bedrooms: 2,\n beds: 4,\n bathrooms: 4,\n guests: 3,\n rating: 4.8,\n reviewCount: 84,\n images: gamingImages,\n amenities: [\"Scene presets\", \"Cable management\", \"Overlays included\"],\n host: {\n name: \"Jules Quinn\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=JulesQuinn\",\n isSuperhost: true,\n },\n isFavorite: false,\n isNew: true,\n instantBook: true,\n },\n {\n id: \"gear-12\",\n title: \"VR Event Pop-up Arena Kit\",\n description:\n \"Portable VR package for activations with signage, chargers, and queue display.\",\n address: \"443 W 14th St\",\n city: \"New York\",\n country: \"USA\",\n coordinates: { lat: 40.7128, lng: -74.006 },\n pricePerNight: 225,\n propertyType: \"cottage\",\n bedrooms: 4,\n beds: 8,\n bathrooms: 5,\n guests: 10,\n rating: 4.9,\n reviewCount: 101,\n images: gamingImages,\n amenities: [\"On-site setup\", \"Safety mats\", \"Fast replacement\"],\n host: {\n name: \"Theo Reed\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=TheoReed\",\n isSuperhost: true,\n },\n isFavorite: true,\n isNew: false,\n instantBook: false,\n },\n {\n id: \"gear-13\",\n title: \"Portable Film Lighting Grid\",\n description:\n \"RGB panel package with softboxes and remote dimmer for interviews and product shots.\",\n address: \"780 N Highland Ave\",\n city: \"Los Angeles\",\n country: \"USA\",\n coordinates: { lat: 34.0522, lng: -118.2437 },\n pricePerNight: 138,\n propertyType: \"house\",\n bedrooms: 3,\n beds: 5,\n bathrooms: 4,\n guests: 5,\n rating: 4.8,\n reviewCount: 92,\n images: cameraImages,\n amenities: [\"Diffusion kit\", \"Sandbags\", \"Color cards\"],\n host: {\n name: \"Rae Dalton\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=RaeDalton\",\n isSuperhost: false,\n },\n isFavorite: false,\n isNew: false,\n instantBook: true,\n },\n {\n id: \"gear-14\",\n title: \"Wedding Photo Duo Package\",\n description:\n \"Two-camera setup with portrait primes, wireless flash triggers, and backup drive.\",\n address: \"940 Peachtree St NE\",\n city: \"Atlanta\",\n country: \"USA\",\n coordinates: { lat: 33.749, lng: -84.388 },\n pricePerNight: 196,\n propertyType: \"apartment\",\n bedrooms: 3,\n beds: 6,\n bathrooms: 3,\n guests: 6,\n rating: 4.9,\n reviewCount: 128,\n images: cameraImages,\n amenities: [\"Lens insurance\", \"Rain cover\", \"Color checker\"],\n host: {\n name: \"Kira Holt\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=KiraHolt\",\n isSuperhost: true,\n },\n isFavorite: true,\n isNew: false,\n instantBook: true,\n },\n {\n id: \"gear-15\",\n title: \"Field Audio Interview Pack\",\n description:\n \"Compact audio kit with lavs, boom mic, and timecode recorder for documentary crews.\",\n address: \"1810 Rue Sainte-Catherine O\",\n city: \"Montreal\",\n country: \"Canada\",\n coordinates: { lat: 45.5017, lng: -73.5673 },\n pricePerNight: 104,\n propertyType: \"house\",\n bedrooms: 2,\n beds: 4,\n bathrooms: 3,\n guests: 4,\n rating: 4.7,\n reviewCount: 59,\n images: audioImages,\n amenities: [\"Rechargeable battery bank\", \"Wind protection\", \"Hard case\"],\n host: {\n name: \"Nina Vale\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=NinaVale\",\n isSuperhost: false,\n },\n isFavorite: false,\n isNew: true,\n instantBook: true,\n },\n {\n id: \"gear-16\",\n title: \"Urban Courier Bike Fleet Kit\",\n description:\n \"Three-bike city set with helmets, pannier bags, and tracking mounts.\",\n address: \"390 W Cordova St\",\n city: \"Vancouver\",\n country: \"Canada\",\n coordinates: { lat: 49.2827, lng: -123.1207 },\n pricePerNight: 148,\n propertyType: \"villa\",\n bedrooms: 3,\n beds: 6,\n bathrooms: 4,\n guests: 6,\n rating: 4.8,\n reviewCount: 68,\n images: cyclingImages,\n amenities: [\"Helmet cleaning\", \"Bike locks\", \"Frame lights\"],\n host: {\n name: \"Owen Cross\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=OwenCross\",\n isSuperhost: true,\n },\n isFavorite: false,\n isNew: false,\n instantBook: false,\n },\n {\n id: \"gear-17\",\n title: \"Creator Office Workstation Set\",\n description:\n \"Desk setup with monitor arm, key light, and webcam for remote brand shoots.\",\n address: \"96 Shoreditch High St\",\n city: \"London\",\n country: \"UK\",\n coordinates: { lat: 51.5074, lng: -0.1278 },\n pricePerNight: 89,\n propertyType: \"cottage\",\n bedrooms: 2,\n beds: 3,\n bathrooms: 2,\n guests: 2,\n rating: 4.6,\n reviewCount: 53,\n images: gamingImages,\n amenities: [\"Cable kit\", \"Desk mount\", \"Audio interface\"],\n host: {\n name: \"Sage Bennett\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=SageBennett\",\n isSuperhost: false,\n },\n isFavorite: true,\n isNew: false,\n instantBook: true,\n },\n {\n id: \"gear-18\",\n title: \"Street Documentary Drone Rig\",\n description:\n \"Compact travel drone setup with fast charger and compliance checklist.\",\n address: \"27 Linienstrasse\",\n city: \"Berlin\",\n country: \"Germany\",\n coordinates: { lat: 52.52, lng: 13.405 },\n pricePerNight: 172,\n propertyType: \"loft\",\n bedrooms: 2,\n beds: 4,\n bathrooms: 3,\n guests: 3,\n rating: 4.9,\n reviewCount: 117,\n images: droneImages,\n amenities: [\"Flight log template\", \"Insurance PDF\", \"Travel case\"],\n host: {\n name: \"Arlo Finch\",\n avatar: \"https://api.dicebear.com/9.x/glass/svg?seed=ArloFinch\",\n isSuperhost: true,\n },\n isFavorite: true,\n isNew: true,\n instantBook: true,\n },\n]\n\nexport const propertyTypeLabels: Record<PropertyType, string> = {\n apartment: \"Cameras\",\n house: \"Audio\",\n villa: \"Cycling\",\n studio: \"Camping\",\n loft: \"Drones\",\n cottage: \"Gaming\",\n}\n"
133
+ },
134
+ {
135
+ "path": "registry/example-apps/default/rentals/store/rentals-store.ts",
136
+ "type": "registry:lib",
137
+ "target": "components/example-apps/rentals/store/rentals-store.ts",
138
+ "content": "import { create } from \"zustand\"\n\nimport {\n listings as initialListings,\n type Listing,\n type PropertyType,\n} from \"../mock-data/listings\"\n\ntype SortBy =\n | \"price-low\"\n | \"price-high\"\n | \"rating\"\n | \"newest\"\n | \"reviews\"\n | \"nearest\"\n\ntype MapStyle = \"default\" | \"streets\" | \"outdoors\" | \"satellite\"\n\ninterface RentalsState {\n listings: Listing[]\n searchQuery: string\n selectedPropertyTypes: PropertyType[]\n priceRange: [number, number]\n bedrooms: number | null\n bathrooms: number | null\n beds: number | null\n guests: number | null\n amenities: string[]\n sortBy: SortBy\n selectedListingId: string | null\n mapCenter: { lat: number; lng: number }\n mapZoom: number\n mapStyle: MapStyle\n userLocation: { lat: number; lng: number } | null\n setSearchQuery: (query: string) => void\n togglePropertyType: (type: PropertyType) => void\n setPriceRange: (range: [number, number]) => void\n setBedrooms: (count: number | null) => void\n setBathrooms: (count: number | null) => void\n setBeds: (count: number | null) => void\n setGuests: (count: number | null) => void\n toggleAmenity: (amenity: string) => void\n setSortBy: (sort: SortBy) => void\n toggleFavorite: (listingId: string) => void\n selectListing: (listingId: string | null) => void\n setMapCenter: (center: { lat: number; lng: number }) => void\n setMapZoom: (zoom: number) => void\n setMapStyle: (style: MapStyle) => void\n setUserLocation: (location: { lat: number; lng: number } | null) => void\n getFilteredListings: () => Listing[]\n getFavoriteListings: () => Listing[]\n resetFilters: () => void\n}\n\nconst defaultPriceRange: [number, number] = [0, 500]\n\nfunction calculateDistance(\n lat1: number,\n lng1: number,\n lat2: number,\n lng2: number\n): number {\n const R = 6371\n const dLat = ((lat2 - lat1) * Math.PI) / 180\n const dLng = ((lng2 - lng1) * Math.PI) / 180\n const a =\n Math.sin(dLat / 2) * Math.sin(dLat / 2) +\n Math.cos((lat1 * Math.PI) / 180) *\n Math.cos((lat2 * Math.PI) / 180) *\n Math.sin(dLng / 2) *\n Math.sin(dLng / 2)\n const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))\n return R * c\n}\n\nexport const useRentalsStore = create<RentalsState>((set, get) => ({\n listings: initialListings,\n searchQuery: \"\",\n selectedPropertyTypes: [],\n priceRange: defaultPriceRange,\n bedrooms: null,\n bathrooms: null,\n beds: null,\n guests: null,\n amenities: [],\n sortBy: \"price-low\",\n selectedListingId: null,\n mapCenter: { lat: 39.7392, lng: -104.9903 },\n mapZoom: 4,\n mapStyle: \"default\",\n userLocation: null,\n\n setSearchQuery: (query) => set({ searchQuery: query }),\n\n togglePropertyType: (type) =>\n set((state) => ({\n selectedPropertyTypes: state.selectedPropertyTypes.includes(type)\n ? state.selectedPropertyTypes.filter((t) => t !== type)\n : [...state.selectedPropertyTypes, type],\n })),\n\n setPriceRange: (range) => set({ priceRange: range }),\n\n setBedrooms: (count) => set({ bedrooms: count }),\n\n setBathrooms: (count) => set({ bathrooms: count }),\n\n setBeds: (count) => set({ beds: count }),\n\n setGuests: (count) => set({ guests: count }),\n\n toggleAmenity: (amenity) =>\n set((state) => ({\n amenities: state.amenities.includes(amenity)\n ? state.amenities.filter((a) => a !== amenity)\n : [...state.amenities, amenity],\n })),\n\n setSortBy: (sort) => set({ sortBy: sort }),\n\n toggleFavorite: (listingId) =>\n set((state) => ({\n listings: state.listings.map((listing) =>\n listing.id === listingId\n ? { ...listing, isFavorite: !listing.isFavorite }\n : listing\n ),\n })),\n\n selectListing: (listingId) => set({ selectedListingId: listingId }),\n\n setMapCenter: (center) => set({ mapCenter: center }),\n\n setMapZoom: (zoom) => set({ mapZoom: zoom }),\n\n setMapStyle: (style) => set({ mapStyle: style }),\n\n setUserLocation: (location) => set({ userLocation: location }),\n\n resetFilters: () =>\n set({\n searchQuery: \"\",\n selectedPropertyTypes: [],\n priceRange: defaultPriceRange,\n bedrooms: null,\n bathrooms: null,\n beds: null,\n guests: null,\n amenities: [],\n sortBy: \"price-low\",\n }),\n\n getFilteredListings: () => {\n const state = get()\n let filtered = [...state.listings]\n\n if (state.searchQuery) {\n const query = state.searchQuery.toLowerCase()\n filtered = filtered.filter(\n (listing) =>\n listing.title.toLowerCase().includes(query) ||\n listing.description.toLowerCase().includes(query) ||\n listing.city.toLowerCase().includes(query) ||\n listing.address.toLowerCase().includes(query)\n )\n }\n\n if (state.selectedPropertyTypes.length > 0) {\n filtered = filtered.filter((listing) =>\n state.selectedPropertyTypes.includes(listing.propertyType)\n )\n }\n\n filtered = filtered.filter(\n (listing) =>\n listing.pricePerNight >= state.priceRange[0] &&\n listing.pricePerNight <= state.priceRange[1]\n )\n\n if (state.bedrooms !== null) {\n filtered = filtered.filter(\n (listing) => listing.bedrooms >= state.bedrooms!\n )\n }\n\n if (state.bathrooms !== null) {\n filtered = filtered.filter(\n (listing) => listing.bathrooms >= state.bathrooms!\n )\n }\n\n if (state.beds !== null) {\n filtered = filtered.filter((listing) => listing.beds >= state.beds!)\n }\n\n if (state.guests !== null) {\n filtered = filtered.filter((listing) => listing.guests >= state.guests!)\n }\n\n if (state.amenities.length > 0) {\n filtered = filtered.filter((listing) =>\n state.amenities.every((amenity) => listing.amenities.includes(amenity))\n )\n }\n\n switch (state.sortBy) {\n case \"price-low\":\n filtered.sort((a, b) => a.pricePerNight - b.pricePerNight)\n break\n case \"price-high\":\n filtered.sort((a, b) => b.pricePerNight - a.pricePerNight)\n break\n case \"rating\":\n filtered.sort((a, b) => b.rating - a.rating)\n break\n case \"newest\":\n filtered.sort((a, b) => (b.isNew ? 1 : 0) - (a.isNew ? 1 : 0))\n break\n case \"reviews\":\n filtered.sort((a, b) => b.reviewCount - a.reviewCount)\n break\n case \"nearest\":\n if (state.userLocation) {\n filtered.sort((a, b) => {\n const distA = calculateDistance(\n state.userLocation!.lat,\n state.userLocation!.lng,\n a.coordinates.lat,\n a.coordinates.lng\n )\n const distB = calculateDistance(\n state.userLocation!.lat,\n state.userLocation!.lng,\n b.coordinates.lat,\n b.coordinates.lng\n )\n return distA - distB\n })\n }\n break\n }\n\n if (state.selectedListingId) {\n const selectedIndex = filtered.findIndex(\n (listing) => listing.id === state.selectedListingId\n )\n if (selectedIndex > 0) {\n const selected = filtered.splice(selectedIndex, 1)[0]\n filtered.unshift(selected)\n }\n }\n\n return filtered\n },\n\n getFavoriteListings: () => {\n const state = get()\n let favorites = state.listings.filter((listing) => listing.isFavorite)\n\n if (state.selectedListingId) {\n const selectedIndex = favorites.findIndex(\n (listing) => listing.id === state.selectedListingId\n )\n if (selectedIndex > 0) {\n const selected = favorites.splice(selectedIndex, 1)[0]\n favorites.unshift(selected)\n }\n }\n\n return favorites\n },\n}))\n"
139
+ }
140
+ ],
141
+ "categories": [
142
+ "example-app",
143
+ "e-commerce",
144
+ "gear",
145
+ "marketplace",
146
+ "maps"
147
+ ],
148
+ "dependencies": [
149
+ "@base-ui/react",
150
+ "@radix-ui/react-slider",
151
+ "@radix-ui/react-slot",
152
+ "class-variance-authority",
153
+ "clsx",
154
+ "embla-carousel-react",
155
+ "lucide-react",
156
+ "maplibre-gl",
157
+ "next-themes",
158
+ "tailwind-merge",
159
+ "usehooks-ts",
160
+ "zustand"
161
+ ],
162
+ "registryDependencies": [
163
+ "https://www.loveui.dev/r/badge.json",
164
+ "https://www.loveui.dev/r/button.json",
165
+ "https://www.loveui.dev/r/input.json",
166
+ "https://www.loveui.dev/r/menu.json",
167
+ "https://www.loveui.dev/r/separator.json",
168
+ "https://www.loveui.dev/r/slider.json",
169
+ "https://www.loveui.dev/r/tooltip.json"
170
+ ],
171
+ "meta": {
172
+ "source": "example-app",
173
+ "appName": "rentals",
174
+ "routes": [
175
+ {
176
+ "path": "/",
177
+ "title": "All Gear",
178
+ "description": "All gear listings map view"
179
+ },
180
+ {
181
+ "path": "/favorites",
182
+ "title": "Favorites",
183
+ "description": "Saved gear listings"
184
+ }
185
+ ]
186
+ }
187
+ }