canvas-ui-sdk 0.3.23 → 4.0.0

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 (177) hide show
  1. package/README.md +25 -5
  2. package/dist/charts.js +11 -6
  3. package/dist/charts.js.map +1 -1
  4. package/dist/index.d.ts +1233 -153
  5. package/dist/index.js +3562 -447
  6. package/dist/index.js.map +1 -1
  7. package/mcp/dist/index.js +1195 -149
  8. package/package.json +1 -1
  9. package/prompts/.cursorrules +96 -0
  10. package/prompts/.windsurfrules +96 -0
  11. package/prompts/CLAUDE.md +22 -0
  12. package/prompts/copilot-instructions.md +96 -0
  13. package/registry/blocks/activity-feed.json +12 -1
  14. package/registry/blocks/blog-cards.json +10 -2
  15. package/registry/blocks/bottom-action-bar.json +27 -0
  16. package/registry/blocks/bottom-input-chat-widget.json +9 -1
  17. package/registry/blocks/category-grid.json +10 -2
  18. package/registry/blocks/centered-hero.json +9 -1
  19. package/registry/blocks/chat-message.json +8 -1
  20. package/registry/blocks/circular-progress-bar-list.json +11 -1
  21. package/registry/blocks/confirmation-popup.json +10 -1
  22. package/registry/blocks/contact-form-popup.json +10 -1
  23. package/registry/blocks/content-dropzone.json +8 -0
  24. package/registry/blocks/content-with-image.json +9 -1
  25. package/registry/blocks/core-values-grid.json +10 -2
  26. package/registry/blocks/credit-card-display.json +9 -1
  27. package/registry/blocks/cta-banner.json +10 -2
  28. package/registry/blocks/destination-cards.json +10 -1
  29. package/registry/blocks/detail-drawer.json +10 -1
  30. package/registry/blocks/details-popup.json +10 -1
  31. package/registry/blocks/editable-list.json +29 -0
  32. package/registry/blocks/empty-state.json +10 -2
  33. package/registry/blocks/faq-accordion.json +9 -1
  34. package/registry/blocks/faqs-table.json +10 -1
  35. package/registry/blocks/feature-with-image.json +9 -1
  36. package/registry/blocks/featured-news-cards.json +10 -2
  37. package/registry/blocks/featured-places.json +10 -2
  38. package/registry/blocks/features-comparison.json +9 -1
  39. package/registry/blocks/feedback-popup.json +9 -1
  40. package/registry/blocks/filter-popover.json +8 -1
  41. package/registry/blocks/fixed-column-data-table.json +11 -1
  42. package/registry/blocks/flair-banner.json +9 -1
  43. package/registry/blocks/footer-navbar.json +9 -1
  44. package/registry/blocks/form-group.json +14 -3
  45. package/registry/blocks/form-popup.json +31 -0
  46. package/registry/blocks/gallery-section.json +10 -2
  47. package/registry/blocks/gradient-banner.json +10 -2
  48. package/registry/blocks/graph-metric-tiles.json +1 -1
  49. package/registry/blocks/grid-tiles-list.json +10 -1
  50. package/registry/blocks/hero-dark-centered.json +9 -1
  51. package/registry/blocks/hero-dark-with-image.json +9 -1
  52. package/registry/blocks/hero-fullwidth-image.json +9 -1
  53. package/registry/blocks/hero-section.json +9 -1
  54. package/registry/blocks/how-it-works.json +9 -1
  55. package/registry/blocks/image-feed-with-nested-comments.json +10 -1
  56. package/registry/blocks/image-popup.json +10 -1
  57. package/registry/blocks/invoice-popup.json +10 -1
  58. package/registry/blocks/large-image-labels-list.json +10 -1
  59. package/registry/blocks/list-popup.json +28 -0
  60. package/registry/blocks/loader.json +9 -1
  61. package/registry/blocks/login-branding-panel.json +10 -2
  62. package/registry/blocks/menu-section.json +9 -1
  63. package/registry/blocks/menufocus-template.json +9 -1
  64. package/registry/blocks/messenger-sidebar.json +11 -2
  65. package/registry/blocks/metrics-section.json +10 -2
  66. package/registry/blocks/mobile-bottom-nav.json +10 -2
  67. package/registry/blocks/monthly-calendar-widget.json +9 -1
  68. package/registry/blocks/multistep-form-popup.json +34 -0
  69. package/registry/blocks/nested-comments-table.json +9 -1
  70. package/registry/blocks/nested-data-table.json +10 -1
  71. package/registry/blocks/nps-survey-popup.json +27 -0
  72. package/registry/blocks/office-locations.json +10 -2
  73. package/registry/blocks/order-summary-sidebar.json +27 -0
  74. package/registry/blocks/page-header-section.json +9 -1
  75. package/registry/blocks/pagination.json +8 -1
  76. package/registry/blocks/participant-list.json +9 -1
  77. package/registry/blocks/persona-card.json +10 -1
  78. package/registry/blocks/personalize-feed-popup.json +27 -0
  79. package/registry/blocks/pill-tabs.json +9 -1
  80. package/registry/blocks/place-detail-panel.json +11 -1
  81. package/registry/blocks/pricing-cards.json +10 -2
  82. package/registry/blocks/pricing-cta.json +9 -1
  83. package/registry/blocks/pricing-plans-popup.json +10 -1
  84. package/registry/blocks/profile-card.json +12 -2
  85. package/registry/blocks/profile-grid-tiles-list.json +10 -1
  86. package/registry/blocks/profile-image-uploader.json +9 -1
  87. package/registry/blocks/profile-info-cards.json +10 -1
  88. package/registry/blocks/progress-bar.json +8 -1
  89. package/registry/blocks/prompt-template.json +1 -1
  90. package/registry/blocks/purchase-confirmation-popup.json +10 -1
  91. package/registry/blocks/reservation-card.json +26 -0
  92. package/registry/blocks/reviews-grid.json +10 -2
  93. package/registry/blocks/reviews-table.json +10 -1
  94. package/registry/blocks/screen-prompt-template.json +1 -1
  95. package/registry/blocks/search-bar.json +9 -2
  96. package/registry/blocks/search-sidebar.json +9 -2
  97. package/registry/blocks/settings-list-row.json +9 -1
  98. package/registry/blocks/share-project-popup.json +36 -0
  99. package/registry/blocks/sidebar-cards.json +10 -2
  100. package/registry/blocks/sidebar-profile-card.json +10 -2
  101. package/registry/blocks/slideshow-grid-tiles.json +10 -2
  102. package/registry/blocks/slideshow-popup.json +10 -1
  103. package/registry/blocks/small-edit-popup.json +29 -0
  104. package/registry/blocks/social-feed.json +10 -1
  105. package/registry/blocks/social-proof.json +9 -1
  106. package/registry/blocks/standard-data-table.json +13 -1
  107. package/registry/blocks/standard-list-with-image.json +10 -1
  108. package/registry/blocks/step-tracker.json +9 -1
  109. package/registry/blocks/store-location-map.json +9 -1
  110. package/registry/blocks/team-cards-grid.json +9 -1
  111. package/registry/blocks/team-circular-grid.json +9 -1
  112. package/registry/blocks/terms-of-service-popup.json +10 -1
  113. package/registry/blocks/testimonial-carousel.json +10 -2
  114. package/registry/blocks/tile-image-gallery.json +26 -0
  115. package/registry/blocks/title-group.json +10 -1
  116. package/registry/blocks/upvoting-posts-table.json +10 -1
  117. package/registry/blocks/vertical-how-it-works.json +9 -1
  118. package/registry/blocks/vertical-step-tracker.json +9 -1
  119. package/registry/blocks/video-chat-controls.json +9 -1
  120. package/registry/blocks/video-content-section.json +9 -1
  121. package/registry/blocks/video-playlist.json +9 -1
  122. package/registry/blocks/video-popup.json +9 -1
  123. package/registry/blocks/view-profile-popup.json +10 -1
  124. package/registry/blocks/webcam-preview.json +9 -1
  125. package/registry/hooks/use-css-variable-sync.json +10 -1
  126. package/registry/hooks/use-mobile.json +9 -1
  127. package/registry/index.json +1526 -147
  128. package/registry/layout/account-settings-shell.json +10 -1
  129. package/registry/layout/dashboard-shell.json +12 -1
  130. package/registry/layout/double-sidebar-shell.json +11 -2
  131. package/registry/layout/double-sidebar.json +9 -1
  132. package/registry/layout/header.json +10 -1
  133. package/registry/layout/icon-sidebar-shell.json +9 -1
  134. package/registry/layout/icon-sidebar.json +9 -1
  135. package/registry/layout/mobile-menu-shell.json +10 -1
  136. package/registry/layout/multistep-progressbar-shell.json +9 -1
  137. package/registry/layout/multistep-shell.json +11 -1
  138. package/registry/layout/multistep-sidebar-shell.json +10 -2
  139. package/registry/layout/project-context-shell.json +1 -1
  140. package/registry/layout/search-bar-shell.json +8 -1
  141. package/registry/layout/sidebar-nav.json +7 -1
  142. package/registry/layout/sidebar.json +9 -2
  143. package/registry/layout/standard-page-shell.json +10 -1
  144. package/registry/layout/vertical-multistep-shell.json +10 -1
  145. package/registry/ui/avatar.json +9 -1
  146. package/registry/ui/button.json +9 -1
  147. package/registry/ui/calendar.json +9 -1
  148. package/registry/ui/checkbox.json +8 -1
  149. package/registry/ui/date-input.json +9 -1
  150. package/registry/ui/dialog.json +8 -1
  151. package/registry/ui/dropdown-menu.json +8 -1
  152. package/registry/ui/file-uploader.json +9 -1
  153. package/registry/ui/image-uploader.json +9 -1
  154. package/registry/ui/input.json +8 -1
  155. package/registry/ui/label.json +8 -1
  156. package/registry/ui/line-tabs.json +9 -1
  157. package/registry/ui/multiselect-checkbox-field.json +9 -1
  158. package/registry/ui/multiselect-tags.json +9 -1
  159. package/registry/ui/popover.json +8 -1
  160. package/registry/ui/radio-group.json +9 -1
  161. package/registry/ui/range-input.json +8 -1
  162. package/registry/ui/scroll-area.json +8 -1
  163. package/registry/ui/searchbox.json +9 -1
  164. package/registry/ui/select.json +9 -1
  165. package/registry/ui/selectable-pills.json +11 -1
  166. package/registry/ui/separator.json +8 -1
  167. package/registry/ui/sheet.json +9 -1
  168. package/registry/ui/sidebar.json +8 -1
  169. package/registry/ui/skeleton.json +8 -1
  170. package/registry/ui/slider.json +10 -2
  171. package/registry/ui/switch.json +9 -1
  172. package/registry/ui/tabs.json +8 -1
  173. package/registry/ui/text-input.json +8 -1
  174. package/registry/ui/textarea.json +9 -1
  175. package/registry/ui/tooltip.json +8 -1
  176. package/registry/ui/typography.json +9 -1
  177. package/styles/tokens.reference.css +21 -0
