shadcn-rails 0.1.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.
- checksums.yaml +7 -0
- data/.dockerignore +40 -0
- data/CHANGELOG.md +54 -0
- data/CLAUDE.md +463 -0
- data/PROGRESS.md +485 -0
- data/README.md +1483 -0
- data/Rakefile +29 -0
- data/__tests__/controllers/__snapshots__/calendar_controller.test.js.snap +13 -0
- data/__tests__/controllers/__snapshots__/popover_controller.test.js.snap +46 -0
- data/__tests__/controllers/__snapshots__/sheet_controller.test.js.snap +111 -0
- data/__tests__/controllers/__snapshots__/tabs_controller.test.js.snap +27 -0
- data/__tests__/controllers/accordion_controller.test.js +904 -0
- data/__tests__/controllers/calendar_controller.test.js +1370 -0
- data/__tests__/controllers/carousel_controller.test.js +912 -0
- data/__tests__/controllers/checkbox_controller.test.js +454 -0
- data/__tests__/controllers/collapsible_controller.test.js +407 -0
- data/__tests__/controllers/combobox_controller.test.js +966 -0
- data/__tests__/controllers/context_menu_controller.test.js +627 -0
- data/__tests__/controllers/date_picker_controller.test.js +636 -0
- data/__tests__/controllers/dialog_controller.test.js +878 -0
- data/__tests__/controllers/drawer_controller.test.js +995 -0
- data/__tests__/controllers/menubar_controller.test.js +736 -0
- data/__tests__/controllers/navigation_menu_controller.test.js +598 -0
- data/__tests__/controllers/popover_controller.test.js +1007 -0
- data/__tests__/controllers/radio_group_controller.test.js +640 -0
- data/__tests__/controllers/resizable_controller.test.js +680 -0
- data/__tests__/controllers/select_controller.test.js +674 -0
- data/__tests__/controllers/sheet_controller.test.js +986 -0
- data/__tests__/controllers/slider_controller.test.js +1036 -0
- data/__tests__/controllers/switch_controller.test.js +424 -0
- data/__tests__/controllers/tabs_controller.test.js +907 -0
- data/__tests__/controllers/toggle_group_controller.test.js +839 -0
- data/__tests__/controllers/tooltip_controller.test.js +808 -0
- data/__tests__/helpers/stimulus-test-helper.js +203 -0
- data/app/assets/config/manifest.js +1 -0
- data/app/assets/javascripts/shadcn/controllers/accordion_controller.d.ts +53 -0
- data/app/assets/javascripts/shadcn/controllers/accordion_controller.js +140 -0
- data/app/assets/javascripts/shadcn/controllers/avatar_controller.d.ts +22 -0
- data/app/assets/javascripts/shadcn/controllers/avatar_controller.js +26 -0
- data/app/assets/javascripts/shadcn/controllers/calendar_controller.js +592 -0
- data/app/assets/javascripts/shadcn/controllers/carousel_controller.js +263 -0
- data/app/assets/javascripts/shadcn/controllers/checkbox_controller.d.ts +31 -0
- data/app/assets/javascripts/shadcn/controllers/checkbox_controller.js +48 -0
- data/app/assets/javascripts/shadcn/controllers/collapsible_controller.d.ts +43 -0
- data/app/assets/javascripts/shadcn/controllers/collapsible_controller.js +73 -0
- data/app/assets/javascripts/shadcn/controllers/combobox_controller.js +234 -0
- data/app/assets/javascripts/shadcn/controllers/command_controller.js +141 -0
- data/app/assets/javascripts/shadcn/controllers/command_dialog_controller.js +162 -0
- data/app/assets/javascripts/shadcn/controllers/context_menu_controller.js +202 -0
- data/app/assets/javascripts/shadcn/controllers/date_picker_controller.js +282 -0
- data/app/assets/javascripts/shadcn/controllers/dialog_controller.d.ts +67 -0
- data/app/assets/javascripts/shadcn/controllers/dialog_controller.js +187 -0
- data/app/assets/javascripts/shadcn/controllers/drawer_controller.d.ts +58 -0
- data/app/assets/javascripts/shadcn/controllers/drawer_controller.js +112 -0
- data/app/assets/javascripts/shadcn/controllers/dropdown_controller.d.ts +83 -0
- data/app/assets/javascripts/shadcn/controllers/dropdown_controller.js +225 -0
- data/app/assets/javascripts/shadcn/controllers/hover_card_controller.d.ts +59 -0
- data/app/assets/javascripts/shadcn/controllers/hover_card_controller.js +143 -0
- data/app/assets/javascripts/shadcn/controllers/input_otp_controller.d.ts +44 -0
- data/app/assets/javascripts/shadcn/controllers/input_otp_controller.js +206 -0
- data/app/assets/javascripts/shadcn/controllers/menubar_controller.js +323 -0
- data/app/assets/javascripts/shadcn/controllers/navigation_menu_controller.js +251 -0
- data/app/assets/javascripts/shadcn/controllers/popover_controller.d.ts +56 -0
- data/app/assets/javascripts/shadcn/controllers/popover_controller.js +141 -0
- data/app/assets/javascripts/shadcn/controllers/radio_group_controller.d.ts +47 -0
- data/app/assets/javascripts/shadcn/controllers/radio_group_controller.js +108 -0
- data/app/assets/javascripts/shadcn/controllers/resizable_controller.js +272 -0
- data/app/assets/javascripts/shadcn/controllers/scroll_area_controller.d.ts +44 -0
- data/app/assets/javascripts/shadcn/controllers/scroll_area_controller.js +74 -0
- data/app/assets/javascripts/shadcn/controllers/select_controller.d.ts +84 -0
- data/app/assets/javascripts/shadcn/controllers/select_controller.js +222 -0
- data/app/assets/javascripts/shadcn/controllers/sheet_controller.d.ts +60 -0
- data/app/assets/javascripts/shadcn/controllers/sheet_controller.js +151 -0
- data/app/assets/javascripts/shadcn/controllers/sidebar_controller.js +148 -0
- data/app/assets/javascripts/shadcn/controllers/slider_controller.d.ts +102 -0
- data/app/assets/javascripts/shadcn/controllers/slider_controller.js +364 -0
- data/app/assets/javascripts/shadcn/controllers/switch_controller.d.ts +46 -0
- data/app/assets/javascripts/shadcn/controllers/switch_controller.js +78 -0
- data/app/assets/javascripts/shadcn/controllers/tabs_controller.d.ts +51 -0
- data/app/assets/javascripts/shadcn/controllers/tabs_controller.js +126 -0
- data/app/assets/javascripts/shadcn/controllers/toast_controller.d.ts +37 -0
- data/app/assets/javascripts/shadcn/controllers/toast_controller.js +58 -0
- data/app/assets/javascripts/shadcn/controllers/toggle_controller.d.ts +27 -0
- data/app/assets/javascripts/shadcn/controllers/toggle_controller.js +42 -0
- data/app/assets/javascripts/shadcn/controllers/toggle_group_controller.d.ts +44 -0
- data/app/assets/javascripts/shadcn/controllers/toggle_group_controller.js +68 -0
- data/app/assets/javascripts/shadcn/controllers/tooltip_controller.d.ts +56 -0
- data/app/assets/javascripts/shadcn/controllers/tooltip_controller.js +117 -0
- data/app/assets/javascripts/shadcn/index.d.ts +74 -0
- data/app/assets/javascripts/shadcn/index.js +133 -0
- data/app/assets/stylesheets/.keep +0 -0
- data/app/assets/stylesheets/shadcn/base.css +445 -0
- data/app/assets/stylesheets/shadcn/components.css +513 -0
- data/app/assets/stylesheets/shadcn/index.css +18 -0
- data/app/assets/stylesheets/shadcn/themes/gray.css +68 -0
- data/app/assets/stylesheets/shadcn/themes/slate.css +68 -0
- data/app/assets/stylesheets/shadcn/themes/stone.css +68 -0
- data/app/assets/stylesheets/shadcn/themes/zinc.css +68 -0
- data/app/components/shadcn/accordion_component.rb +63 -0
- data/app/components/shadcn/accordion_content_component.rb +29 -0
- data/app/components/shadcn/accordion_item_component.rb +40 -0
- data/app/components/shadcn/accordion_trigger_component.rb +49 -0
- data/app/components/shadcn/alert_component.rb +75 -0
- data/app/components/shadcn/alert_description_component.rb +12 -0
- data/app/components/shadcn/alert_dialog_action_component.rb +24 -0
- data/app/components/shadcn/alert_dialog_cancel_component.rb +24 -0
- data/app/components/shadcn/alert_dialog_component.rb +71 -0
- data/app/components/shadcn/alert_dialog_content_component.rb +57 -0
- data/app/components/shadcn/alert_dialog_description_component.rb +12 -0
- data/app/components/shadcn/alert_dialog_footer_component.rb +19 -0
- data/app/components/shadcn/alert_dialog_header_component.rb +19 -0
- data/app/components/shadcn/alert_dialog_title_component.rb +12 -0
- data/app/components/shadcn/alert_title_component.rb +12 -0
- data/app/components/shadcn/aspect_ratio_component.rb +49 -0
- data/app/components/shadcn/avatar_component.rb +107 -0
- data/app/components/shadcn/avatar_fallback_component.rb +17 -0
- data/app/components/shadcn/badge_component.rb +49 -0
- data/app/components/shadcn/base_component.rb +100 -0
- data/app/components/shadcn/breadcrumb_component.rb +70 -0
- data/app/components/shadcn/breadcrumb_item_component.rb +50 -0
- data/app/components/shadcn/button_component.rb +141 -0
- data/app/components/shadcn/button_group_component.rb +69 -0
- data/app/components/shadcn/calendar_component.rb +337 -0
- data/app/components/shadcn/card_action_component.rb +10 -0
- data/app/components/shadcn/card_component.rb +63 -0
- data/app/components/shadcn/card_content_component.rb +19 -0
- data/app/components/shadcn/card_description_component.rb +12 -0
- data/app/components/shadcn/card_footer_component.rb +12 -0
- data/app/components/shadcn/card_header_component.rb +24 -0
- data/app/components/shadcn/card_title_component.rb +18 -0
- data/app/components/shadcn/carousel_component.rb +275 -0
- data/app/components/shadcn/checkbox_component.rb +103 -0
- data/app/components/shadcn/collapsible_component.rb +66 -0
- data/app/components/shadcn/collapsible_content_component.rb +28 -0
- data/app/components/shadcn/combobox_component.rb +322 -0
- data/app/components/shadcn/command_component.rb +52 -0
- data/app/components/shadcn/command_dialog_component.rb +76 -0
- data/app/components/shadcn/command_empty_component.rb +12 -0
- data/app/components/shadcn/command_group_component.rb +34 -0
- data/app/components/shadcn/command_input_component.rb +59 -0
- data/app/components/shadcn/command_item_component.rb +48 -0
- data/app/components/shadcn/command_list_component.rb +38 -0
- data/app/components/shadcn/command_separator_component.rb +12 -0
- data/app/components/shadcn/command_shortcut_component.rb +12 -0
- data/app/components/shadcn/context_menu_component.rb +64 -0
- data/app/components/shadcn/context_menu_content_component.rb +44 -0
- data/app/components/shadcn/context_menu_item_component.rb +63 -0
- data/app/components/shadcn/context_menu_label_component.rb +18 -0
- data/app/components/shadcn/context_menu_separator_component.rb +12 -0
- data/app/components/shadcn/context_menu_shortcut_component.rb +12 -0
- data/app/components/shadcn/date_picker_component.rb +368 -0
- data/app/components/shadcn/dialog_component.rb +77 -0
- data/app/components/shadcn/dialog_content_component.rb +91 -0
- data/app/components/shadcn/dialog_description_component.rb +12 -0
- data/app/components/shadcn/dialog_footer_component.rb +12 -0
- data/app/components/shadcn/dialog_header_component.rb +19 -0
- data/app/components/shadcn/dialog_title_component.rb +12 -0
- data/app/components/shadcn/drawer_component.rb +72 -0
- data/app/components/shadcn/drawer_content_component.rb +76 -0
- data/app/components/shadcn/drawer_description_component.rb +12 -0
- data/app/components/shadcn/drawer_footer_component.rb +12 -0
- data/app/components/shadcn/drawer_header_component.rb +19 -0
- data/app/components/shadcn/drawer_title_component.rb +12 -0
- data/app/components/shadcn/dropdown_menu_component.rb +75 -0
- data/app/components/shadcn/dropdown_menu_content_component.rb +49 -0
- data/app/components/shadcn/dropdown_menu_group_component.rb +10 -0
- data/app/components/shadcn/dropdown_menu_item_component.rb +63 -0
- data/app/components/shadcn/dropdown_menu_label_component.rb +18 -0
- data/app/components/shadcn/dropdown_menu_separator_component.rb +12 -0
- data/app/components/shadcn/dropdown_menu_shortcut_component.rb +12 -0
- data/app/components/shadcn/empty_component.rb +48 -0
- data/app/components/shadcn/empty_content_component.rb +12 -0
- data/app/components/shadcn/empty_description_component.rb +12 -0
- data/app/components/shadcn/empty_header_component.rb +29 -0
- data/app/components/shadcn/empty_media_component.rb +21 -0
- data/app/components/shadcn/empty_title_component.rb +12 -0
- data/app/components/shadcn/field_component.rb +113 -0
- data/app/components/shadcn/hover_card_component.rb +64 -0
- data/app/components/shadcn/hover_card_content_component.rb +36 -0
- data/app/components/shadcn/input_component.rb +108 -0
- data/app/components/shadcn/input_group_component.rb +70 -0
- data/app/components/shadcn/input_otp_component.rb +183 -0
- data/app/components/shadcn/item_actions_component.rb +12 -0
- data/app/components/shadcn/item_component.rb +98 -0
- data/app/components/shadcn/item_content_component.rb +24 -0
- data/app/components/shadcn/item_description_component.rb +12 -0
- data/app/components/shadcn/item_footer_component.rb +12 -0
- data/app/components/shadcn/item_group_component.rb +24 -0
- data/app/components/shadcn/item_header_component.rb +12 -0
- data/app/components/shadcn/item_media_component.rb +22 -0
- data/app/components/shadcn/item_separator_component.rb +12 -0
- data/app/components/shadcn/item_title_component.rb +12 -0
- data/app/components/shadcn/kbd_component.rb +36 -0
- data/app/components/shadcn/label_component.rb +49 -0
- data/app/components/shadcn/menubar_checkbox_item_component.rb +76 -0
- data/app/components/shadcn/menubar_component.rb +56 -0
- data/app/components/shadcn/menubar_content_component.rb +64 -0
- data/app/components/shadcn/menubar_item_component.rb +65 -0
- data/app/components/shadcn/menubar_label_component.rb +27 -0
- data/app/components/shadcn/menubar_menu_component.rb +34 -0
- data/app/components/shadcn/menubar_radio_group_component.rb +42 -0
- data/app/components/shadcn/menubar_radio_item_component.rb +76 -0
- data/app/components/shadcn/menubar_separator_component.rb +22 -0
- data/app/components/shadcn/menubar_shortcut_component.rb +21 -0
- data/app/components/shadcn/menubar_sub_component.rb +38 -0
- data/app/components/shadcn/menubar_sub_content_component.rb +45 -0
- data/app/components/shadcn/menubar_sub_trigger_component.rb +59 -0
- data/app/components/shadcn/menubar_trigger_component.rb +31 -0
- data/app/components/shadcn/native_select_component.rb +150 -0
- data/app/components/shadcn/navigation_menu_component.rb +76 -0
- data/app/components/shadcn/navigation_menu_content_component.rb +30 -0
- data/app/components/shadcn/navigation_menu_item_component.rb +39 -0
- data/app/components/shadcn/navigation_menu_link_component.rb +38 -0
- data/app/components/shadcn/navigation_menu_list_component.rb +29 -0
- data/app/components/shadcn/navigation_menu_trigger_component.rb +59 -0
- data/app/components/shadcn/pagination_component.rb +195 -0
- data/app/components/shadcn/pagination_content_component.rb +47 -0
- data/app/components/shadcn/pagination_ellipsis_component.rb +30 -0
- data/app/components/shadcn/pagination_item_component.rb +53 -0
- data/app/components/shadcn/pagination_next_component.rb +48 -0
- data/app/components/shadcn/pagination_previous_component.rb +48 -0
- data/app/components/shadcn/popover_component.rb +76 -0
- data/app/components/shadcn/popover_content_component.rb +25 -0
- data/app/components/shadcn/progress_component.rb +77 -0
- data/app/components/shadcn/radio_group_component.rb +129 -0
- data/app/components/shadcn/radio_group_item_component.rb +109 -0
- data/app/components/shadcn/resizable_handle_component.rb +98 -0
- data/app/components/shadcn/resizable_panel_component.rb +56 -0
- data/app/components/shadcn/resizable_panel_group_component.rb +94 -0
- data/app/components/shadcn/scroll_area_component.rb +110 -0
- data/app/components/shadcn/select_component.rb +151 -0
- data/app/components/shadcn/select_group_component.rb +32 -0
- data/app/components/shadcn/select_item_component.rb +59 -0
- data/app/components/shadcn/select_separator_component.rb +12 -0
- data/app/components/shadcn/separator_component.rb +54 -0
- data/app/components/shadcn/sheet_component.rb +82 -0
- data/app/components/shadcn/sheet_content_component.rb +95 -0
- data/app/components/shadcn/sheet_description_component.rb +12 -0
- data/app/components/shadcn/sheet_footer_component.rb +12 -0
- data/app/components/shadcn/sheet_header_component.rb +19 -0
- data/app/components/shadcn/sheet_title_component.rb +12 -0
- data/app/components/shadcn/sidebar_component.rb +180 -0
- data/app/components/shadcn/sidebar_content_component.rb +32 -0
- data/app/components/shadcn/sidebar_footer_component.rb +24 -0
- data/app/components/shadcn/sidebar_group_action_component.rb +26 -0
- data/app/components/shadcn/sidebar_group_component.rb +38 -0
- data/app/components/shadcn/sidebar_group_content_component.rb +32 -0
- data/app/components/shadcn/sidebar_group_label_component.rb +25 -0
- data/app/components/shadcn/sidebar_header_component.rb +24 -0
- data/app/components/shadcn/sidebar_inset_component.rb +25 -0
- data/app/components/shadcn/sidebar_menu_action_component.rb +37 -0
- data/app/components/shadcn/sidebar_menu_badge_component.rb +25 -0
- data/app/components/shadcn/sidebar_menu_button_component.rb +52 -0
- data/app/components/shadcn/sidebar_menu_component.rb +32 -0
- data/app/components/shadcn/sidebar_menu_item_component.rb +41 -0
- data/app/components/shadcn/sidebar_menu_skeleton_component.rb +46 -0
- data/app/components/shadcn/sidebar_menu_sub_button_component.rb +43 -0
- data/app/components/shadcn/sidebar_menu_sub_component.rb +33 -0
- data/app/components/shadcn/sidebar_menu_sub_item_component.rb +30 -0
- data/app/components/shadcn/sidebar_provider_component.rb +57 -0
- data/app/components/shadcn/sidebar_rail_component.rb +30 -0
- data/app/components/shadcn/sidebar_separator_component.rb +24 -0
- data/app/components/shadcn/sidebar_trigger_component.rb +51 -0
- data/app/components/shadcn/skeleton_component.rb +29 -0
- data/app/components/shadcn/slider_component.rb +76 -0
- data/app/components/shadcn/spinner_component.rb +67 -0
- data/app/components/shadcn/switch_component.rb +147 -0
- data/app/components/shadcn/table_body_component.rb +16 -0
- data/app/components/shadcn/table_caption_component.rb +12 -0
- data/app/components/shadcn/table_cell_component.rb +12 -0
- data/app/components/shadcn/table_component.rb +57 -0
- data/app/components/shadcn/table_footer_component.rb +16 -0
- data/app/components/shadcn/table_head_component.rb +12 -0
- data/app/components/shadcn/table_header_component.rb +16 -0
- data/app/components/shadcn/table_row_component.rb +40 -0
- data/app/components/shadcn/tabs_component.rb +78 -0
- data/app/components/shadcn/tabs_content_component.rb +32 -0
- data/app/components/shadcn/tabs_list_component.rb +30 -0
- data/app/components/shadcn/tabs_trigger_component.rb +37 -0
- data/app/components/shadcn/textarea_component.rb +84 -0
- data/app/components/shadcn/toast_action_component.rb +18 -0
- data/app/components/shadcn/toast_component.rb +114 -0
- data/app/components/shadcn/toast_description_component.rb +12 -0
- data/app/components/shadcn/toast_title_component.rb +12 -0
- data/app/components/shadcn/toast_viewport_component.rb +12 -0
- data/app/components/shadcn/toggle_component.rb +77 -0
- data/app/components/shadcn/toggle_group_component.rb +96 -0
- data/app/components/shadcn/toggle_group_item_component.rb +62 -0
- data/app/components/shadcn/tooltip_component.rb +89 -0
- data/app/components/shadcn/typography_component.rb +112 -0
- data/babel.config.cjs +5 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/config/importmap.rb +5 -0
- data/fly.toml +26 -0
- data/jest.config.js +19 -0
- data/jest.setup.js +8 -0
- data/lib/generators/shadcn/component/component_generator.rb +188 -0
- data/lib/generators/shadcn/install/install_generator.rb +140 -0
- data/lib/generators/shadcn/install/templates/initializer.rb.tt +35 -0
- data/lib/generators/shadcn/install/templates/shadcn.yml.tt +35 -0
- data/lib/generators/shadcn/theme/theme_generator.rb +128 -0
- data/lib/shadcn/rails/class_merger.rb +228 -0
- data/lib/shadcn/rails/configuration.rb +341 -0
- data/lib/shadcn/rails/engine.rb +59 -0
- data/lib/shadcn/rails/helpers/class_name_helper.rb +35 -0
- data/lib/shadcn/rails/helpers/component_helper.rb +60 -0
- data/lib/shadcn/rails/helpers/pagination_helper.rb +187 -0
- data/lib/shadcn/rails/version.rb +7 -0
- data/lib/shadcn/rails.rb +179 -0
- data/package-lock.json +7415 -0
- data/package.json +68 -0
- data/rollup.config.js +29 -0
- data/sig/shadcn/rails.rbs +6 -0
- metadata +526 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dialog Content component
|
|
5
|
+
class DialogContentComponent < BaseComponent
|
|
6
|
+
OVERLAY_CLASSES = "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
|
7
|
+
CONTENT_CLASSES = "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg"
|
|
8
|
+
CLOSE_CLASSES = "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
|
|
9
|
+
|
|
10
|
+
renders_one :header, lambda { |**options|
|
|
11
|
+
DialogHeaderComponent.new(**options)
|
|
12
|
+
}
|
|
13
|
+
renders_one :title, lambda { |**options|
|
|
14
|
+
DialogTitleComponent.new(**options)
|
|
15
|
+
}
|
|
16
|
+
renders_one :description, lambda { |**options|
|
|
17
|
+
DialogDescriptionComponent.new(**options)
|
|
18
|
+
}
|
|
19
|
+
renders_one :footer, lambda { |**options|
|
|
20
|
+
DialogFooterComponent.new(**options)
|
|
21
|
+
}
|
|
22
|
+
renders_one :close_button
|
|
23
|
+
|
|
24
|
+
def call
|
|
25
|
+
# Portal container that will be moved to body
|
|
26
|
+
content_tag(:template, content_wrapper, { "data-shadcn--dialog-target": "template" })
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def content_wrapper
|
|
32
|
+
safe_join([
|
|
33
|
+
overlay,
|
|
34
|
+
dialog_panel
|
|
35
|
+
])
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def overlay
|
|
39
|
+
content_tag(:div, "", {
|
|
40
|
+
class: OVERLAY_CLASSES,
|
|
41
|
+
"data-shadcn--dialog-target": "overlay",
|
|
42
|
+
"data-action": "click->shadcn--dialog#close",
|
|
43
|
+
"data-state": "closed",
|
|
44
|
+
"aria-hidden": "true"
|
|
45
|
+
})
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def dialog_panel
|
|
49
|
+
content_tag(:div, panel_content, {
|
|
50
|
+
class: cn(CONTENT_CLASSES, class_name),
|
|
51
|
+
role: "dialog",
|
|
52
|
+
"aria-modal": "true",
|
|
53
|
+
"data-shadcn--dialog-target": "content",
|
|
54
|
+
"data-state": "closed",
|
|
55
|
+
tabindex: "-1"
|
|
56
|
+
})
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def panel_content
|
|
60
|
+
safe_join([
|
|
61
|
+
header,
|
|
62
|
+
title,
|
|
63
|
+
description,
|
|
64
|
+
content,
|
|
65
|
+
footer,
|
|
66
|
+
close_element
|
|
67
|
+
].compact)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def close_element
|
|
71
|
+
content_tag(:button, close_icon, {
|
|
72
|
+
type: "button",
|
|
73
|
+
class: CLOSE_CLASSES,
|
|
74
|
+
"data-action": "click->shadcn--dialog#close",
|
|
75
|
+
"aria-label": "Close"
|
|
76
|
+
})
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def close_icon
|
|
80
|
+
content_tag(:svg,
|
|
81
|
+
content_tag(:path, nil, d: "M18 6 6 18M6 6l12 12", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round"),
|
|
82
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
83
|
+
width: "16",
|
|
84
|
+
height: "16",
|
|
85
|
+
viewBox: "0 0 24 24",
|
|
86
|
+
fill: "none",
|
|
87
|
+
class: "h-4 w-4"
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dialog Description component
|
|
5
|
+
class DialogDescriptionComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "text-sm text-muted-foreground"
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
content_tag(:p, content, class: merge_classes(BASE_CLASSES))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dialog Footer component
|
|
5
|
+
class DialogFooterComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2"
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
content_tag(:div, content, class: merge_classes(BASE_CLASSES))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dialog Header component
|
|
5
|
+
class DialogHeaderComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "flex flex-col space-y-1.5 text-center sm:text-left"
|
|
7
|
+
|
|
8
|
+
renders_one :title, lambda { |**options|
|
|
9
|
+
DialogTitleComponent.new(**options)
|
|
10
|
+
}
|
|
11
|
+
renders_one :description, lambda { |**options|
|
|
12
|
+
DialogDescriptionComponent.new(**options)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
content_tag(:div, safe_join([title, description, content].compact), class: merge_classes(BASE_CLASSES))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dialog Title component
|
|
5
|
+
class DialogTitleComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "text-lg font-semibold leading-none tracking-tight"
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
content_tag(:h2, content, class: merge_classes(BASE_CLASSES))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Drawer component for mobile-optimized modal panels
|
|
5
|
+
# Matches shadcn/ui Drawer component (built on Vaul)
|
|
6
|
+
#
|
|
7
|
+
# @example Basic drawer
|
|
8
|
+
# <%= render Shadcn::DrawerComponent.new do |drawer| %>
|
|
9
|
+
# <% drawer.with_trigger do %>
|
|
10
|
+
# <%= render Shadcn::ButtonComponent.new { "Open Drawer" } %>
|
|
11
|
+
# <% end %>
|
|
12
|
+
# <% drawer.with_body do |body| %>
|
|
13
|
+
# <% body.with_header do |header| %>
|
|
14
|
+
# <% header.with_title { "Edit Profile" } %>
|
|
15
|
+
# <% header.with_description { "Make changes to your profile." } %>
|
|
16
|
+
# <% end %>
|
|
17
|
+
# <div class="p-4">Content here</div>
|
|
18
|
+
# <% body.with_footer do %>
|
|
19
|
+
# <%= render Shadcn::ButtonComponent.new { "Save" } %>
|
|
20
|
+
# <% end %>
|
|
21
|
+
# <% end %>
|
|
22
|
+
# <% end %>
|
|
23
|
+
#
|
|
24
|
+
class DrawerComponent < BaseComponent
|
|
25
|
+
renders_one :trigger
|
|
26
|
+
renders_one :body, lambda { |**options|
|
|
27
|
+
DrawerContentComponent.new(**options)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# @param open [Boolean] Whether drawer starts open
|
|
31
|
+
# @param direction [Symbol] :bottom, :top, :left, or :right
|
|
32
|
+
def initialize(open: false, direction: :bottom, **options)
|
|
33
|
+
super(**options)
|
|
34
|
+
@open = open
|
|
35
|
+
@direction = direction
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def call
|
|
39
|
+
content_tag(:div, drawer_content, drawer_attributes)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def drawer_content
|
|
45
|
+
safe_join([
|
|
46
|
+
trigger_wrapper,
|
|
47
|
+
body
|
|
48
|
+
].compact)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def trigger_wrapper
|
|
52
|
+
return unless trigger
|
|
53
|
+
|
|
54
|
+
content_tag(:div, trigger, {
|
|
55
|
+
"data-shadcn--drawer-target": "trigger",
|
|
56
|
+
"data-action": "click->shadcn--drawer#open"
|
|
57
|
+
})
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def drawer_attributes
|
|
61
|
+
attrs = {
|
|
62
|
+
class: class_name,
|
|
63
|
+
"data-controller": "shadcn--drawer",
|
|
64
|
+
"data-shadcn--drawer-open-value": @open.to_s,
|
|
65
|
+
"data-shadcn--drawer-direction-value": @direction.to_s
|
|
66
|
+
}
|
|
67
|
+
attrs.merge!(html_options)
|
|
68
|
+
attrs.merge!(build_data)
|
|
69
|
+
attrs.compact
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Drawer Content component
|
|
5
|
+
class DrawerContentComponent < BaseComponent
|
|
6
|
+
OVERLAY_CLASSES = "fixed inset-0 z-50 bg-black/80"
|
|
7
|
+
CONTENT_CLASSES = {
|
|
8
|
+
bottom: "fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
|
|
9
|
+
top: "fixed inset-x-0 top-0 z-50 mb-24 flex h-auto flex-col rounded-b-[10px] border bg-background",
|
|
10
|
+
left: "fixed inset-y-0 left-0 z-50 h-full w-3/4 max-w-sm flex flex-col border-r bg-background",
|
|
11
|
+
right: "fixed inset-y-0 right-0 z-50 h-full w-3/4 max-w-sm flex flex-col border-l bg-background"
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
renders_one :header, lambda { |**options|
|
|
15
|
+
DrawerHeaderComponent.new(**options)
|
|
16
|
+
}
|
|
17
|
+
renders_one :footer, lambda { |**options|
|
|
18
|
+
DrawerFooterComponent.new(**options)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# @param direction [Symbol] :bottom, :top, :left, or :right
|
|
22
|
+
def initialize(direction: :bottom, **options, &block)
|
|
23
|
+
super(**options, &block)
|
|
24
|
+
@direction = direction
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def call
|
|
28
|
+
content_tag(:template, content_wrapper, { "data-shadcn--drawer-target": "template" })
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def content_wrapper
|
|
34
|
+
safe_join([
|
|
35
|
+
overlay,
|
|
36
|
+
drawer_panel
|
|
37
|
+
])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def overlay
|
|
41
|
+
content_tag(:div, "", {
|
|
42
|
+
class: OVERLAY_CLASSES,
|
|
43
|
+
"data-shadcn--drawer-target": "overlay",
|
|
44
|
+
"data-action": "click->shadcn--drawer#close",
|
|
45
|
+
"data-state": "closed"
|
|
46
|
+
})
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def drawer_panel
|
|
50
|
+
content_tag(:div, panel_content, {
|
|
51
|
+
class: cn(CONTENT_CLASSES[@direction] || CONTENT_CLASSES[:bottom], class_name),
|
|
52
|
+
role: "dialog",
|
|
53
|
+
"aria-modal": "true",
|
|
54
|
+
"data-shadcn--drawer-target": "content",
|
|
55
|
+
"data-state": "closed",
|
|
56
|
+
"data-direction": @direction.to_s,
|
|
57
|
+
tabindex: "-1"
|
|
58
|
+
})
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def panel_content
|
|
62
|
+
safe_join([
|
|
63
|
+
handle_bar,
|
|
64
|
+
header,
|
|
65
|
+
content,
|
|
66
|
+
footer
|
|
67
|
+
].compact)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def handle_bar
|
|
71
|
+
return unless [:bottom, :top].include?(@direction)
|
|
72
|
+
|
|
73
|
+
content_tag(:div, class: "mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted") { "" }
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Drawer Description component
|
|
5
|
+
class DrawerDescriptionComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "text-sm text-muted-foreground"
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
content_tag(:p, content, class: merge_classes(BASE_CLASSES))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Drawer Footer component
|
|
5
|
+
class DrawerFooterComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "mt-auto flex flex-col gap-2 p-4"
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
content_tag(:div, content, class: merge_classes(BASE_CLASSES))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Drawer Header component
|
|
5
|
+
class DrawerHeaderComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "grid gap-1.5 p-4 text-center sm:text-left"
|
|
7
|
+
|
|
8
|
+
renders_one :title, lambda { |**options|
|
|
9
|
+
DrawerTitleComponent.new(**options)
|
|
10
|
+
}
|
|
11
|
+
renders_one :description, lambda { |**options|
|
|
12
|
+
DrawerDescriptionComponent.new(**options)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
content_tag(:div, safe_join([title, description, content].compact), class: merge_classes(BASE_CLASSES))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Drawer Title component
|
|
5
|
+
class DrawerTitleComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "text-lg font-semibold leading-none tracking-tight"
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
content_tag(:h2, content, class: merge_classes(BASE_CLASSES))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dropdown Menu component
|
|
5
|
+
# Matches shadcn/ui DropdownMenu component
|
|
6
|
+
# Uses Stimulus for interactivity
|
|
7
|
+
#
|
|
8
|
+
# @example Basic dropdown
|
|
9
|
+
# <%= render Shadcn::DropdownMenuComponent.new do |menu| %>
|
|
10
|
+
# <% menu.with_trigger do %>
|
|
11
|
+
# <%= render Shadcn::ButtonComponent.new(variant: :outline) { "Open Menu" } %>
|
|
12
|
+
# <% end %>
|
|
13
|
+
# <% menu.with_content do |content| %>
|
|
14
|
+
# <% content.with_label { "My Account" } %>
|
|
15
|
+
# <% content.with_separator %>
|
|
16
|
+
# <% content.with_item(href: "/profile") { "Profile" } %>
|
|
17
|
+
# <% content.with_item(href: "/settings") { "Settings" } %>
|
|
18
|
+
# <% content.with_separator %>
|
|
19
|
+
# <% content.with_item(variant: :destructive) { "Log out" } %>
|
|
20
|
+
# <% end %>
|
|
21
|
+
# <% end %>
|
|
22
|
+
#
|
|
23
|
+
class DropdownMenuComponent < BaseComponent
|
|
24
|
+
renders_one :trigger
|
|
25
|
+
renders_one :menu, lambda { |**options|
|
|
26
|
+
DropdownMenuContentComponent.new(**options)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# @param open [Boolean] Whether dropdown starts open
|
|
30
|
+
# @param align [Symbol] Content alignment (:start, :center, :end)
|
|
31
|
+
# @param side [Symbol] Side to show content (:top, :right, :bottom, :left)
|
|
32
|
+
def initialize(open: false, align: :end, side: :bottom, **options)
|
|
33
|
+
super(**options)
|
|
34
|
+
@open = open
|
|
35
|
+
@align = align
|
|
36
|
+
@side = side
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def call
|
|
40
|
+
content_tag(:div, dropdown_content, dropdown_attributes)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def dropdown_content
|
|
46
|
+
safe_join([
|
|
47
|
+
trigger_wrapper,
|
|
48
|
+
menu
|
|
49
|
+
].compact)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def trigger_wrapper
|
|
53
|
+
return unless trigger
|
|
54
|
+
|
|
55
|
+
content_tag(:div, trigger, {
|
|
56
|
+
"data-shadcn--dropdown-target": "trigger",
|
|
57
|
+
"data-action": "click->shadcn--dropdown#toggle"
|
|
58
|
+
})
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def dropdown_attributes
|
|
62
|
+
attrs = {
|
|
63
|
+
class: cn("relative inline-block", class_name),
|
|
64
|
+
"data-controller": "shadcn--dropdown",
|
|
65
|
+
"data-shadcn--dropdown-open-value": @open.to_s,
|
|
66
|
+
"data-shadcn--dropdown-align-value": @align.to_s,
|
|
67
|
+
"data-shadcn--dropdown-side-value": @side.to_s,
|
|
68
|
+
"data-action": "keydown.escape->shadcn--dropdown#close clickOutside->shadcn--dropdown#close"
|
|
69
|
+
}
|
|
70
|
+
attrs.merge!(html_options)
|
|
71
|
+
attrs.merge!(build_data)
|
|
72
|
+
attrs.compact
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dropdown Menu Content component
|
|
5
|
+
class DropdownMenuContentComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=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"
|
|
7
|
+
|
|
8
|
+
renders_many :items, lambda { |**options, &block|
|
|
9
|
+
DropdownMenuItemComponent.new(**options, &block)
|
|
10
|
+
}
|
|
11
|
+
renders_many :labels, lambda { |**options, &block|
|
|
12
|
+
DropdownMenuLabelComponent.new(**options, &block)
|
|
13
|
+
}
|
|
14
|
+
renders_many :separators, lambda { |**options|
|
|
15
|
+
DropdownMenuSeparatorComponent.new(**options)
|
|
16
|
+
}
|
|
17
|
+
renders_many :groups, lambda { |**options, &block|
|
|
18
|
+
DropdownMenuGroupComponent.new(**options, &block)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
def call
|
|
22
|
+
content_tag(:div, menu_content, menu_attributes)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def menu_content
|
|
28
|
+
# If items/labels/separators are used, render them
|
|
29
|
+
# Otherwise render the block content
|
|
30
|
+
if items.any? || labels.any? || separators.any? || groups.any?
|
|
31
|
+
safe_join([labels, items, separators, groups, content].flatten.compact)
|
|
32
|
+
else
|
|
33
|
+
content
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def menu_attributes
|
|
38
|
+
{
|
|
39
|
+
class: merge_classes(BASE_CLASSES),
|
|
40
|
+
role: "menu",
|
|
41
|
+
"aria-orientation": "vertical",
|
|
42
|
+
"data-shadcn--dropdown-target": "content",
|
|
43
|
+
"data-state": "closed",
|
|
44
|
+
"data-side": "bottom",
|
|
45
|
+
hidden: true
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dropdown Menu Item component
|
|
5
|
+
class DropdownMenuItemComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0"
|
|
7
|
+
|
|
8
|
+
VARIANTS = {
|
|
9
|
+
default: "",
|
|
10
|
+
destructive: "text-destructive focus:bg-destructive focus:text-destructive-foreground"
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
renders_one :shortcut, lambda { |**options|
|
|
14
|
+
DropdownMenuShortcutComponent.new(**options)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# @param href [String, nil] Link URL
|
|
18
|
+
# @param variant [Symbol] Item variant (:default, :destructive)
|
|
19
|
+
# @param disabled [Boolean] Whether item is disabled
|
|
20
|
+
# @param inset [Boolean] Whether to add left padding for icons
|
|
21
|
+
def initialize(href: nil, variant: :default, disabled: false, inset: false, **options, &block)
|
|
22
|
+
super(**options, &block)
|
|
23
|
+
@href = href
|
|
24
|
+
@variant = variant.to_sym
|
|
25
|
+
@disabled = disabled
|
|
26
|
+
@inset = inset
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def call
|
|
30
|
+
tag_name = @href ? :a : :div
|
|
31
|
+
content_tag(tag_name, item_content, item_attributes)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def item_content
|
|
37
|
+
safe_join([content, shortcut].compact)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def item_classes
|
|
41
|
+
cn(
|
|
42
|
+
BASE_CLASSES,
|
|
43
|
+
VARIANTS[@variant],
|
|
44
|
+
@inset ? "pl-8" : "",
|
|
45
|
+
class_name
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def item_attributes
|
|
50
|
+
attrs = {
|
|
51
|
+
class: item_classes,
|
|
52
|
+
role: "menuitem",
|
|
53
|
+
tabindex: @disabled ? nil : "-1",
|
|
54
|
+
href: @href,
|
|
55
|
+
"data-disabled": @disabled ? "" : nil,
|
|
56
|
+
"data-action": "click->shadcn--dropdown#selectItem"
|
|
57
|
+
}
|
|
58
|
+
attrs.merge!(html_options)
|
|
59
|
+
attrs.merge!(build_data)
|
|
60
|
+
attrs.compact
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dropdown Menu Label component
|
|
5
|
+
class DropdownMenuLabelComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "px-2 py-1.5 text-sm font-semibold"
|
|
7
|
+
|
|
8
|
+
# @param inset [Boolean] Whether to add left padding
|
|
9
|
+
def initialize(inset: false, **options, &block)
|
|
10
|
+
super(**options, &block)
|
|
11
|
+
@inset = inset
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def call
|
|
15
|
+
content_tag(:div, content, class: cn(BASE_CLASSES, @inset ? "pl-8" : "", class_name))
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dropdown Menu Separator component
|
|
5
|
+
class DropdownMenuSeparatorComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "-mx-1 my-1 h-px bg-muted"
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
content_tag(:div, "", class: merge_classes(BASE_CLASSES), role: "separator")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Dropdown Menu Shortcut component
|
|
5
|
+
class DropdownMenuShortcutComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "ml-auto text-xs tracking-widest opacity-60"
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
content_tag(:span, content, class: merge_classes(BASE_CLASSES))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Empty state component for displaying placeholder content when no data is available
|
|
5
|
+
# Matches shadcn/ui Empty component
|
|
6
|
+
#
|
|
7
|
+
# @example Basic empty state
|
|
8
|
+
# <%= render Shadcn::EmptyComponent.new do |empty| %>
|
|
9
|
+
# <% empty.with_header do |header| %>
|
|
10
|
+
# <% header.with_media(variant: :icon) do %>
|
|
11
|
+
# <svg>...</svg>
|
|
12
|
+
# <% end %>
|
|
13
|
+
# <% header.with_title { "No Projects Yet" } %>
|
|
14
|
+
# <% header.with_description { "Get started by creating your first project." } %>
|
|
15
|
+
# <% end %>
|
|
16
|
+
# <% empty.with_content do %>
|
|
17
|
+
# <%= render Shadcn::ButtonComponent.new { "Create Project" } %>
|
|
18
|
+
# <% end %>
|
|
19
|
+
# <% end %>
|
|
20
|
+
#
|
|
21
|
+
# @example With outline style
|
|
22
|
+
# <%= render Shadcn::EmptyComponent.new(class_name: "border border-dashed") do |empty| %>
|
|
23
|
+
# ...
|
|
24
|
+
# <% end %>
|
|
25
|
+
#
|
|
26
|
+
class EmptyComponent < BaseComponent
|
|
27
|
+
BASE_CLASSES = "flex flex-col items-center justify-center gap-6 py-16 text-center"
|
|
28
|
+
|
|
29
|
+
# Header slot containing media, title, and description
|
|
30
|
+
renders_one :header, lambda { |**options|
|
|
31
|
+
EmptyHeaderComponent.new(**options)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Content slot for action buttons
|
|
35
|
+
renders_one :content_slot, lambda { |**options|
|
|
36
|
+
EmptyContentComponent.new(**options)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Alias for more intuitive API
|
|
40
|
+
alias_method :with_content, :with_content_slot
|
|
41
|
+
|
|
42
|
+
def call
|
|
43
|
+
content_tag(:div, class: merge_classes(BASE_CLASSES), **html_options.merge(build_data)) do
|
|
44
|
+
safe_join([header, content_slot, content].compact)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Empty Content component - container for action buttons
|
|
5
|
+
class EmptyContentComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "flex flex-col items-center gap-2"
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
content_tag(:div, content, class: merge_classes(BASE_CLASSES), **html_options.merge(build_data))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
# Empty Description component
|
|
5
|
+
class EmptyDescriptionComponent < BaseComponent
|
|
6
|
+
BASE_CLASSES = "text-sm text-muted-foreground max-w-sm"
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
content_tag(:p, content, class: merge_classes(BASE_CLASSES), **html_options.merge(build_data))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|