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,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/base"
|
|
5
|
+
|
|
6
|
+
module Shadcn
|
|
7
|
+
module Generators
|
|
8
|
+
# Generator for installing shadcn-rails in a Rails application
|
|
9
|
+
# Usage: rails generate shadcn:install
|
|
10
|
+
class InstallGenerator < Rails::Generators::Base
|
|
11
|
+
source_root File.expand_path("templates", __dir__)
|
|
12
|
+
|
|
13
|
+
class_option :theme, type: :string, default: "neutral",
|
|
14
|
+
desc: "Base color theme (neutral, slate, stone, zinc, gray)"
|
|
15
|
+
class_option :css_variables, type: :boolean, default: true,
|
|
16
|
+
desc: "Use CSS variables for theming"
|
|
17
|
+
class_option :dark_mode, type: :string, default: "class",
|
|
18
|
+
desc: "Dark mode strategy (class, media, selector)"
|
|
19
|
+
class_option :skip_tailwind, type: :boolean, default: false,
|
|
20
|
+
desc: "Skip Tailwind CSS configuration"
|
|
21
|
+
|
|
22
|
+
desc "Installs shadcn-rails and configures your application"
|
|
23
|
+
|
|
24
|
+
def create_initializer
|
|
25
|
+
template "initializer.rb.tt", "config/initializers/shadcn.rb"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def create_config_file
|
|
29
|
+
template "shadcn.yml.tt", "config/shadcn.yml"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def add_stylesheet
|
|
33
|
+
return if options[:skip_tailwind]
|
|
34
|
+
|
|
35
|
+
if File.exist?("app/assets/stylesheets/application.tailwind.css")
|
|
36
|
+
inject_into_file "app/assets/stylesheets/application.tailwind.css", before: "@tailwind base;" do
|
|
37
|
+
"/* shadcn-rails styles */\n@import \"shadcn/base\";\n@import \"shadcn/components\";\n\n"
|
|
38
|
+
end
|
|
39
|
+
elsif File.exist?("app/assets/stylesheets/application.css")
|
|
40
|
+
append_to_file "app/assets/stylesheets/application.css" do
|
|
41
|
+
"\n/*\n *= require shadcn/base\n *= require shadcn/components\n */\n"
|
|
42
|
+
end
|
|
43
|
+
else
|
|
44
|
+
say "Could not find application stylesheet. Please manually import shadcn/base.css and shadcn/components.css", :yellow
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def configure_tailwind
|
|
49
|
+
return if options[:skip_tailwind]
|
|
50
|
+
return unless File.exist?("tailwind.config.js")
|
|
51
|
+
|
|
52
|
+
inject_into_file "tailwind.config.js", after: "content: [" do
|
|
53
|
+
"\n './app/components/**/*.{rb,html,erb}',\n './app/views/**/*.{html,erb}',"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
say "Updated tailwind.config.js to include component paths", :green
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def setup_stimulus_controllers
|
|
60
|
+
if importmap?
|
|
61
|
+
setup_importmap
|
|
62
|
+
elsif using_esbuild? || using_webpack?
|
|
63
|
+
setup_bundler
|
|
64
|
+
else
|
|
65
|
+
say "Could not detect JavaScript bundler. Please manually configure Stimulus controllers.", :yellow
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def display_post_install_message
|
|
70
|
+
say ""
|
|
71
|
+
say "=" * 60, :green
|
|
72
|
+
say " shadcn-rails has been installed!", :green
|
|
73
|
+
say "=" * 60, :green
|
|
74
|
+
say ""
|
|
75
|
+
say "Next steps:", :yellow
|
|
76
|
+
say " 1. Ensure Tailwind CSS is configured with the shadcn theme"
|
|
77
|
+
say " 2. Import the Stimulus controllers in your application"
|
|
78
|
+
say " 3. Start using components in your views:"
|
|
79
|
+
say ""
|
|
80
|
+
say " <%= render Shadcn::ButtonComponent.new(variant: :primary) do %>"
|
|
81
|
+
say " Click me"
|
|
82
|
+
say " <% end %>"
|
|
83
|
+
say ""
|
|
84
|
+
say "For more information, visit: https://github.com/iheanyi/shadcn-rails"
|
|
85
|
+
say ""
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def importmap?
|
|
91
|
+
File.exist?("config/importmap.rb")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def using_esbuild?
|
|
95
|
+
File.exist?("esbuild.config.mjs") ||
|
|
96
|
+
(File.exist?("package.json") && File.read("package.json").include?("esbuild"))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def using_webpack?
|
|
100
|
+
File.exist?("webpack.config.js") ||
|
|
101
|
+
(File.exist?("package.json") && File.read("package.json").include?("webpack"))
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def setup_importmap
|
|
105
|
+
append_to_file "config/importmap.rb" do
|
|
106
|
+
<<~RUBY
|
|
107
|
+
|
|
108
|
+
# shadcn-rails Stimulus controllers
|
|
109
|
+
pin "shadcn", to: "shadcn/index.js"
|
|
110
|
+
RUBY
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Update application.js to register controllers
|
|
114
|
+
if File.exist?("app/javascript/controllers/application.js")
|
|
115
|
+
append_to_file "app/javascript/controllers/application.js" do
|
|
116
|
+
<<~JS
|
|
117
|
+
|
|
118
|
+
// Import and register shadcn-rails controllers
|
|
119
|
+
import { registerShadcnControllers } from "shadcn"
|
|
120
|
+
registerShadcnControllers(application)
|
|
121
|
+
JS
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
say "Configured importmap for shadcn-rails", :green
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def setup_bundler
|
|
129
|
+
# Add to package.json dependencies
|
|
130
|
+
if File.exist?("package.json")
|
|
131
|
+
say "Please add the following to your JavaScript entry point:", :yellow
|
|
132
|
+
say ""
|
|
133
|
+
say " import { registerShadcnControllers } from 'shadcn-rails'"
|
|
134
|
+
say " registerShadcnControllers(application)"
|
|
135
|
+
say ""
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# shadcn-rails configuration
|
|
4
|
+
Shadcn::Rails.configure do |config|
|
|
5
|
+
# Style preset (currently only "default" is supported)
|
|
6
|
+
config.style = "default"
|
|
7
|
+
|
|
8
|
+
# Base color theme: neutral, stone, zinc, gray, slate
|
|
9
|
+
config.base_color = "<%= options[:theme] %>"
|
|
10
|
+
|
|
11
|
+
# Whether to use CSS variables for theming
|
|
12
|
+
config.css_variables = <%= options[:css_variables] %>
|
|
13
|
+
|
|
14
|
+
# Prefix for Tailwind classes (e.g., "tw-")
|
|
15
|
+
# config.tailwind_prefix = ""
|
|
16
|
+
|
|
17
|
+
# Default border radius for components
|
|
18
|
+
config.radius = "0.5rem"
|
|
19
|
+
|
|
20
|
+
# Dark mode strategy: :class, :media, or :selector
|
|
21
|
+
config.dark_mode = :<%= options[:dark_mode] %>
|
|
22
|
+
|
|
23
|
+
# Icon library to use: :lucide (default)
|
|
24
|
+
# config.icon_library = :lucide
|
|
25
|
+
|
|
26
|
+
# Register custom component aliases
|
|
27
|
+
# config.alias_component :my_button, MyCustomButtonComponent
|
|
28
|
+
|
|
29
|
+
# Register custom themes
|
|
30
|
+
# config.register_theme :corporate, {
|
|
31
|
+
# primary: "210 100% 50%",
|
|
32
|
+
# primary_foreground: "0 0% 100%",
|
|
33
|
+
# ...
|
|
34
|
+
# }
|
|
35
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# shadcn-rails configuration file
|
|
2
|
+
# This file mirrors the components.json structure from shadcn/ui
|
|
3
|
+
|
|
4
|
+
# Style preset (currently only "default" is supported)
|
|
5
|
+
style: "default"
|
|
6
|
+
|
|
7
|
+
# Tailwind CSS configuration
|
|
8
|
+
tailwind:
|
|
9
|
+
# Path to your CSS file (for Tailwind CSS v4, leave config blank)
|
|
10
|
+
css: "app/assets/stylesheets/application.tailwind.css"
|
|
11
|
+
|
|
12
|
+
# Base color theme: neutral, stone, zinc, gray, slate
|
|
13
|
+
base_color: "<%= options[:theme] %>"
|
|
14
|
+
|
|
15
|
+
# Use CSS variables for theming
|
|
16
|
+
css_variables: <%= options[:css_variables] %>
|
|
17
|
+
|
|
18
|
+
# Prefix for Tailwind utility classes (e.g., "tw-")
|
|
19
|
+
prefix: ""
|
|
20
|
+
|
|
21
|
+
# Dark mode configuration
|
|
22
|
+
dark_mode: "<%= options[:dark_mode] %>"
|
|
23
|
+
|
|
24
|
+
# Component aliases for path mapping
|
|
25
|
+
aliases:
|
|
26
|
+
components: "app/components"
|
|
27
|
+
ui: "app/components/shadcn"
|
|
28
|
+
lib: "lib"
|
|
29
|
+
hooks: "app/javascript/hooks"
|
|
30
|
+
|
|
31
|
+
# Custom themes (optional)
|
|
32
|
+
# themes:
|
|
33
|
+
# corporate:
|
|
34
|
+
# primary: "210 100% 50%"
|
|
35
|
+
# primary_foreground: "0 0% 100%"
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/base"
|
|
5
|
+
|
|
6
|
+
module Shadcn
|
|
7
|
+
module Generators
|
|
8
|
+
# Generator for switching or customizing themes
|
|
9
|
+
# Usage: rails generate shadcn:theme slate
|
|
10
|
+
class ThemeGenerator < Rails::Generators::Base
|
|
11
|
+
source_root File.expand_path("templates", __dir__)
|
|
12
|
+
|
|
13
|
+
argument :theme_name, type: :string, default: "neutral",
|
|
14
|
+
banner: "theme_name"
|
|
15
|
+
|
|
16
|
+
class_option :list, type: :boolean, default: false,
|
|
17
|
+
desc: "List all available themes"
|
|
18
|
+
|
|
19
|
+
desc "Changes the shadcn-rails theme or creates a custom theme"
|
|
20
|
+
|
|
21
|
+
AVAILABLE_THEMES = %w[neutral slate stone zinc gray].freeze
|
|
22
|
+
|
|
23
|
+
def validate_theme
|
|
24
|
+
if options[:list]
|
|
25
|
+
display_available_themes
|
|
26
|
+
exit 0
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
unless AVAILABLE_THEMES.include?(theme_name)
|
|
30
|
+
say "Error: Unknown theme '#{theme_name}'", :red
|
|
31
|
+
display_available_themes
|
|
32
|
+
exit 1
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def update_initializer
|
|
37
|
+
initializer_path = "config/initializers/shadcn.rb"
|
|
38
|
+
|
|
39
|
+
if File.exist?(initializer_path)
|
|
40
|
+
gsub_file initializer_path,
|
|
41
|
+
/config\.base_color = ["']?\w+["']?/,
|
|
42
|
+
"config.base_color = \"#{theme_name}\""
|
|
43
|
+
say "Updated initializer to use '#{theme_name}' theme", :green
|
|
44
|
+
else
|
|
45
|
+
say "Initializer not found. Run 'rails generate shadcn:install' first.", :yellow
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def update_config_file
|
|
50
|
+
config_path = "config/shadcn.yml"
|
|
51
|
+
|
|
52
|
+
if File.exist?(config_path)
|
|
53
|
+
gsub_file config_path,
|
|
54
|
+
/base_color: \w+/,
|
|
55
|
+
"base_color: #{theme_name}"
|
|
56
|
+
say "Updated shadcn.yml to use '#{theme_name}' theme", :green
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def update_stylesheet
|
|
61
|
+
# Check for theme import in stylesheet
|
|
62
|
+
stylesheet_path = "app/assets/stylesheets/application.tailwind.css"
|
|
63
|
+
|
|
64
|
+
if File.exist?(stylesheet_path)
|
|
65
|
+
content = File.read(stylesheet_path)
|
|
66
|
+
|
|
67
|
+
# Remove existing theme import
|
|
68
|
+
AVAILABLE_THEMES.each do |theme|
|
|
69
|
+
next if theme == "neutral" # neutral uses base.css
|
|
70
|
+
gsub_file stylesheet_path, /@import ["']shadcn\/themes\/#{theme}["'];\n?/, ""
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Add new theme import if not neutral
|
|
74
|
+
unless theme_name == "neutral"
|
|
75
|
+
inject_into_file stylesheet_path, after: '@import "shadcn/base";' do
|
|
76
|
+
"\n@import \"shadcn/themes/#{theme_name}\";"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
say "Updated stylesheet with '#{theme_name}' theme", :green
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def display_completion_message
|
|
85
|
+
say ""
|
|
86
|
+
say "Theme changed to '#{theme_name}'!", :green
|
|
87
|
+
say ""
|
|
88
|
+
say "The following colors are now active:", :yellow
|
|
89
|
+
display_theme_preview(theme_name)
|
|
90
|
+
say ""
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def display_available_themes
|
|
96
|
+
say ""
|
|
97
|
+
say "Available themes:", :green
|
|
98
|
+
say ""
|
|
99
|
+
AVAILABLE_THEMES.each do |theme|
|
|
100
|
+
say " - #{theme}"
|
|
101
|
+
end
|
|
102
|
+
say ""
|
|
103
|
+
say "Usage: rails generate shadcn:theme slate"
|
|
104
|
+
say ""
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def display_theme_preview(theme)
|
|
108
|
+
case theme
|
|
109
|
+
when "neutral"
|
|
110
|
+
say " Primary: Pure black/white"
|
|
111
|
+
say " Style: Clean, minimal"
|
|
112
|
+
when "slate"
|
|
113
|
+
say " Primary: Cool blue-gray"
|
|
114
|
+
say " Style: Professional, corporate"
|
|
115
|
+
when "stone"
|
|
116
|
+
say " Primary: Warm gray-brown"
|
|
117
|
+
say " Style: Earthy, natural"
|
|
118
|
+
when "zinc"
|
|
119
|
+
say " Primary: Cool gray"
|
|
120
|
+
say " Style: Modern, sleek"
|
|
121
|
+
when "gray"
|
|
122
|
+
say " Primary: True gray"
|
|
123
|
+
say " Style: Neutral, balanced"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module Rails
|
|
5
|
+
# Utility class for merging CSS classes intelligently
|
|
6
|
+
# Handles Tailwind CSS class conflicts similar to tailwind-merge
|
|
7
|
+
class ClassMerger
|
|
8
|
+
# Class groups that conflict with each other
|
|
9
|
+
# Later classes in the same group override earlier ones
|
|
10
|
+
CLASS_GROUPS = {
|
|
11
|
+
# Display
|
|
12
|
+
display: %w[block inline-block inline flex inline-flex grid inline-grid hidden],
|
|
13
|
+
|
|
14
|
+
# Position
|
|
15
|
+
position: %w[static fixed absolute relative sticky],
|
|
16
|
+
|
|
17
|
+
# Overflow
|
|
18
|
+
overflow: %w[overflow-auto overflow-hidden overflow-visible overflow-scroll],
|
|
19
|
+
overflow_x: %w[overflow-x-auto overflow-x-hidden overflow-x-visible overflow-x-scroll],
|
|
20
|
+
overflow_y: %w[overflow-y-auto overflow-y-hidden overflow-y-visible overflow-y-scroll],
|
|
21
|
+
|
|
22
|
+
# Flex direction
|
|
23
|
+
flex_direction: %w[flex-row flex-row-reverse flex-col flex-col-reverse],
|
|
24
|
+
|
|
25
|
+
# Flex wrap
|
|
26
|
+
flex_wrap: %w[flex-wrap flex-wrap-reverse flex-nowrap],
|
|
27
|
+
|
|
28
|
+
# Justify content
|
|
29
|
+
justify: %w[justify-start justify-end justify-center justify-between justify-around justify-evenly],
|
|
30
|
+
|
|
31
|
+
# Align items
|
|
32
|
+
items: %w[items-start items-end items-center items-baseline items-stretch],
|
|
33
|
+
|
|
34
|
+
# Align content
|
|
35
|
+
content: %w[content-start content-end content-center content-between content-around content-evenly],
|
|
36
|
+
|
|
37
|
+
# Align self
|
|
38
|
+
self: %w[self-auto self-start self-end self-center self-stretch],
|
|
39
|
+
|
|
40
|
+
# Font size
|
|
41
|
+
font_size: %w[text-xs text-sm text-base text-lg text-xl text-2xl text-3xl text-4xl text-5xl text-6xl text-7xl text-8xl text-9xl],
|
|
42
|
+
|
|
43
|
+
# Font weight
|
|
44
|
+
font_weight: %w[font-thin font-extralight font-light font-normal font-medium font-semibold font-bold font-extrabold font-black],
|
|
45
|
+
|
|
46
|
+
# Text align
|
|
47
|
+
text_align: %w[text-left text-center text-right text-justify],
|
|
48
|
+
|
|
49
|
+
# Whitespace
|
|
50
|
+
whitespace: %w[whitespace-normal whitespace-nowrap whitespace-pre whitespace-pre-line whitespace-pre-wrap],
|
|
51
|
+
|
|
52
|
+
# Text decoration
|
|
53
|
+
text_decoration: %w[underline overline line-through no-underline],
|
|
54
|
+
|
|
55
|
+
# Border style
|
|
56
|
+
border_style: %w[border-solid border-dashed border-dotted border-double border-none],
|
|
57
|
+
|
|
58
|
+
# Cursor
|
|
59
|
+
cursor: %w[cursor-auto cursor-default cursor-pointer cursor-wait cursor-text cursor-move cursor-not-allowed]
|
|
60
|
+
}.freeze
|
|
61
|
+
|
|
62
|
+
# Regex patterns for conflicting classes
|
|
63
|
+
CONFLICT_PATTERNS = {
|
|
64
|
+
# Spacing (margin, padding)
|
|
65
|
+
/^m-/ => :margin,
|
|
66
|
+
/^mx-/ => :margin_x,
|
|
67
|
+
/^my-/ => :margin_y,
|
|
68
|
+
/^mt-/ => :margin_top,
|
|
69
|
+
/^mr-/ => :margin_right,
|
|
70
|
+
/^mb-/ => :margin_bottom,
|
|
71
|
+
/^ml-/ => :margin_left,
|
|
72
|
+
/^p-/ => :padding,
|
|
73
|
+
/^px-/ => :padding_x,
|
|
74
|
+
/^py-/ => :padding_y,
|
|
75
|
+
/^pt-/ => :padding_top,
|
|
76
|
+
/^pr-/ => :padding_right,
|
|
77
|
+
/^pb-/ => :padding_bottom,
|
|
78
|
+
/^pl-/ => :padding_left,
|
|
79
|
+
|
|
80
|
+
# Sizing
|
|
81
|
+
/^w-/ => :width,
|
|
82
|
+
/^min-w-/ => :min_width,
|
|
83
|
+
/^max-w-/ => :max_width,
|
|
84
|
+
/^h-/ => :height,
|
|
85
|
+
/^min-h-/ => :min_height,
|
|
86
|
+
/^max-h-/ => :max_height,
|
|
87
|
+
/^size-/ => :size,
|
|
88
|
+
|
|
89
|
+
# Colors
|
|
90
|
+
/^bg-/ => :background,
|
|
91
|
+
/^text-(?!left|center|right|justify|xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)/ => :text_color,
|
|
92
|
+
/^border-(?!solid|dashed|dotted|double|none|[0-9])/ => :border_color,
|
|
93
|
+
/^ring-(?!offset)/ => :ring_color,
|
|
94
|
+
/^ring-offset-(?!\d)/ => :ring_offset_color,
|
|
95
|
+
|
|
96
|
+
# Border radius
|
|
97
|
+
/^rounded(?:-|$)/ => :border_radius,
|
|
98
|
+
/^rounded-t(?:-|$)/ => :border_radius_top,
|
|
99
|
+
/^rounded-r(?:-|$)/ => :border_radius_right,
|
|
100
|
+
/^rounded-b(?:-|$)/ => :border_radius_bottom,
|
|
101
|
+
/^rounded-l(?:-|$)/ => :border_radius_left,
|
|
102
|
+
/^rounded-tl(?:-|$)/ => :border_radius_top_left,
|
|
103
|
+
/^rounded-tr(?:-|$)/ => :border_radius_top_right,
|
|
104
|
+
/^rounded-bl(?:-|$)/ => :border_radius_bottom_left,
|
|
105
|
+
/^rounded-br(?:-|$)/ => :border_radius_bottom_right,
|
|
106
|
+
|
|
107
|
+
# Border width
|
|
108
|
+
/^border(?:-[0-9]|$)/ => :border_width,
|
|
109
|
+
/^border-t(?:-[0-9]|$)/ => :border_width_top,
|
|
110
|
+
/^border-r(?:-[0-9]|$)/ => :border_width_right,
|
|
111
|
+
/^border-b(?:-[0-9]|$)/ => :border_width_bottom,
|
|
112
|
+
/^border-l(?:-[0-9]|$)/ => :border_width_left,
|
|
113
|
+
|
|
114
|
+
# Opacity
|
|
115
|
+
/^opacity-/ => :opacity,
|
|
116
|
+
|
|
117
|
+
# Z-index
|
|
118
|
+
/^z-/ => :z_index,
|
|
119
|
+
|
|
120
|
+
# Gap
|
|
121
|
+
/^gap-/ => :gap,
|
|
122
|
+
/^gap-x-/ => :gap_x,
|
|
123
|
+
/^gap-y-/ => :gap_y,
|
|
124
|
+
|
|
125
|
+
# Grid
|
|
126
|
+
/^grid-cols-/ => :grid_cols,
|
|
127
|
+
/^grid-rows-/ => :grid_rows,
|
|
128
|
+
/^col-span-/ => :col_span,
|
|
129
|
+
/^row-span-/ => :row_span,
|
|
130
|
+
|
|
131
|
+
# Shadow
|
|
132
|
+
/^shadow(?:-|$)/ => :shadow,
|
|
133
|
+
|
|
134
|
+
# Transition
|
|
135
|
+
/^transition(?:-|$)/ => :transition,
|
|
136
|
+
/^duration-/ => :duration,
|
|
137
|
+
/^ease-/ => :ease,
|
|
138
|
+
|
|
139
|
+
# Transform
|
|
140
|
+
/^scale-/ => :scale,
|
|
141
|
+
/^rotate-/ => :rotate,
|
|
142
|
+
/^translate-x-/ => :translate_x,
|
|
143
|
+
/^translate-y-/ => :translate_y
|
|
144
|
+
}.freeze
|
|
145
|
+
|
|
146
|
+
class << self
|
|
147
|
+
# Merge CSS classes, handling conflicts
|
|
148
|
+
# @param args [Array] Classes to merge (strings, hashes, arrays, or nil)
|
|
149
|
+
# @return [String] Merged class string
|
|
150
|
+
def merge(*args)
|
|
151
|
+
classes = flatten_classes(args)
|
|
152
|
+
dedupe_classes(classes).join(" ")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
private
|
|
156
|
+
|
|
157
|
+
# Flatten nested arrays and handle conditional hashes
|
|
158
|
+
def flatten_classes(args)
|
|
159
|
+
args.flat_map do |arg|
|
|
160
|
+
case arg
|
|
161
|
+
when nil, false
|
|
162
|
+
[]
|
|
163
|
+
when String
|
|
164
|
+
arg.split
|
|
165
|
+
when Array
|
|
166
|
+
flatten_classes(arg)
|
|
167
|
+
when Hash
|
|
168
|
+
arg.filter_map { |klass, condition| klass.to_s if condition }
|
|
169
|
+
else
|
|
170
|
+
arg.to_s.split
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Remove duplicate/conflicting classes, keeping last occurrence
|
|
176
|
+
def dedupe_classes(classes)
|
|
177
|
+
class_groups = {}
|
|
178
|
+
result = []
|
|
179
|
+
|
|
180
|
+
classes.each do |klass|
|
|
181
|
+
# Strip responsive/state prefixes for conflict detection
|
|
182
|
+
base_class = strip_prefixes(klass)
|
|
183
|
+
group = find_conflict_group(base_class)
|
|
184
|
+
|
|
185
|
+
if group
|
|
186
|
+
# Get the prefix (like "sm:", "hover:", etc.)
|
|
187
|
+
prefix = klass.sub(base_class, "")
|
|
188
|
+
|
|
189
|
+
# Create a unique key combining prefix and group
|
|
190
|
+
key = "#{prefix}:#{group}"
|
|
191
|
+
|
|
192
|
+
# If we've seen this group before, remove the old class
|
|
193
|
+
if class_groups[key]
|
|
194
|
+
result.delete(class_groups[key])
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
class_groups[key] = klass
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
result << klass
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
result.uniq
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Strip responsive and state prefixes
|
|
207
|
+
def strip_prefixes(klass)
|
|
208
|
+
klass.gsub(/^(?:sm:|md:|lg:|xl:|2xl:|hover:|focus:|active:|disabled:|dark:|group-hover:|peer-\w+:)+/, "")
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Find the conflict group for a class
|
|
212
|
+
def find_conflict_group(klass)
|
|
213
|
+
# Check static groups first
|
|
214
|
+
CLASS_GROUPS.each do |group, classes|
|
|
215
|
+
return group if classes.include?(klass)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Check pattern-based groups
|
|
219
|
+
CONFLICT_PATTERNS.each do |pattern, group|
|
|
220
|
+
return group if klass.match?(pattern)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
nil
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|