@@ -1,12 +1,20 @@
1
1
  {
2
2
  "name": "core-values-grid",
3
3
  "type": "registry:block",
4
- "description": "Grid of value cards with icons and descriptions.",
4
+ "description": "3-column grid of value cards, each with an icon in a square container, title, and description text. Centered header with subtitle, title, and description. Light and dark variants. Use for core values, company principles, service benefits, or feature grids.",
5
+ "keywords": [
6
+ "values",
7
+ "principles",
8
+ "benefits",
9
+ "features",
10
+ "grid"
11
+ ],
12
+ "visualWeight": "medium",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/marketing/core-values-grid.tsx",
8
16
  "type": "registry:block",
9
- "content": "\"use client\";\n\nimport {\n Rocket,\n UserFocus,\n UsersFour,\n Eye,\n Books,\n Lightning,\n} from \"@phosphor-icons/react\";\nimport { ReactNode } from \"react\";\nimport { Typography } from \"../../ui/typography\";\n\ninterface Value {\n icon: ReactNode;\n title: string;\n description: string;\n}\n\ninterface CoreValuesGridProps {\n variant?: \"light\" | \"dark\";\n subtitle?: string;\n title?: string;\n description?: string;\n values?: Value[];\n}\n\nconst defaultValues: Value[] = [\n {\n icon: <Rocket size={32} weight=\"duotone\" />,\n title: \"Innovation\",\n description:\n \"We are committed to constantly pushing boundaries and exploring new ideas, technologies, and solutions to drive innovation and progress\",\n },\n {\n icon: <UserFocus size={32} weight=\"duotone\" />,\n title: \"Customers first\",\n description:\n \"Our customers are at the center of everything we do, and we are dedicated to providing them with the best possible experience and support\",\n },\n {\n icon: <UsersFour size={32} weight=\"duotone\" />,\n title: \"Teamwork\",\n description:\n \"We believe in the power of collaboration and teamwork, and we strive to foster a supportive and inclusive environment\",\n },\n {\n icon: <Eye size={32} weight=\"duotone\" />,\n title: \"Accountability\",\n description:\n \"We take responsibility for our actions and decisions, and we hold ourselves accountable to the highest standards\",\n },\n {\n icon: <Books size={32} weight=\"duotone\" />,\n title: \"Continuous learning\",\n description:\n \"We believe in the importance of continuous learning and growth, and we encourage our team members to pursue development opportunities\",\n },\n {\n icon: <Lightning size={32} weight=\"duotone\" />,\n title: \"Agility\",\n description:\n \"We are adaptable and nimble, and we embrace change as an opportunity to grow and improve\",\n },\n];\n\nexport function CoreValuesGrid({\n variant = \"light\",\n subtitle = \"CORE VALUES\",\n title = \"How we work\",\n description = \"Guided by our core values, we strive to exceed expectations and create meaningful experiences\",\n values = defaultValues,\n}: CoreValuesGridProps) {\n const isDark = variant === \"dark\";\n\n return (\n <section\n className=\"w-full px-6 md:px-20 py-16 md:py-24\"\n style={{\n backgroundColor: isDark\n ? \"var(--canvas-dark-section-bg)\"\n : \"var(--canvas-background)\",\n }}\n >\n <div className=\"max-w-[1240px] mx-auto flex flex-col items-center gap-10 md:gap-12\">\n {/* Header */}\n <div className=\"flex flex-col items-center gap-4 md:gap-6 max-w-[768px] text-center\">\n <div className=\"flex flex-col items-center gap-3\">\n <Typography variant=\"body-xs\" as=\"span\" color=\"muted\" className=\"uppercase tracking-wide\">\n {subtitle}\n </Typography>\n <Typography\n variant=\"h3\"\n as=\"h2\"\n {...(isDark && { style: { color: \"white\" } })}\n >\n {title}\n </Typography>\n </div>\n <Typography\n variant=\"body-l\"\n color=\"muted\"\n className=\"max-w-[576px]\"\n {...(isDark && { style: { color: \"rgba(255, 255, 255, 0.7)\" } })}\n >\n {description}\n </Typography>\n </div>\n\n {/* Values Grid */}\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-12 md:gap-20 w-full\">\n {values.map((value, index) => (\n <div key={index} className=\"flex flex-col gap-5\">\n {/* Icon */}\n <div\n className=\"w-16 h-16 rounded-lg flex items-center justify-center\"\n style={{\n backgroundColor: \"var(--canvas-border)\",\n color: \"var(--canvas-text)\",\n }}\n >\n {value.icon}\n </div>\n\n {/* Text */}\n <div className=\"flex flex-col gap-2\">\n <Typography\n variant=\"h6\"\n as=\"h3\"\n {...(isDark && { style: { color: \"white\" } })}\n >\n {value.title}\n </Typography>\n <Typography\n variant=\"body-m\"\n color=\"muted\"\n {...(isDark && { style: { color: \"rgba(255, 255, 255, 0.7)\" } })}\n >\n {value.description}\n </Typography>\n </div>\n </div>\n ))}\n </div>\n </div>\n </section>\n );\n}\n"
17
+ "content": "\"use client\";\n\nimport {\n Rocket,\n UserFocus,\n UsersFour,\n Eye,\n Books,\n Lightning,\n} from \"@phosphor-icons/react\";\nimport { ReactNode } from \"react\";\nimport { Typography } from \"../../ui/typography\";\n\ninterface Value {\n icon: ReactNode;\n title: string;\n description: string;\n}\n\ninterface CoreValuesGridProps {\n variant?: \"light\" | \"dark\";\n subtitle?: string;\n title?: string;\n description?: string;\n values?: Value[];\n}\n\nconst defaultValues: Value[] = [\n {\n icon: <Rocket size={32} weight=\"duotone\" />,\n title: \"Innovation\",\n description:\n \"We are committed to constantly pushing boundaries and exploring new ideas, technologies, and solutions to drive innovation and progress\",\n },\n {\n icon: <UserFocus size={32} weight=\"duotone\" />,\n title: \"Customers first\",\n description:\n \"Our customers are at the center of everything we do, and we are dedicated to providing them with the best possible experience and support\",\n },\n {\n icon: <UsersFour size={32} weight=\"duotone\" />,\n title: \"Teamwork\",\n description:\n \"We believe in the power of collaboration and teamwork, and we strive to foster a supportive and inclusive environment\",\n },\n {\n icon: <Eye size={32} weight=\"duotone\" />,\n title: \"Accountability\",\n description:\n \"We take responsibility for our actions and decisions, and we hold ourselves accountable to the highest standards\",\n },\n {\n icon: <Books size={32} weight=\"duotone\" />,\n title: \"Continuous learning\",\n description:\n \"We believe in the importance of continuous learning and growth, and we encourage our team members to pursue development opportunities\",\n },\n {\n icon: <Lightning size={32} weight=\"duotone\" />,\n title: \"Agility\",\n description:\n \"We are adaptable and nimble, and we embrace change as an opportunity to grow and improve\",\n },\n];\n\nexport function CoreValuesGrid({\n variant = \"light\",\n subtitle = \"CORE VALUES\",\n title = \"How we work\",\n description = \"Guided by our core values, we strive to exceed expectations and create meaningful experiences\",\n values = defaultValues,\n}: CoreValuesGridProps) {\n const isDark = variant === \"dark\";\n\n return (\n <section\n className=\"w-full px-6 md:px-20 py-16 md:py-24\"\n style={{\n backgroundColor: isDark\n ? \"var(--canvas-dark-section-bg)\"\n : \"var(--canvas-background)\",\n }}\n >\n <div className=\"max-w-[1240px] mx-auto flex flex-col items-center gap-10 md:gap-12\">\n {/* Header */}\n <div className=\"flex flex-col items-center gap-4 md:gap-6 max-w-[768px] text-center\">\n <div className=\"flex flex-col items-center gap-3\">\n <Typography variant=\"body-xs\" as=\"span\" color=\"muted\" className=\"uppercase tracking-wide\">\n {subtitle}\n </Typography>\n <Typography\n variant=\"h3\"\n as=\"h2\"\n {...(isDark && { style: { color: \"white\" } })}\n >\n {title}\n </Typography>\n </div>\n <Typography\n variant=\"body-l\"\n color=\"muted\"\n className=\"max-w-[576px]\"\n {...(isDark && { style: { color: \"rgba(255, 255, 255, 0.7)\" } })}\n >\n {description}\n </Typography>\n </div>\n\n {/* Values Grid */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-12 lg:gap-20 w-full\">\n {values.map((value, index) => (\n <div key={index} className=\"flex flex-col gap-5\">\n {/* Icon */}\n <div\n className=\"w-16 h-16 rounded-lg flex items-center justify-center\"\n style={{\n backgroundColor: \"var(--canvas-border)\",\n color: \"var(--canvas-text)\",\n }}\n >\n {value.icon}\n </div>\n\n {/* Text */}\n <div className=\"flex flex-col gap-2\">\n <Typography\n variant=\"h6\"\n as=\"h3\"\n {...(isDark && { style: { color: \"white\" } })}\n >\n {value.title}\n </Typography>\n <Typography\n variant=\"body-m\"\n color=\"muted\"\n {...(isDark && { style: { color: \"rgba(255, 255, 255, 0.7)\" } })}\n >\n {value.description}\n </Typography>\n </div>\n </div>\n ))}\n </div>\n </div>\n </section>\n );\n}\n"
10
18
  }
11
19
  ],
12
20
  "dependencies": [
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "credit-card-display",
3
3
  "type": "registry:block",
4
- "description": "Visual credit card display showing card details.",
4
+ "description": "Visual credit/debit card display showing card number (masked), cardholder name, expiry date, and card type logo. Use for payment method displays, saved cards, or financial account interfaces.",
5
+ "keywords": [
6
+ "credit-card",
7
+ "payment",
8
+ "card",
9
+ "financial",
10
+ "billing"
11
+ ],
12
+ "visualWeight": "light",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/credit-card-display.tsx",
@@ -1,12 +1,20 @@
1
1
  {
2
2
  "name": "cta-banner",
3
3
  "type": "registry:block",
4
- "description": "Call to action banner with title and button.",
4
+ "description": "Full-width call-to-action banner with heading text and primary action button. Use for newsletter signups, contact prompts, trial starts, or any conversion-focused section.",
5
+ "keywords": [
6
+ "cta",
7
+ "call-to-action",
8
+ "conversion",
9
+ "signup",
10
+ "banner"
11
+ ],
12
+ "visualWeight": "light",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/marketing/cta-banner.tsx",
8
16
  "type": "registry:block",
9
- "content": "\"use client\";\n\nimport { Button } from \"../../ui/button\";\nimport { Typography } from \"../../ui/typography\";\n\ninterface CtaBannerProps {\n title?: string;\n buttonText?: string;\n onButtonClick?: () => void;\n}\n\nexport function CtaBanner({ \n title = \"Ready for your next adventure?\",\n buttonText = \"Book now\",\n onButtonClick \n}: CtaBannerProps) {\n return (\n <section \n className=\"w-full px-4 md:px-8 lg:px-10\"\n >\n <div \n className=\"w-full flex flex-col items-center justify-center text-center\"\n style={{\n backgroundColor: \"var(--canvas-dark-section-bg)\",\n borderRadius: \"var(--radius-3xl)\",\n padding: \"var(--spacing-6xl) var(--spacing-5xl) var(--spacing-7xl)\",\n gap: \"var(--spacing-4xl)\",\n }}\n >\n <Typography \n variant=\"h3\" \n as=\"h2\"\n style={{ color: \"white\" }}\n >\n {title}\n </Typography>\n <Button \n variant=\"primary\" \n size=\"lg\"\n onClick={onButtonClick}\n >\n {buttonText}\n </Button>\n </div>\n </section>\n );\n}\n\n"
17
+ "content": "\"use client\";\n\nimport { Button } from \"../../ui/button\";\nimport { Typography } from \"../../ui/typography\";\n\ninterface CtaBannerProps {\n title?: string;\n buttonText?: string;\n onButtonClick?: () => void;\n}\n\nexport function CtaBanner({ \n title = \"Ready for your next adventure?\",\n buttonText = \"Book now\",\n onButtonClick \n}: CtaBannerProps) {\n return (\n <section \n className=\"w-full px-4 md:px-8 lg:px-10\"\n >\n <div \n className=\"w-full flex flex-col items-center justify-center text-center\"\n style={{\n backgroundColor: \"var(--canvas-dark-section-bg)\",\n borderRadius: \"var(--radius-3xl)\",\n padding: \"var(--spacing-6xl) var(--spacing-5xl) var(--spacing-7xl)\",\n gap: \"var(--spacing-4xl)\",\n }}\n >\n <Typography\n variant=\"h3\"\n as=\"h2\"\n style={{ color: \"white\", maxWidth: 640, textAlign: \"center\" }}\n >\n {title}\n </Typography>\n <Button \n variant=\"primary\" \n size=\"lg\"\n onClick={onButtonClick}\n >\n {buttonText}\n </Button>\n </div>\n </section>\n );\n}\n\n"
10
18
  }
11
19
  ],
12
20
  "dependencies": [],
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "destination-cards",
3
3
  "type": "registry:block",
4
- "description": "Grid of destination cards with images and titles.",
4
+ "description": "4-column card grid with large images, title, item count, and price. Each card has hover zoom effect. Header with title and 'Explore more' link. Use for featured categories, popular items, highlighted locations, or any curated collection showcase.",
5
+ "keywords": [
6
+ "cards",
7
+ "grid",
8
+ "categories",
9
+ "featured",
10
+ "browse",
11
+ "destinations"
12
+ ],
13
+ "visualWeight": "medium",
5
14
  "files": [
6
15
  {
7
16
  "path": "components/blocks/marketing/destination-cards.tsx",
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "detail-drawer",
3
3
  "type": "registry:block",
4
- "description": "Right-side detail drawer with tabbed content. Info tab shows metadata fields (with avatars, badges, links), rich content sections, and file attachments. Comments tab shows a chat-style thread with sender names, timestamps, and a comment input.",
4
+ "description": "Right-side sliding drawer with tabbed content. Info tab shows metadata fields (with avatars, badges, links), rich content sections, and file attachments. Comments tab shows a chat-style thread. Use for row detail views, task details, record inspection, or any side-panel detail interface.",
5
+ "keywords": [
6
+ "drawer",
7
+ "detail",
8
+ "side-panel",
9
+ "inspect",
10
+ "comments",
11
+ "overlay"
12
+ ],
13
+ "visualWeight": "heavy",
5
14
  "files": [
6
15
  {
7
16
  "path": "components/blocks/detail-drawer.tsx",
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "details-popup",
3
3
  "type": "registry:block",
4
- "description": "",
4
+ "description": "Read-only details viewer modal displaying label-value pairs. Centered dialog (~300px tall). Use for displaying product specs, property information, record details, or any structured metadata.",
5
+ "keywords": [
6
+ "details",
7
+ "view",
8
+ "modal",
9
+ "specs",
10
+ "metadata",
11
+ "info"
12
+ ],
13
+ "visualWeight": "light",
5
14
  "files": [
6
15
  {
7
16
  "path": "components/blocks/details-popup.tsx",
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "editable-list",
3
+ "type": "registry:block",
4
+ "description": "Editable list where users can add items via input field and remove them with trash icon buttons. Compact inline element. Use for tag lists, skill lists, or any dynamic list where users add/remove items.",
5
+ "keywords": [
6
+ "list",
7
+ "editable",
8
+ "add",
9
+ "remove",
10
+ "tags",
11
+ "dynamic"
12
+ ],
13
+ "visualWeight": "light",
14
+ "files": [
15
+ {
16
+ "path": "components/blocks/editable-list.tsx",
17
+ "type": "registry:block",
18
+ "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Trash2, Plus } from \"lucide-react\";\nimport { TextInput } from \"../ui/text-input\";\nimport { Label } from \"../ui/label\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface EditableListProps {\n /** Label displayed above the list */\n label?: string;\n /** Current list items */\n items?: string[];\n /** Callback when items change */\n onItemsChange?: (items: string[]) => void;\n /** Placeholder text for the add input */\n addPlaceholder?: string;\n /** Whether the list is disabled */\n disabled?: boolean;\n /** Additional class names */\n className?: string;\n}\n\n// ---------------------------------------------------------------------------\n// EditableList\n// ---------------------------------------------------------------------------\n\nexport function EditableList({\n label,\n items: controlledItems,\n onItemsChange,\n addPlaceholder = \"Enter item\",\n disabled = false,\n className,\n}: EditableListProps) {\n const [internalItems, setInternalItems] = React.useState<string[]>(\n controlledItems ?? []\n );\n const [inputValue, setInputValue] = React.useState(\"\");\n\n const items = controlledItems ?? internalItems;\n\n const updateItems = (newItems: string[]) => {\n setInternalItems(newItems);\n onItemsChange?.(newItems);\n };\n\n const handleAdd = () => {\n const trimmed = inputValue.trim();\n if (!trimmed) return;\n updateItems([...items, trimmed]);\n setInputValue(\"\");\n };\n\n const handleRemove = (index: number) => {\n updateItems(items.filter((_, i) => i !== index));\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n handleAdd();\n }\n };\n\n return (\n <div\n className={cn(\"flex flex-col w-full\", className)}\n style={{ gap: \"var(--spacing-xs)\" }}\n >\n {label && (\n <Label\n className=\"text-[var(--canvas-primary)]\"\n style={{\n fontFamily: \"var(--typo-body-s-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-body-s-size)\",\n lineHeight: \"var(--typo-body-s-line-height)\",\n }}\n >\n {label}\n </Label>\n )}\n\n {/* List items */}\n <div className=\"flex flex-col\">\n {items.map((item, index) => (\n <div\n key={index}\n className=\"flex items-center justify-between border-b border-[var(--canvas-border)]\"\n style={{\n padding: \"var(--spacing-lg) 0\",\n }}\n >\n <span\n style={{\n fontFamily: \"var(--typo-body-m-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-body-m-size)\",\n lineHeight: \"var(--typo-body-m-line-height)\",\n color: \"var(--canvas-text)\",\n }}\n >\n {item}\n </span>\n {!disabled && (\n <button\n type=\"button\"\n onClick={() => handleRemove(index)}\n className=\"flex items-center justify-center text-[var(--canvas-text-muted)] hover:text-[var(--canvas-text)] transition-colors\"\n style={{\n width: \"var(--spacing-3xl)\",\n height: \"var(--spacing-3xl)\",\n }}\n >\n <Trash2 className=\"size-4\" />\n </button>\n )}\n </div>\n ))}\n </div>\n\n {/* Add input row */}\n {!disabled && (\n <div\n className=\"flex items-center w-full\"\n style={{\n gap: \"var(--spacing-md)\",\n paddingTop: \"var(--spacing-md)\",\n }}\n >\n <div className=\"flex-1\">\n <Label\n style={{\n fontFamily: \"var(--typo-body-s-font, var(--typo-global-font))\",\n fontSize: \"var(--typo-body-s-size)\",\n lineHeight: \"var(--typo-body-s-line-height)\",\n color: \"var(--canvas-text)\",\n marginBottom: \"var(--spacing-xs)\",\n display: \"block\",\n }}\n >\n Label\n </Label>\n <TextInput\n placeholder={addPlaceholder}\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n />\n </div>\n <button\n type=\"button\"\n onClick={handleAdd}\n className=\"flex items-center justify-center text-[var(--canvas-text-muted)] hover:text-[var(--canvas-text)] transition-colors self-end\"\n style={{\n width: \"var(--input-standard-height)\",\n height: \"var(--input-standard-height)\",\n }}\n >\n <Plus className=\"size-5\" />\n </button>\n </div>\n )}\n </div>\n );\n}\n"
19
+ }
20
+ ],
21
+ "dependencies": [
22
+ "lucide-react"
23
+ ],
24
+ "registryDependencies": [
25
+ "lib/utils",
26
+ "ui/text-input",
27
+ "ui/label"
28
+ ]
29
+ }
@@ -1,12 +1,20 @@
1
1
  {
2
2
  "name": "empty-state",
3
3
  "type": "registry:block",
4
- "description": "",
4
+ "description": "Centered empty state display with emoji/icon, title, and optional description inside a dashed border card. Compact (~200px tall). Use when a list, table, or content area has no data to show.",
5
+ "keywords": [
6
+ "empty",
7
+ "placeholder",
8
+ "no-data",
9
+ "no-results",
10
+ "blank"
11
+ ],
12
+ "visualWeight": "light",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/empty-state.tsx",
8
16
  "type": "registry:block",
9
- "content": "\"use client\";\n\nimport { cn } from \"../../lib/utils\";\n\ninterface EmptyStateProps {\n icon: string;\n title: string;\n description?: string;\n className?: string;\n}\n\nexport function EmptyState({ icon, title, description, className }: EmptyStateProps) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center py-12 px-6\",\n \"rounded-xl border-2 border-dashed border-[var(--canvas-border)]\",\n \"bg-[var(--canvas-surface)]\",\n className\n )}\n >\n <span className=\"text-4xl mb-3\">{icon}</span>\n <p className=\"text-[var(--canvas-text-muted)] font-medium text-center\">\n {title}\n </p>\n {description && (\n <p className=\"text-[var(--canvas-text-placeholder)] text-center mt-1 max-w-md\" style={{ fontSize: \"var(--typo-body-s-size)\" }}>\n {description}\n </p>\n )}\n </div>\n );\n}\n"
17
+ "content": "\"use client\";\n\nimport { cn } from \"../../lib/utils\";\n\ninterface EmptyStateProps {\n icon: string;\n title: string;\n description?: string;\n className?: string;\n}\n\nexport function EmptyState({ icon, title, description, className }: EmptyStateProps) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center py-12 px-6\",\n \"rounded-xl border-2 border-dashed border-[var(--canvas-border)]\",\n \"bg-[var(--canvas-surface)]\",\n className\n )}\n >\n <span className=\"text-4xl mb-3\">{icon}</span>\n <p className=\"text-[var(--canvas-text-muted)] font-medium text-center\" style={{ fontFamily: \"var(--typo-body-m-font, var(--typo-global-font))\" }}>\n {title}\n </p>\n {description && (\n <p className=\"text-[var(--canvas-text-placeholder)] text-center mt-1 max-w-md\" style={{ fontSize: \"var(--typo-body-s-size)\", fontFamily: \"var(--typo-body-s-font, var(--typo-global-font))\" }}>\n {description}\n </p>\n )}\n </div>\n );\n}\n"
10
18
  }
11
19
  ],
12
20
  "dependencies": [],
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "faq-accordion",
3
3
  "type": "registry:block",
4
- "description": "Expandable FAQ accordion for pricing pages.",
4
+ "description": "Expandable FAQ accordion with question titles and expandable answer text. Use for pricing FAQ sections, help pages, or any expandable Q&A content.",
5
+ "keywords": [
6
+ "faq",
7
+ "questions",
8
+ "answers",
9
+ "accordion",
10
+ "help"
11
+ ],
12
+ "visualWeight": "medium",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/pricing/faq-accordion.tsx",
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "faqs-table",
3
3
  "type": "registry:block",
4
- "description": "Expandable FAQ list with accordion behavior. Shows questions with plus/minus toggle icons, revealing answers one at a time.",
4
+ "description": "Expandable FAQ list with accordion behavior. Shows question text with plus/minus toggle icons, revealing answer text one at a time. Full-width block (~300-600px depending on items). Use for FAQ sections, help centers, or any question-and-answer content.",
5
+ "keywords": [
6
+ "faq",
7
+ "questions",
8
+ "answers",
9
+ "accordion",
10
+ "help",
11
+ "expandable"
12
+ ],
13
+ "visualWeight": "medium",
5
14
  "files": [
6
15
  {
7
16
  "path": "components/blocks/faqs-table.tsx",
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "feature-with-image",
3
3
  "type": "registry:block",
4
- "description": "Feature highlight with image and text side by side.",
4
+ "description": "Two-column feature section with large image on one side and heading, description, benefit list, and CTA button on the other. Image position toggleable (left/right). Stacks vertically on mobile. Use for product features, service explanations, or benefit showcases.",
5
+ "keywords": [
6
+ "feature",
7
+ "two-column",
8
+ "image",
9
+ "benefits",
10
+ "product"
11
+ ],
12
+ "visualWeight": "medium",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/marketing/feature-with-image.tsx",
@@ -1,12 +1,20 @@
1
1
  {
2
2
  "name": "featured-news-cards",
3
3
  "type": "registry:block",
4
- "description": "Featured news/press cards section.",
4
+ "description": "2-column grid of large news/press cards with images, headlines, descriptions, and 'Read more' links. Centered header with subtitle, title, and description. Light and dark variants. Use for press coverage, news highlights, blog features, or content spotlights.",
5
+ "keywords": [
6
+ "news",
7
+ "press",
8
+ "articles",
9
+ "featured",
10
+ "highlights"
11
+ ],
12
+ "visualWeight": "medium",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/marketing/featured-news-cards.tsx",
8
16
  "type": "registry:block",
9
- "content": "\"use client\";\n\nimport { ArrowRight } from \"@phosphor-icons/react\";\nimport { Typography } from \"../../ui/typography\";\n\ninterface NewsItem {\n title: string;\n description: string;\n image: string;\n href?: string;\n}\n\ninterface FeaturedNewsCardsProps {\n variant?: \"light\" | \"dark\";\n subtitle?: string;\n title?: string;\n description?: string;\n items?: NewsItem[];\n}\n\nconst defaultItems: NewsItem[] = [\n {\n title: \"How this company is using AI to 10x its revenue\",\n description:\n \"Explore how this company is leveraging AI to enhance innovation, streamline operations, and improve customer experiences\",\n image:\n \"https://images.unsplash.com/photo-1497366216548-37526070297c?w=800&h=500&fit=crop\",\n href: \"#\",\n },\n {\n title: \"Fundraise on confidence\",\n description:\n \"Discover how our founders successfully raised over $200 million and gain insights to fuel your own fundraising journey.\",\n image:\n \"https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?w=800&h=500&fit=crop\",\n href: \"#\",\n },\n];\n\nexport function FeaturedNewsCards({\n variant = \"light\",\n subtitle = \"IN THE PRESS\",\n title = \"Featured news\",\n description = \"Stay updated with the latest headlines, media coverage, and featured stories about us from top publications\",\n items = defaultItems,\n}: FeaturedNewsCardsProps) {\n const isDark = variant === \"dark\";\n\n return (\n <section\n className=\"w-full px-6 md:px-20 py-16 md:py-24\"\n style={{\n backgroundColor: isDark\n ? \"var(--canvas-dark-section-bg)\"\n : \"var(--canvas-background)\",\n }}\n >\n <div className=\"max-w-[1240px] mx-auto flex flex-col items-center gap-12 md:gap-16\">\n {/* Header */}\n <div className=\"flex flex-col items-center gap-4 md:gap-6 max-w-[768px] text-center\">\n <div className=\"flex flex-col items-center gap-3\">\n <Typography variant=\"body-xs\" as=\"span\" color=\"muted\" className=\"uppercase tracking-wide\">\n {subtitle}\n </Typography>\n <Typography\n variant=\"h3\"\n as=\"h2\"\n {...(isDark && { style: { color: \"white\" } })}\n >\n {title}\n </Typography>\n </div>\n <Typography\n variant=\"body-l\"\n color=\"muted\"\n {...(isDark && { style: { color: \"rgba(255, 255, 255, 0.7)\" } })}\n >\n {description}\n </Typography>\n </div>\n\n {/* News Cards */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-10 w-full\">\n {items.map((item, index) => (\n <div\n key={index}\n className=\"rounded-xl overflow-hidden\"\n style={{\n backgroundColor: isDark\n ? \"var(--canvas-dark-card-bg)\"\n : \"var(--canvas-background)\",\n border: isDark ? \"none\" : \"1px solid var(--canvas-border)\",\n }}\n >\n {/* Image */}\n <div className=\"w-full h-[220px] md:h-[340px]\">\n <img\n src={item.image}\n alt={item.title}\n className=\"w-full h-full object-cover\"\n />\n </div>\n\n {/* Content */}\n <div className=\"flex flex-col gap-1 p-6\">\n <Typography\n variant=\"h6\"\n as=\"h3\"\n {...(isDark && { style: { color: \"white\" } })}\n >\n {item.title}\n </Typography>\n <Typography\n variant=\"body-m\"\n color=\"muted\"\n {...(isDark && { style: { color: \"rgba(255, 255, 255, 0.7)\" } })}\n >\n {item.description}\n </Typography>\n\n {/* Read More Link */}\n <a\n href={item.href || \"#\"}\n className=\"flex items-center gap-2 pt-5 group\"\n >\n <Typography\n variant=\"body-m\"\n as=\"span\"\n {...(isDark && { style: { color: \"white\" } })}\n >\n Read more\n </Typography>\n <div\n className=\"w-6 h-6 rounded-full flex items-center justify-center group-hover:translate-x-1 transition-transform\"\n style={{\n backgroundColor: isDark\n ? \"rgba(255, 255, 255, 0.5)\"\n : \"var(--canvas-text)\",\n }}\n >\n <ArrowRight size={16} weight=\"bold\" color=\"white\" />\n </div>\n </a>\n </div>\n </div>\n ))}\n </div>\n </div>\n </section>\n );\n}\n"
17
+ "content": "\"use client\";\n\nimport { ArrowRight } from \"@phosphor-icons/react\";\nimport { Typography } from \"../../ui/typography\";\n\ninterface NewsItem {\n title: string;\n description: string;\n image: string;\n href?: string;\n}\n\ninterface FeaturedNewsCardsProps {\n variant?: \"light\" | \"dark\";\n subtitle?: string;\n title?: string;\n description?: string;\n items?: NewsItem[];\n}\n\nconst defaultItems: NewsItem[] = [\n {\n title: \"How this company is using AI to 10x its revenue\",\n description:\n \"Explore how this company is leveraging AI to enhance innovation, streamline operations, and improve customer experiences\",\n image:\n \"https://images.unsplash.com/photo-1497366216548-37526070297c?w=800&h=500&fit=crop\",\n href: \"#\",\n },\n {\n title: \"Fundraise on confidence\",\n description:\n \"Discover how our founders successfully raised over $200 million and gain insights to fuel your own fundraising journey.\",\n image:\n \"https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?w=800&h=500&fit=crop\",\n href: \"#\",\n },\n];\n\nexport function FeaturedNewsCards({\n variant = \"light\",\n subtitle = \"IN THE PRESS\",\n title = \"Featured news\",\n description = \"Stay updated with the latest headlines, media coverage, and featured stories about us from top publications\",\n items = defaultItems,\n}: FeaturedNewsCardsProps) {\n const isDark = variant === \"dark\";\n\n return (\n <section\n className=\"w-full px-6 md:px-20 py-16 md:py-24\"\n style={{\n backgroundColor: isDark\n ? \"var(--canvas-dark-section-bg)\"\n : \"var(--canvas-background)\",\n }}\n >\n <div className=\"max-w-[1240px] mx-auto flex flex-col items-center gap-12 md:gap-16\">\n {/* Header */}\n <div className=\"flex flex-col items-center gap-4 md:gap-6 max-w-[768px] text-center\">\n <div className=\"flex flex-col items-center gap-3\">\n <Typography variant=\"body-xs\" as=\"span\" color=\"muted\" className=\"uppercase tracking-wide\">\n {subtitle}\n </Typography>\n <Typography\n variant=\"h3\"\n as=\"h2\"\n {...(isDark && { style: { color: \"white\" } })}\n >\n {title}\n </Typography>\n </div>\n <Typography\n variant=\"body-l\"\n color=\"muted\"\n {...(isDark && { style: { color: \"rgba(255, 255, 255, 0.7)\" } })}\n >\n {description}\n </Typography>\n </div>\n\n {/* News Cards */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-8 sm:gap-10 w-full\">\n {items.map((item, index) => (\n <div\n key={index}\n className=\"rounded-xl overflow-hidden\"\n style={{\n backgroundColor: isDark\n ? \"var(--canvas-dark-card-bg)\"\n : \"var(--canvas-background)\",\n border: isDark ? \"none\" : \"1px solid var(--canvas-border)\",\n }}\n >\n {/* Image */}\n <div className=\"w-full h-[220px] md:h-[340px]\">\n <img\n src={item.image}\n alt={item.title}\n className=\"w-full h-full object-cover\"\n />\n </div>\n\n {/* Content */}\n <div className=\"flex flex-col gap-1 p-6\">\n <Typography\n variant=\"h6\"\n as=\"h3\"\n {...(isDark && { style: { color: \"white\" } })}\n >\n {item.title}\n </Typography>\n <Typography\n variant=\"body-m\"\n color=\"muted\"\n {...(isDark && { style: { color: \"rgba(255, 255, 255, 0.7)\" } })}\n >\n {item.description}\n </Typography>\n\n {/* Read More Link */}\n <a\n href={item.href || \"#\"}\n className=\"flex items-center gap-2 pt-5 group\"\n >\n <Typography\n variant=\"body-m\"\n as=\"span\"\n {...(isDark && { style: { color: \"white\" } })}\n >\n Read more\n </Typography>\n <div\n className=\"w-6 h-6 rounded-full flex items-center justify-center group-hover:translate-x-1 transition-transform\"\n style={{\n backgroundColor: isDark\n ? \"rgba(255, 255, 255, 0.5)\"\n : \"var(--canvas-text)\",\n }}\n >\n <ArrowRight size={16} weight=\"bold\" color=\"white\" />\n </div>\n </a>\n </div>\n </div>\n ))}\n </div>\n </div>\n </section>\n );\n}\n"
10
18
  }
11
19
  ],
12
20
  "dependencies": [
@@ -1,12 +1,20 @@
1
1
  {
2
2
  "name": "featured-places",
3
3
  "type": "registry:block",
4
- "description": "Featured places section with filter pills and card grid.",
4
+ "description": "3-column card grid with filter pill tabs at top, image cards with name, rating, item count, and price. Header with title and 'Explore more' link. Use for filterable catalogs, featured products, or curated collections with category filtering.",
5
+ "keywords": [
6
+ "cards",
7
+ "grid",
8
+ "filter",
9
+ "featured",
10
+ "catalog"
11
+ ],
12
+ "visualWeight": "medium",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/marketing/featured-places.tsx",
8
16
  "type": "registry:block",
9
- "content": "\"use client\";\n\nimport { ArrowRight, Star, Camera, Buildings, Palette, Mountains } from \"@phosphor-icons/react\";\nimport { Typography } from \"../../ui/typography\";\nimport { useState } from \"react\";\n\ninterface FeaturedPlace {\n id: string;\n name: string;\n count: string;\n price: string;\n rating: number;\n image: string;\n}\n\ninterface FilterPill {\n id: string;\n label: string;\n icon: React.ReactNode;\n}\n\nconst defaultFilters: FilterPill[] = [\n { id: \"views\", label: \"Amazing views\", icon: <Camera size={20} /> },\n { id: \"cities\", label: \"Top cities\", icon: <Buildings size={20} /> },\n { id: \"design\", label: \"Design\", icon: <Palette size={20} /> },\n { id: \"countryside\", label: \"Countryside\", icon: <Mountains size={20} /> },\n];\n\nconst defaultPlaces: FeaturedPlace[] = [\n {\n id: \"1\",\n name: \"Sausalito, California\",\n count: \"246 homes\",\n price: \"from $240\",\n rating: 4.92,\n image: \"https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?w=400&h=300&fit=crop\",\n },\n {\n id: \"2\",\n name: \"Portola Valley, California\",\n count: \"634 homes\",\n price: \"from $354\",\n rating: 4.98,\n image: \"https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=400&h=300&fit=crop\",\n },\n {\n id: \"3\",\n name: \"San Francisco, California\",\n count: \"194 homes\",\n price: \"from $278\",\n rating: 4.87,\n image: \"https://images.unsplash.com/photo-1449844908441-8829872d2607?w=400&h=300&fit=crop\",\n },\n {\n id: \"4\",\n name: \"Sonoma, California\",\n count: \"176 homes\",\n price: \"from $543\",\n rating: 4.96,\n image: \"https://images.unsplash.com/photo-1564013799919-ab600027ffc6?w=400&h=300&fit=crop\",\n },\n {\n id: \"5\",\n name: \"Half Moon Bay, California\",\n count: \"83 homes\",\n price: \"from $389\",\n rating: 4.82,\n image: \"https://images.unsplash.com/photo-1600047509807-ba8f99d2cdde?w=400&h=300&fit=crop\",\n },\n {\n id: \"6\",\n name: \"Sebastopol, California\",\n count: \"65 homes\",\n price: \"from $176\",\n rating: 4.84,\n image: \"https://images.unsplash.com/photo-1600566753190-17f0baa2a6c3?w=400&h=300&fit=crop\",\n },\n];\n\nexport function FeaturedPlaces() {\n const [activeFilter, setActiveFilter] = useState(\"views\");\n\n return (\n <section \n className=\"w-full px-4 md:px-8 lg:px-10 py-10 md:py-16\"\n style={{\n backgroundColor: \"var(--canvas-background)\",\n }}\n >\n <div className=\"w-full max-w-[1240px] mx-auto\">\n {/* Header */}\n <div className=\"flex items-center justify-between\" style={{ marginBottom: \"var(--spacing-3xl)\" }}>\n <Typography variant=\"h3\" as=\"h2\">\n Featured places\n </Typography>\n <button \n className=\"flex items-center gap-2 hover:opacity-80 transition-opacity\"\n style={{ paddingTop: \"var(--spacing-2xl)\" }}\n >\n <Typography variant=\"body-l\" as=\"span\" style={{ fontWeight: 600 }}>\n Explore more\n </Typography>\n <div \n className=\"flex items-center justify-center\"\n style={{\n width: \"24px\",\n height: \"24px\",\n backgroundColor: \"var(--canvas-text)\",\n borderRadius: \"var(--radius-4xl)\",\n }}\n >\n <ArrowRight size={16} color=\"white\" weight=\"bold\" />\n </div>\n </button>\n </div>\n\n {/* Filter Pills */}\n <div className=\"flex flex-wrap gap-4 mb-6\" style={{ marginBottom: \"var(--spacing-3xl)\" }}>\n {defaultFilters.map((filter) => (\n <button\n key={filter.id}\n onClick={() => setActiveFilter(filter.id)}\n className=\"flex items-center gap-2 transition-colors\"\n style={{\n height: \"44px\",\n padding: \"0 var(--spacing-xl)\",\n borderRadius: \"var(--spacing-5xl)\",\n border: `1px solid ${activeFilter === filter.id ? \"var(--canvas-primary)\" : \"var(--canvas-border)\"}`,\n backgroundColor: activeFilter === filter.id ? \"var(--canvas-surface-brand)\" : \"var(--canvas-background)\",\n color: activeFilter === filter.id ? \"var(--canvas-primary)\" : \"var(--canvas-text-placeholder)\",\n fontFamily: \"var(--typo-global-font)\",\n fontSize: \"var(--typo-body-s-size)\",\n fontWeight: 500,\n }}\n >\n {filter.icon}\n {filter.label}\n </button>\n ))}\n </div>\n\n {/* Cards Grid */}\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10\">\n {defaultPlaces.map((place) => (\n <div \n key={place.id}\n className=\"group cursor-pointer overflow-hidden\"\n style={{\n border: \"1px solid var(--canvas-border)\",\n borderRadius: \"var(--radius-xl)\",\n }}\n >\n <div \n className=\"w-full overflow-hidden\"\n style={{ \n height: \"240px\",\n borderBottom: \"1px solid var(--canvas-border)\",\n }}\n >\n <img \n src={place.image} \n alt={place.name}\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-300\"\n />\n </div>\n <div \n className=\"flex flex-col\"\n style={{ \n padding: \"0 var(--spacing-3xl) var(--spacing-3xl)\",\n gap: \"var(--spacing-xs)\",\n }}\n >\n <div className=\"flex items-center justify-between mt-6\">\n <Typography variant=\"body-xl\" as=\"h3\" style={{ fontWeight: 600 }}>\n {place.name}\n </Typography>\n <div className=\"flex items-center gap-1\">\n <Star size={16} weight=\"fill\" style={{ color: \"var(--canvas-primary)\" }} />\n <Typography variant=\"body-s\" as=\"span\">\n {place.rating}\n </Typography>\n </div>\n </div>\n <Typography variant=\"body-m\" color=\"muted\">\n {place.count}\n </Typography>\n <Typography variant=\"h6\" as=\"p\" className=\"mt-5\">\n {place.price}\n </Typography>\n </div>\n </div>\n ))}\n </div>\n </div>\n </section>\n );\n}\n"
17
+ "content": "\"use client\";\n\nimport { ArrowRight, Star, Camera, Buildings, Palette, Mountains } from \"@phosphor-icons/react\";\nimport { Typography } from \"../../ui/typography\";\nimport { useState } from \"react\";\n\ninterface FeaturedPlace {\n id: string;\n name: string;\n count: string;\n price: string;\n rating: number;\n image: string;\n}\n\ninterface FilterPill {\n id: string;\n label: string;\n icon: React.ReactNode;\n}\n\nconst defaultFilters: FilterPill[] = [\n { id: \"views\", label: \"Amazing views\", icon: <Camera size={20} /> },\n { id: \"cities\", label: \"Top cities\", icon: <Buildings size={20} /> },\n { id: \"design\", label: \"Design\", icon: <Palette size={20} /> },\n { id: \"countryside\", label: \"Countryside\", icon: <Mountains size={20} /> },\n];\n\nconst defaultPlaces: FeaturedPlace[] = [\n {\n id: \"1\",\n name: \"Sausalito, California\",\n count: \"246 homes\",\n price: \"from $240\",\n rating: 4.92,\n image: \"https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?w=400&h=300&fit=crop\",\n },\n {\n id: \"2\",\n name: \"Portola Valley, California\",\n count: \"634 homes\",\n price: \"from $354\",\n rating: 4.98,\n image: \"https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=400&h=300&fit=crop\",\n },\n {\n id: \"3\",\n name: \"San Francisco, California\",\n count: \"194 homes\",\n price: \"from $278\",\n rating: 4.87,\n image: \"https://images.unsplash.com/photo-1449844908441-8829872d2607?w=400&h=300&fit=crop\",\n },\n {\n id: \"4\",\n name: \"Sonoma, California\",\n count: \"176 homes\",\n price: \"from $543\",\n rating: 4.96,\n image: \"https://images.unsplash.com/photo-1564013799919-ab600027ffc6?w=400&h=300&fit=crop\",\n },\n {\n id: \"5\",\n name: \"Half Moon Bay, California\",\n count: \"83 homes\",\n price: \"from $389\",\n rating: 4.82,\n image: \"https://images.unsplash.com/photo-1600047509807-ba8f99d2cdde?w=400&h=300&fit=crop\",\n },\n {\n id: \"6\",\n name: \"Sebastopol, California\",\n count: \"65 homes\",\n price: \"from $176\",\n rating: 4.84,\n image: \"https://images.unsplash.com/photo-1600566753190-17f0baa2a6c3?w=400&h=300&fit=crop\",\n },\n];\n\ninterface FeaturedPlacesProps {\n /** Custom places to display instead of defaults */\n places?: FeaturedPlace[];\n}\n\nexport function FeaturedPlaces({ places }: FeaturedPlacesProps = {}) {\n const [activeFilter, setActiveFilter] = useState(\"views\");\n const displayPlaces = places ?? defaultPlaces;\n\n return (\n <section \n className=\"w-full px-4 md:px-8 lg:px-10 py-10 md:py-16\"\n style={{\n backgroundColor: \"var(--canvas-background)\",\n }}\n >\n <div className=\"w-full max-w-[1240px] mx-auto\">\n {/* Header */}\n <div className=\"flex items-center justify-between\" style={{ marginBottom: \"var(--spacing-3xl)\" }}>\n <Typography variant=\"h3\" as=\"h2\">\n Featured places\n </Typography>\n <button \n className=\"flex items-center gap-2 hover:opacity-80 transition-opacity\"\n style={{ paddingTop: \"var(--spacing-2xl)\" }}\n >\n <Typography variant=\"body-l\" as=\"span\" style={{ fontWeight: 600 }}>\n Explore more\n </Typography>\n <div \n className=\"flex items-center justify-center\"\n style={{\n width: \"24px\",\n height: \"24px\",\n backgroundColor: \"var(--canvas-text)\",\n borderRadius: \"var(--radius-4xl)\",\n }}\n >\n <ArrowRight size={16} color=\"white\" weight=\"bold\" />\n </div>\n </button>\n </div>\n\n {/* Filter Pills */}\n <div className=\"flex flex-wrap gap-4 mb-6\" style={{ marginBottom: \"var(--spacing-3xl)\" }}>\n {defaultFilters.map((filter) => (\n <button\n key={filter.id}\n onClick={() => setActiveFilter(filter.id)}\n className=\"flex items-center gap-2 transition-colors\"\n style={{\n height: \"44px\",\n padding: \"0 var(--spacing-xl)\",\n borderRadius: \"var(--spacing-5xl)\",\n border: `1px solid ${activeFilter === filter.id ? \"var(--canvas-primary)\" : \"var(--canvas-border)\"}`,\n backgroundColor: activeFilter === filter.id ? \"var(--canvas-surface-brand)\" : \"var(--canvas-background)\",\n color: activeFilter === filter.id ? \"var(--canvas-primary)\" : \"var(--canvas-text-placeholder)\",\n fontFamily: \"var(--typo-global-font)\",\n fontSize: \"var(--typo-body-s-size)\",\n fontWeight: 500,\n }}\n >\n {filter.icon}\n {filter.label}\n </button>\n ))}\n </div>\n\n {/* Cards Grid */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-10\">\n {displayPlaces.map((place) => (\n <div \n key={place.id}\n className=\"group cursor-pointer overflow-hidden\"\n style={{\n border: \"1px solid var(--canvas-border)\",\n borderRadius: \"var(--radius-xl)\",\n }}\n >\n <div \n className=\"w-full overflow-hidden\"\n style={{ \n height: \"240px\",\n borderBottom: \"1px solid var(--canvas-border)\",\n }}\n >\n <img \n src={place.image} \n alt={place.name}\n className=\"w-full h-full object-cover group-hover:scale-105 transition-transform duration-300\"\n />\n </div>\n <div \n className=\"flex flex-col\"\n style={{ \n padding: \"0 var(--spacing-3xl) var(--spacing-3xl)\",\n gap: \"var(--spacing-xs)\",\n }}\n >\n <div className=\"flex items-center justify-between mt-6\">\n <Typography variant=\"body-xl\" as=\"h3\" style={{ fontWeight: 600 }}>\n {place.name}\n </Typography>\n <div className=\"flex items-center gap-1\">\n <Star size={16} weight=\"fill\" style={{ color: \"var(--canvas-primary)\" }} />\n <Typography variant=\"body-s\" as=\"span\">\n {place.rating}\n </Typography>\n </div>\n </div>\n <Typography variant=\"body-m\" color=\"muted\">\n {place.count}\n </Typography>\n <Typography variant=\"h6\" as=\"p\" className=\"mt-5\">\n {place.price}\n </Typography>\n </div>\n </div>\n ))}\n </div>\n </div>\n </section>\n );\n}\n"
10
18
  }
11
19
  ],
12
20
  "dependencies": [
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "features-comparison",
3
3
  "type": "registry:block",
4
- "description": "Feature comparison table across pricing tiers.",
4
+ "description": "Feature comparison table showing plan names across columns and feature rows with check/cross indicators. Use for comparing pricing tiers, product editions, or service levels side by side.",
5
+ "keywords": [
6
+ "comparison",
7
+ "features",
8
+ "plans",
9
+ "table",
10
+ "tiers"
11
+ ],
12
+ "visualWeight": "heavy",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/pricing/features-comparison.tsx",
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "feedback-popup",
3
3
  "type": "registry:block",
4
- "description": "",
4
+ "description": "Compact feedback collection modal with textarea for free-text input. Centered dialog (~250px tall). Use for user feedback, bug reports, feature requests, or any free-text submission.",
5
+ "keywords": [
6
+ "feedback",
7
+ "modal",
8
+ "textarea",
9
+ "comment",
10
+ "report"
11
+ ],
12
+ "visualWeight": "light",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/feedback-popup.tsx",
@@ -1,7 +1,14 @@
1
1
  {
2
2
  "name": "filter-popover",
3
3
  "type": "registry:block",
4
- "description": "Popover with filter controls (checkboxes, date ranges, etc.).",
4
+ "description": "Popover dropdown with filter controls (checkboxes, date ranges, sliders). Triggered by a filter button. Use for refining lists, tables, or search results.",
5
+ "keywords": [
6
+ "filter",
7
+ "popover",
8
+ "dropdown",
9
+ "refine"
10
+ ],
11
+ "visualWeight": "light",
5
12
  "files": [
6
13
  {
7
14
  "path": "components/blocks/filter-popover.tsx",
@@ -1,7 +1,17 @@
1
1
  {
2
2
  "name": "fixed-column-data-table",
3
3
  "type": "registry:block",
4
- "description": "Data table with fixed first column (Name with avatar) that stays visible during horizontal scroll. Ideal for invoice-style tables with columns: Amount, Status badge, Logo, Company, Date Sent.",
4
+ "description": "Data table with fixed first column (name with avatar) that stays visible during horizontal scroll. Remaining columns scroll horizontally. Full-width block (~400-800px). Dense, text-heavy. Use for wide data sets like invoices, financial reports, or comparison tables where the row identifier must stay visible.",
5
+ "keywords": [
6
+ "table",
7
+ "fixed-column",
8
+ "scroll",
9
+ "wide",
10
+ "invoices",
11
+ "financial",
12
+ "comparison"
13
+ ],
14
+ "visualWeight": "heavy",
5
15
  "files": [
6
16
  {
7
17
  "path": "components/blocks/fixed-column-data-table.tsx",
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "flair-banner",
3
3
  "type": "registry:block",
4
- "description": "Dark blue hero banner with large title text. Used at top of pages.",
4
+ "description": "Full-width dark blue hero banner with large title text. Use at the top of content pages for visual emphasis. Pairs well with PageHeaderSection below it.",
5
+ "keywords": [
6
+ "banner",
7
+ "hero",
8
+ "header",
9
+ "decorative",
10
+ "flair"
11
+ ],
12
+ "visualWeight": "spacer",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/flair-banner.tsx",
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "footer-navbar",
3
3
  "type": "registry:block",
4
- "description": "Footer with logo, nav links, and social icons.",
4
+ "description": "Full-width footer with company logo, multi-column navigation link groups, and social media icons. Use at the bottom of any marketing or content page.",
5
+ "keywords": [
6
+ "footer",
7
+ "navigation",
8
+ "links",
9
+ "social",
10
+ "bottom"
11
+ ],
12
+ "visualWeight": "medium",
5
13
  "files": [
6
14
  {
7
15
  "path": "components/blocks/marketing/footer-navbar.tsx",