From 8606c61f1f95fa9e445e7da9faf8ed9af70b2395 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 20:34:41 -0300 Subject: [PATCH 01/48] Setup sidebar --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 80 +++++++++++++++++++ lib/ruby_ui/sidebar/mobile_sidebar.rb | 18 +++++ .../sidebar/non_collapsible_sidebar.rb | 17 ++++ lib/ruby_ui/sidebar/sidebar.rb | 61 ++++++++++++++ lib/ruby_ui/sidebar/sidebar_content.rb | 20 +++++ 5 files changed, 196 insertions(+) create mode 100644 lib/ruby_ui/sidebar/collapsiable_sidebar.rb create mode 100644 lib/ruby_ui/sidebar/mobile_sidebar.rb create mode 100644 lib/ruby_ui/sidebar/non_collapsible_sidebar.rb create mode 100644 lib/ruby_ui/sidebar/sidebar.rb create mode 100644 lib/ruby_ui/sidebar/sidebar_content.rb diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb new file mode 100644 index 00000000..b65ce1f0 --- /dev/null +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +module RubyUI + class CollapsiableSidebar < Base + def initialize(side: :left, variant: :sidebar, **attrs) + @side = side + @variant = variant + super(**attrs) + end + + def view_template(&) + div(**attrs) do + div(**gap_element_attrs) + div(**content_wrapper_attrs) do + div(**content_attrs, &) + end + end + end + + private + + def default_attrs + { + class: "peer hidden text-sidebar-foreground md:block" + } + end + + def gap_element_attrs + { + class: [ + "relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear", + "group-data-[collapsible=offcanvas]:w-0", + "group-data-[side=right]:rotate-180", + variant_classes + ] + } + end + + def content_wrapper_attrs + { + class: [ + "absolute inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex", + content_wrapper_side_classes, + content_wrapper_variant_classes, + ] + } + end + + def content_attrs + { + class: "flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow", + data: { + sidebar: "sidebar" + } + } + end + + def variant_classes + if %i[floating inset].include?(@variant) + "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" + else + "group-data-[collapsible=icon]:w-[--sidebar-width-icon]" + end + end + + def content_wrapper_side_classes + return "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" if @side == :left + + "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]" + end + + def content_wrapper_variant_classes + if %i[floating inset].include?(@variant) + "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" + else + "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l" + end + end + end +end diff --git a/lib/ruby_ui/sidebar/mobile_sidebar.rb b/lib/ruby_ui/sidebar/mobile_sidebar.rb new file mode 100644 index 00000000..0995424a --- /dev/null +++ b/lib/ruby_ui/sidebar/mobile_sidebar.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module RubyUI + class MobileSidebar < Base + def view_template(&) + div(**attrs) do + "teste" + end + end + + private + + def default_attrs + { + } + end + end +end diff --git a/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb b/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb new file mode 100644 index 00000000..6d08e3f4 --- /dev/null +++ b/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module RubyUI + class NonCollpapsibleSidebar < Base + def view_template(&) + div(**attrs, &) + end + + private + + def default_attrs + { + class: "flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground" + } + end + end +end diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb new file mode 100644 index 00000000..423ff0a2 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +# "--sidebar-width": SIDEBAR_WIDTH, +# "--sidebar-width-icon": SIDEBAR_WIDTH_ICON, + +# TODO: Add keyboard events +# TODO: Open only mobile or normal sidebar +# TODO: state => expanded, collapsed +# TODO: cache + +# const MOBILE_BREAKPOINT = 768 + +module RubyUI + class Sidebar < Base + SIDEBAR_WIDTH = "16rem" + SIDEBAR_WIDTH_ICON = "3rem" + + SIDES = %i[ left right ].freeze + VARIANTS = %i[ sidebar floating inset ].freeze + COLLAPSIBLES = %i[ offcanvas icon none ].freeze + + + def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, mobile: false, **attrs) + raise ArgumentError, "Invalid side: #{side}. Must be one of #{SIDES}." unless SIDES.include?(side) + raise ArgumentError, "Invalid variant: #{variant}. Must be one of #{VARIANTS}." unless VARIANTS.include?(variant) + raise ArgumentError, "Invalid collapsible: #{collapsible}. Must be one of #{COLLAPSIBLES}." unless COLLAPSIBLES.include?(collapsible) + + @side = side + @variant = variant + @collapsible = collapsible + @mobile = mobile + super(**attrs) + end + + def view_template(&) + div(**attrs) do + if @collapsible == :none + NonCollapsiableSidebar(&) + else + MobileSidebar(&) + CollapsiableSidebar(&) + end + end + end + + private + + def default_attrs + { + class: "group flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar", + style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", + data: { + state: "expanded", + collapsible: @collapsible, + variant: @variant, + side: @side + } + } + end + end +end diff --git a/lib/ruby_ui/sidebar/sidebar_content.rb b/lib/ruby_ui/sidebar/sidebar_content.rb new file mode 100644 index 00000000..0874ce71 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_content.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarContent < Base + def view_template(&) + div(**attrs, &) + end + + private + + def default_attrs + { + class: "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden", + data: { + sidebar: "content" + } + } + end + end +end From 813366fdbb141f149e9dc3f87f5b9cecf3c9cc58 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 20:35:34 -0300 Subject: [PATCH 02/48] Add the sidebar group component --- lib/ruby_ui/sidebar/sidebar_group.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_group.rb diff --git a/lib/ruby_ui/sidebar/sidebar_group.rb b/lib/ruby_ui/sidebar/sidebar_group.rb new file mode 100644 index 00000000..54e71ece --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_group.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarGroup < Base + def view_template(&) + div(**attrs, &) + end + + private + + def default_attrs + { + class: "relative flex w-full min-w-0 flex-col p-2", + data: { + sidebar: "group" + } + } + end + end +end From ecc143a7184ca65e427ee648032e61859d020f3b Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 20:42:43 -0300 Subject: [PATCH 03/48] Add sidebar group label --- lib/ruby_ui/sidebar/sidebar_group_label.rb | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_group_label.rb diff --git a/lib/ruby_ui/sidebar/sidebar_group_label.rb b/lib/ruby_ui/sidebar/sidebar_group_label.rb new file mode 100644 index 00000000..6f6647c7 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_group_label.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarGroupLabel < Base + def view_template(&) + div(**attrs, &) + end + + private + + def default_attrs + { + class: [ + "flex h-8 shrink-0 items-center rounded-md px-2 text-xs", + "font-medium text-sidebar-foreground/70 outline-none", + "ring-sidebar-ring transition-[margin,opacity] duration-200", + "ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", + "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0", + ], + data: { + sidebar: "group-label" + } + } + end + end +end From 54c60753774d2d3ba99d8dcdd316d983f4f27975 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 20:46:30 -0300 Subject: [PATCH 04/48] Add the sidebar group content componeent --- lib/ruby_ui/sidebar/sidebar_group_content.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_group_content.rb diff --git a/lib/ruby_ui/sidebar/sidebar_group_content.rb b/lib/ruby_ui/sidebar/sidebar_group_content.rb new file mode 100644 index 00000000..d4c8de7c --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_group_content.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarGroupContent < Base + def view_template(&) + div(**attrs, &) + end + + private + + def default_attrs + { + class: "w-full text-sm", + data: { + sidebar: "group-content" + } + } + end + end +end From 5c70609697561bcc3e7ac8e8b70added15675f06 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 20:48:54 -0300 Subject: [PATCH 05/48] add sidebar menu --- lib/ruby_ui/sidebar/sidebar_menu.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_menu.rb diff --git a/lib/ruby_ui/sidebar/sidebar_menu.rb b/lib/ruby_ui/sidebar/sidebar_menu.rb new file mode 100644 index 00000000..959db3ef --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_menu.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarMenu < Base + def view_template(&) + ul(**attrs, &) + end + + private + + def default_attrs + { + class: "flex w-full min-w-0 flex-col gap-1", + data: { + sidebar: "menu" + } + } + end + end +end From 505b4a713f7beee2d5324e6c590ba93756cdb720 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 20:53:11 -0300 Subject: [PATCH 06/48] add sidebar menu item --- lib/ruby_ui/sidebar/sidebar_menu_item.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_menu_item.rb diff --git a/lib/ruby_ui/sidebar/sidebar_menu_item.rb b/lib/ruby_ui/sidebar/sidebar_menu_item.rb new file mode 100644 index 00000000..4412c738 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_menu_item.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarMenuItem < Base + def view_template(&) + ul(**attrs, &) + end + + private + + def default_attrs + { + class: "group/menu-item relative", + data: { + sidebar: "menu-item" + } + } + end + end +end From b3d6d6bbfc5a4d8f76ef054d075eb547032153d2 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 21:19:02 -0300 Subject: [PATCH 07/48] rename group --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 18 +++++++++--------- lib/ruby_ui/sidebar/sidebar.rb | 2 +- lib/ruby_ui/sidebar/sidebar_content.rb | 2 +- lib/ruby_ui/sidebar/sidebar_group_label.rb | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb index b65ce1f0..8707b9ff 100644 --- a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -29,8 +29,8 @@ def gap_element_attrs { class: [ "relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear", - "group-data-[collapsible=offcanvas]:w-0", - "group-data-[side=right]:rotate-180", + "group-data-[collapsible=offcanvas]/sidebar-wrapper:w-0", + "group-data-[side=right]/sidebar-wrapper:rotate-180", variant_classes ] } @@ -48,7 +48,7 @@ def content_wrapper_attrs def content_attrs { - class: "flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow", + class: "flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]/sidebar-wrapper:rounded-lg group-data-[variant=floating]/sidebar-wrapper:border group-data-[variant=floating]/sidebar-wrapper:border-sidebar-border group-data-[variant=floating]/sidebar-wrapper:shadow", data: { sidebar: "sidebar" } @@ -57,23 +57,23 @@ def content_attrs def variant_classes if %i[floating inset].include?(@variant) - "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" + "group-data-[collapsible=icon]/sidebar-wrapper:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" else - "group-data-[collapsible=icon]:w-[--sidebar-width-icon]" + "group-data-[collapsible=icon]/sidebar-wrapper:w-[--sidebar-width-icon]" end end def content_wrapper_side_classes - return "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" if @side == :left + return "left-0 group-data-[collapsible=offcanvas]/sidebar-wrapper:left-[calc(var(--sidebar-width)*-1)]" if @side == :left - "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]" + "right-0 group-data-[collapsible=offcanvas]/sidebar-wrapper:right-[calc(var(--sidebar-width)*-1)]" end def content_wrapper_variant_classes if %i[floating inset].include?(@variant) - "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" + "p-2 group-data-[collapsible=icon]/sidebar-wrapper:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" else - "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l" + "group-data-[collapsible=icon]/sidebar-wrapper:w-[--sidebar-width-icon] group-data-[side=left]/sidebar-wrapper:border-r group-data-[side=right]/sidebar-wrapper:border-l" end end end diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index 423ff0a2..3076fa8a 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -47,7 +47,7 @@ def view_template(&) def default_attrs { - class: "group flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar", + class: "group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar", style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", data: { state: "expanded", diff --git a/lib/ruby_ui/sidebar/sidebar_content.rb b/lib/ruby_ui/sidebar/sidebar_content.rb index 0874ce71..215e3707 100644 --- a/lib/ruby_ui/sidebar/sidebar_content.rb +++ b/lib/ruby_ui/sidebar/sidebar_content.rb @@ -10,7 +10,7 @@ def view_template(&) def default_attrs { - class: "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden", + class: "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]/sidebar-wrapper:overflow-hidden", data: { sidebar: "content" } diff --git a/lib/ruby_ui/sidebar/sidebar_group_label.rb b/lib/ruby_ui/sidebar/sidebar_group_label.rb index 6f6647c7..65ed38e4 100644 --- a/lib/ruby_ui/sidebar/sidebar_group_label.rb +++ b/lib/ruby_ui/sidebar/sidebar_group_label.rb @@ -15,7 +15,7 @@ def default_attrs "font-medium text-sidebar-foreground/70 outline-none", "ring-sidebar-ring transition-[margin,opacity] duration-200", "ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", - "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0", + "group-data-[collapsible=icon]/sidebar-wrapper:-mt-8 group-data-[collapsible=icon]/sidebar-wrapper:opacity-0", ], data: { sidebar: "group-label" From 7fff06a8dba863a8bd82a2af0749e66bb0f91903 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 21:54:57 -0300 Subject: [PATCH 08/48] add sidebar submenu item --- lib/ruby_ui/sidebar/mobile_sidebar.rb | 4 +- lib/ruby_ui/sidebar/sidebar_menu_button.rb | 47 ++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 lib/ruby_ui/sidebar/sidebar_menu_button.rb diff --git a/lib/ruby_ui/sidebar/mobile_sidebar.rb b/lib/ruby_ui/sidebar/mobile_sidebar.rb index 0995424a..3bcbd730 100644 --- a/lib/ruby_ui/sidebar/mobile_sidebar.rb +++ b/lib/ruby_ui/sidebar/mobile_sidebar.rb @@ -4,15 +4,13 @@ module RubyUI class MobileSidebar < Base def view_template(&) div(**attrs) do - "teste" end end private def default_attrs - { - } + {} end end end diff --git a/lib/ruby_ui/sidebar/sidebar_menu_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_button.rb new file mode 100644 index 00000000..eb91cf53 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_menu_button.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarMenuButton < Base + VARIANT_CLASSES = { + default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", + outline: + "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]", + }.freeze + + SIZE_CLASSES = { + default: "h-8 text-sm", + sm: "h-7 text-xs", + lg: "h-12 text-sm group-data-[collapsible=icon]/sidebar-wrapper:!p-0", + }.freeze + + def initialize(as: "button", variant: :default, size: :default, active: false, **attrs) + raise ArgumentError, "Invalid variant: #{variant}" unless VARIANT_CLASSES.key?(variant) + raise ArgumentError, "Invalid size: #{size}" unless SIZE_CLASSES.key?(size) + + @active = active + @as = as + super(**attrs) + end + + def view_template(&) + public_send(@as, **attrs, &) + end + + private + + def default_attrs + { + class: [ + "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]/sidebar-wrapper:!size-8 group-data-[collapsible=icon]/sidebar-wrapper:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", + VARIANT_CLASSES[@variant], + SIZE_CLASSES[@size] + ], + data: { + sidebar: "menu-button", + size: @size, + active: @active + } + } + end + end +end From 024391cfe41a2e6be48da3453573b54f03283417 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 23:22:58 -0300 Subject: [PATCH 09/48] add sidebar header --- lib/ruby_ui/sidebar/sidebar_header.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_header.rb diff --git a/lib/ruby_ui/sidebar/sidebar_header.rb b/lib/ruby_ui/sidebar/sidebar_header.rb new file mode 100644 index 00000000..ca2d1601 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_header.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarHeader < Base + def view_template(&) + div(**attrs, &) + end + + private + + def default_attrs + { + class: "flex flex-col gap-2 p-2", + data: { + sidebar: "header" + } + } + end + end +end From 49b93755537ed00a16e1380609782ae57a650501 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 23:23:44 -0300 Subject: [PATCH 10/48] add sidebar footer --- lib/ruby_ui/sidebar/sidebar_footer.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_footer.rb diff --git a/lib/ruby_ui/sidebar/sidebar_footer.rb b/lib/ruby_ui/sidebar/sidebar_footer.rb new file mode 100644 index 00000000..3df63e2b --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_footer.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarFooter < Base + def view_template(&) + div(**attrs, &) + end + + private + + def default_attrs + { + class: "flex flex-col gap-2 p-2", + data: { + sidebar: "footer" + } + } + end + end +end From c6454620f8edc5bb2608b8b75c057caf8e13fbd3 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 23:38:23 -0300 Subject: [PATCH 11/48] add sidebar group action --- lib/ruby_ui/sidebar/sidebar_group_action.rb | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_group_action.rb diff --git a/lib/ruby_ui/sidebar/sidebar_group_action.rb b/lib/ruby_ui/sidebar/sidebar_group_action.rb new file mode 100644 index 00000000..6a8607a0 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_group_action.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarGroupAction < Base + def initialize(as: "button", **attrs) + @as = as + super(**attrs) + end + + def view_template(&) + public_send(@as, **attrs, &) + end + + private + + def default_attrs + { + class: [ + "absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", + "after:absolute after:-inset-2 after:md:hidden", + "group-data-[collapsible=icon]/sidebar-wrapper:hidden", + ], + data: { + sidebar: "group-action" + } + } + end + end +end From 80e7b574061ead37e8e6e9889c4e317bd7f22365 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 20 Mar 2025 23:45:55 -0300 Subject: [PATCH 12/48] add sidebar menu action --- lib/ruby_ui/sidebar/sidebar_menu_action.rb | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_menu_action.rb diff --git a/lib/ruby_ui/sidebar/sidebar_menu_action.rb b/lib/ruby_ui/sidebar/sidebar_menu_action.rb new file mode 100644 index 00000000..291fb195 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_menu_action.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarMenuAction < Base + def initialize(as: "button", show_on_hover: false, **attrs) + @as = as + super(**attrs) + end + + def view_template(&) + public_send(@as, **attrs, &) + end + + private + + def default_attrs + { + class: [ + "absolute right-1 top-1.5 flex aspect-square w-5 items-center", + "justify-center rounded-md p-0 text-sidebar-foreground outline-none", + "ring-sidebar-ring transition-transform hover:bg-sidebar-accent", + "hover:text-sidebar-accent-foreground focus-visible:ring-2", + "peer-hover/menu-button:text-sidebar-accent-foreground", + "[&>svg]:size-4 [&>svg]:shrink-0", + "after:absolute after:-inset-2 after:md:hidden", + "peer-data-[size=sm]/menu-button:top-1", + "peer-data-[size=default]/menu-button:top-1.5", + "peer-data-[size=lg]/menu-button:top-2.5", + "group-data-[collapsible=icon]/sidebar-wrapper:hidden", + show_on_hover_classes + ], + data: { + sidebar: "menu-action" + } + } + end + + def show_on_hover_classes + return unless @show_on_hover + + [ + "group-focus-within/menu-item:opacity-100", + "group-hover/menu-item:opacity-100 data-[state=open]:opacity-100", + "peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0" + ].join(" ") + end + end +end From af7b3de7f1c2e3b132fc8a5dc38f40f6ceb1ba2a Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Fri, 21 Mar 2025 00:00:47 -0300 Subject: [PATCH 13/48] fix state --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 2 +- lib/ruby_ui/sidebar/sidebar.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb index 8707b9ff..6da267b2 100644 --- a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -39,7 +39,7 @@ def gap_element_attrs def content_wrapper_attrs { class: [ - "absolute inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex", + "fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex", content_wrapper_side_classes, content_wrapper_variant_classes, ] diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index 3076fa8a..e5504d9b 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -51,7 +51,7 @@ def default_attrs style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", data: { state: "expanded", - collapsible: @collapsible, + collapsible: @state == "collapsed" ? @collapsible : "expanded", variant: @variant, side: @side } From bd85ef34623ae626f66e73c62ad6e9f0458fce6b Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Fri, 21 Mar 2025 00:10:11 -0300 Subject: [PATCH 14/48] add menu badge component --- lib/ruby_ui/sidebar/sidebar_menu_badge.rb | 30 ++++++++++++++++++++++ lib/ruby_ui/sidebar/sidebar_menu_button.rb | 1 + 2 files changed, 31 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_menu_badge.rb diff --git a/lib/ruby_ui/sidebar/sidebar_menu_badge.rb b/lib/ruby_ui/sidebar/sidebar_menu_badge.rb new file mode 100644 index 00000000..4ac53f97 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_menu_badge.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarMenuBadge < Base + def view_template(&) + div(**attrs, &) + end + + private + + def default_attrs + { + class: [ + "pointer-events-none absolute right-1 flex h-5 min-w-5 select-none", + "items-center justify-center rounded-md px-1 text-xs font-medium", + "tabular-nums text-sidebar-foreground", + "peer-hover/menu-button:text-sidebar-accent-foreground", + "peer-data-[active=true]/menu-button:text-sidebar-accent-foreground", + "peer-data-[size=sm]/menu-button:top-1", + "peer-data-[size=default]/menu-button:top-1.5", + "peer-data-[size=lg]/menu-button:top-2.5", + "group-data-[collapsible=icon]/sidebar-wrapper:hidden", + ], + data: { + sidebar: "menu-badge" + } + } + end + end +end diff --git a/lib/ruby_ui/sidebar/sidebar_menu_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_button.rb index eb91cf53..8830bb8b 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_button.rb @@ -20,6 +20,7 @@ def initialize(as: "button", variant: :default, size: :default, active: false, * @active = active @as = as + @size = size super(**attrs) end From d153edd93a80fbab5a7051beadb24a57b76566a6 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 11:07:23 -0300 Subject: [PATCH 15/48] break long class strings into shorter ones --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb index 6da267b2..50ab496b 100644 --- a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -28,7 +28,8 @@ def default_attrs def gap_element_attrs { class: [ - "relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear", + "relative w-[--sidebar-width] bg-transparent transition-[width]", + "duration-200 ease-linear", "group-data-[collapsible=offcanvas]/sidebar-wrapper:w-0", "group-data-[side=right]/sidebar-wrapper:rotate-180", variant_classes @@ -39,7 +40,8 @@ def gap_element_attrs def content_wrapper_attrs { class: [ - "fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex", + "fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width]", + "transition-[left,right,width] duration-200 ease-linear md:flex", content_wrapper_side_classes, content_wrapper_variant_classes, ] @@ -48,7 +50,13 @@ def content_wrapper_attrs def content_attrs { - class: "flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]/sidebar-wrapper:rounded-lg group-data-[variant=floating]/sidebar-wrapper:border group-data-[variant=floating]/sidebar-wrapper:border-sidebar-border group-data-[variant=floating]/sidebar-wrapper:shadow", + class: [ + "flex h-full w-full flex-col bg-sidebar", + "group-data-[variant=floating]/sidebar-wrapper:rounded-lg", + "group-data-[variant=floating]/sidebar-wrapper:border", + "group-data-[variant=floating]/sidebar-wrapper:border-sidebar-border", + "group-data-[variant=floating]/sidebar-wrapper:shadow" + ], data: { sidebar: "sidebar" } From 3c404fb8db48222c8a95f47dcb806470e90080b8 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 11:14:35 -0300 Subject: [PATCH 16/48] add sidebar menu sub --- lib/ruby_ui/sidebar/sidebar_menu_sub.rb | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_menu_sub.rb diff --git a/lib/ruby_ui/sidebar/sidebar_menu_sub.rb b/lib/ruby_ui/sidebar/sidebar_menu_sub.rb new file mode 100644 index 00000000..9375f887 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_menu_sub.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarMenuSub < Base + def view_template(&) + ul(**attrs, &) + end + + private + + def default_attrs + { + class: [ + "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l", + "border-sidebar-border px-2.5 py-0.5", + "group-data-[collapsible=icon]/sidebar-wrapper:hidden" + ], + data: { + sidebar: "menu-sub" + } + } + end + end +end From f0dffe4a2abcca81e60616f299288bc68f8cd90f Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 11:15:49 -0300 Subject: [PATCH 17/48] add sidebar menu sub item --- lib/ruby_ui/sidebar/sidebar_menu_sub_item.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_menu_sub_item.rb diff --git a/lib/ruby_ui/sidebar/sidebar_menu_sub_item.rb b/lib/ruby_ui/sidebar/sidebar_menu_sub_item.rb new file mode 100644 index 00000000..424ed78e --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_menu_sub_item.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarMenuSubItem < Base + def view_template(&) + li(**attrs, &) + end + end +end From a0e8b4f5f4694f2a98ace84f1bef5317d11fe0e9 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 11:18:33 -0300 Subject: [PATCH 18/48] fix variant instance not being set --- lib/ruby_ui/sidebar/sidebar_menu_button.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ruby_ui/sidebar/sidebar_menu_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_button.rb index 8830bb8b..2697408d 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_button.rb @@ -18,9 +18,10 @@ def initialize(as: "button", variant: :default, size: :default, active: false, * raise ArgumentError, "Invalid variant: #{variant}" unless VARIANT_CLASSES.key?(variant) raise ArgumentError, "Invalid size: #{size}" unless SIZE_CLASSES.key?(size) - @active = active @as = as + @variant = variant @size = size + @active = active super(**attrs) end From 0627ec19249b1ee41c0247d29002f66ec62a4629 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 11:23:45 -0300 Subject: [PATCH 19/48] add sidebar menu sub button --- .../sidebar/sidebar_menu_sub_button.rb | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb diff --git a/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb new file mode 100644 index 00000000..3dd8b1b0 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarMenuSubButton < Base + SIZE_CLASSES = { + sm: "text-xs", + md: "text-sm" + }.freeze + + def initialize(as: "button", size: :md, active: false, **attrs) + raise ArgumentError, "Invalid size: #{size}" unless SIZE_CLASSES.key?(size) + + @as = as + @size = size + @active = active + super(**attrs) + end + + def view_template(&) + public_send(@as, **attrs, &) + end + + private + + def default_attrs + { + class: [ + "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden", + "rounded-md px-2 text-sidebar-foreground outline-none", + "ring-sidebar-ring hover:bg-sidebar-accent", + "hover:text-sidebar-accent-foreground focus-visible:ring-2", + "active:bg-sidebar-accent active:text-sidebar-accent-foreground", + "disabled:pointer-events-none disabled:opacity-50", + "aria-disabled:pointer-events-none aria-disabled:opacity-50", + "[&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", + "[&>svg]:text-sidebar-accent-foreground", + "data-[active=true]:bg-sidebar-accent", + "data-[active=true]:text-sidebar-accent-foreground", + "group-data-[collapsible=icon]/sidebar-wrapper:hidden", + SIZE_CLASSES[@size] + ], + data: { + sidebar: "menu-sub-button", + size: @size, + active: @active + } + } + end + end +end From 525d2639da035fd3afe182c255110c305ca0f544 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 12:17:22 -0300 Subject: [PATCH 20/48] add sidebar menu skeleton --- lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb | 36 ++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb diff --git a/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb b/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb new file mode 100644 index 00000000..07324956 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarMenuSkeleton < Base + def initialize(show_icon: false, **attrs) + @show_icon = show_icon + super(**attrs) + end + + def view_template(&) + div(**attrs) do + Skeleton(class: "size-4 rounded-md", data: {sidebar: "menu-skeleton-icon"}) if @show_icon + Skeleton( + class: "h-4 max-w-[--skeleton-width] flex-1", + data: {sidebar: "menu-skeleton-text"}, + style: {"--skeleton-width" => "#{skeleton_width}%"} + ) + end + end + + private + + def default_attrs + { + class: "flex h-8 items-center gap-2 rounded-md px-2", + data: { + sidebar: "menu-skeleton" + } + } + end + + def skeleton_width + @_skeleton_width ||= rand(40) + 50 + end + end +end From d8aa789c7778c92d408875cf123d872d1378eca3 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 13:30:12 -0300 Subject: [PATCH 21/48] rename sidebar-wrapper group to sidebar --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 24 +++++++++---------- lib/ruby_ui/sidebar/sidebar.rb | 2 +- lib/ruby_ui/sidebar/sidebar_content.rb | 2 +- lib/ruby_ui/sidebar/sidebar_group_action.rb | 2 +- lib/ruby_ui/sidebar/sidebar_group_label.rb | 2 +- lib/ruby_ui/sidebar/sidebar_menu_action.rb | 2 +- lib/ruby_ui/sidebar/sidebar_menu_badge.rb | 2 +- lib/ruby_ui/sidebar/sidebar_menu_button.rb | 4 ++-- lib/ruby_ui/sidebar/sidebar_menu_sub.rb | 2 +- .../sidebar/sidebar_menu_sub_button.rb | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb index 50ab496b..55cbfe15 100644 --- a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -30,8 +30,8 @@ def gap_element_attrs class: [ "relative w-[--sidebar-width] bg-transparent transition-[width]", "duration-200 ease-linear", - "group-data-[collapsible=offcanvas]/sidebar-wrapper:w-0", - "group-data-[side=right]/sidebar-wrapper:rotate-180", + "group-data-[collapsible=offcanvas]/sidebar:w-0", + "group-data-[side=right]/sidebar:rotate-180", variant_classes ] } @@ -52,10 +52,10 @@ def content_attrs { class: [ "flex h-full w-full flex-col bg-sidebar", - "group-data-[variant=floating]/sidebar-wrapper:rounded-lg", - "group-data-[variant=floating]/sidebar-wrapper:border", - "group-data-[variant=floating]/sidebar-wrapper:border-sidebar-border", - "group-data-[variant=floating]/sidebar-wrapper:shadow" + "group-data-[variant=floating]/sidebar:rounded-lg", + "group-data-[variant=floating]/sidebar:border", + "group-data-[variant=floating]/sidebar:border-sidebar-border", + "group-data-[variant=floating]/sidebar:shadow" ], data: { sidebar: "sidebar" @@ -65,23 +65,23 @@ def content_attrs def variant_classes if %i[floating inset].include?(@variant) - "group-data-[collapsible=icon]/sidebar-wrapper:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" + "group-data-[collapsible=icon]/sidebar:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" else - "group-data-[collapsible=icon]/sidebar-wrapper:w-[--sidebar-width-icon]" + "group-data-[collapsible=icon]/sidebar:w-[--sidebar-width-icon]" end end def content_wrapper_side_classes - return "left-0 group-data-[collapsible=offcanvas]/sidebar-wrapper:left-[calc(var(--sidebar-width)*-1)]" if @side == :left + return "left-0 group-data-[collapsible=offcanvas]/sidebar:left-[calc(var(--sidebar-width)*-1)]" if @side == :left - "right-0 group-data-[collapsible=offcanvas]/sidebar-wrapper:right-[calc(var(--sidebar-width)*-1)]" + "right-0 group-data-[collapsible=offcanvas]/sidebar:right-[calc(var(--sidebar-width)*-1)]" end def content_wrapper_variant_classes if %i[floating inset].include?(@variant) - "p-2 group-data-[collapsible=icon]/sidebar-wrapper:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" + "p-2 group-data-[collapsible=icon]/sidebar:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" else - "group-data-[collapsible=icon]/sidebar-wrapper:w-[--sidebar-width-icon] group-data-[side=left]/sidebar-wrapper:border-r group-data-[side=right]/sidebar-wrapper:border-l" + "group-data-[collapsible=icon]/sidebar:w-[--sidebar-width-icon] group-data-[side=left]/sidebar:border-r group-data-[side=right]/sidebar:border-l" end end end diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index e5504d9b..0b0915c7 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -47,7 +47,7 @@ def view_template(&) def default_attrs { - class: "group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar", + class: "group/sidebar has-[[data-variant=inset]]:bg-sidebar", style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", data: { state: "expanded", diff --git a/lib/ruby_ui/sidebar/sidebar_content.rb b/lib/ruby_ui/sidebar/sidebar_content.rb index 215e3707..2aa968d8 100644 --- a/lib/ruby_ui/sidebar/sidebar_content.rb +++ b/lib/ruby_ui/sidebar/sidebar_content.rb @@ -10,7 +10,7 @@ def view_template(&) def default_attrs { - class: "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]/sidebar-wrapper:overflow-hidden", + class: "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]/sidebar:overflow-hidden", data: { sidebar: "content" } diff --git a/lib/ruby_ui/sidebar/sidebar_group_action.rb b/lib/ruby_ui/sidebar/sidebar_group_action.rb index 6a8607a0..e03aa129 100644 --- a/lib/ruby_ui/sidebar/sidebar_group_action.rb +++ b/lib/ruby_ui/sidebar/sidebar_group_action.rb @@ -18,7 +18,7 @@ def default_attrs class: [ "absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", "after:absolute after:-inset-2 after:md:hidden", - "group-data-[collapsible=icon]/sidebar-wrapper:hidden", + "group-data-[collapsible=icon]/sidebar:hidden", ], data: { sidebar: "group-action" diff --git a/lib/ruby_ui/sidebar/sidebar_group_label.rb b/lib/ruby_ui/sidebar/sidebar_group_label.rb index 65ed38e4..0f42f297 100644 --- a/lib/ruby_ui/sidebar/sidebar_group_label.rb +++ b/lib/ruby_ui/sidebar/sidebar_group_label.rb @@ -15,7 +15,7 @@ def default_attrs "font-medium text-sidebar-foreground/70 outline-none", "ring-sidebar-ring transition-[margin,opacity] duration-200", "ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", - "group-data-[collapsible=icon]/sidebar-wrapper:-mt-8 group-data-[collapsible=icon]/sidebar-wrapper:opacity-0", + "group-data-[collapsible=icon]/sidebar:-mt-8 group-data-[collapsible=icon]/sidebar:opacity-0", ], data: { sidebar: "group-label" diff --git a/lib/ruby_ui/sidebar/sidebar_menu_action.rb b/lib/ruby_ui/sidebar/sidebar_menu_action.rb index 291fb195..2f8b0ca2 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_action.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_action.rb @@ -26,7 +26,7 @@ def default_attrs "peer-data-[size=sm]/menu-button:top-1", "peer-data-[size=default]/menu-button:top-1.5", "peer-data-[size=lg]/menu-button:top-2.5", - "group-data-[collapsible=icon]/sidebar-wrapper:hidden", + "group-data-[collapsible=icon]/sidebar:hidden", show_on_hover_classes ], data: { diff --git a/lib/ruby_ui/sidebar/sidebar_menu_badge.rb b/lib/ruby_ui/sidebar/sidebar_menu_badge.rb index 4ac53f97..16f1fa08 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_badge.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_badge.rb @@ -19,7 +19,7 @@ def default_attrs "peer-data-[size=sm]/menu-button:top-1", "peer-data-[size=default]/menu-button:top-1.5", "peer-data-[size=lg]/menu-button:top-2.5", - "group-data-[collapsible=icon]/sidebar-wrapper:hidden", + "group-data-[collapsible=icon]/sidebar:hidden", ], data: { sidebar: "menu-badge" diff --git a/lib/ruby_ui/sidebar/sidebar_menu_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_button.rb index 2697408d..46ebf2fc 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_button.rb @@ -11,7 +11,7 @@ class SidebarMenuButton < Base SIZE_CLASSES = { default: "h-8 text-sm", sm: "h-7 text-xs", - lg: "h-12 text-sm group-data-[collapsible=icon]/sidebar-wrapper:!p-0", + lg: "h-12 text-sm group-data-[collapsible=icon]/sidebar:!p-0", }.freeze def initialize(as: "button", variant: :default, size: :default, active: false, **attrs) @@ -34,7 +34,7 @@ def view_template(&) def default_attrs { class: [ - "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]/sidebar-wrapper:!size-8 group-data-[collapsible=icon]/sidebar-wrapper:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", + "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]/sidebar:!size-8 group-data-[collapsible=icon]/sidebar:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", VARIANT_CLASSES[@variant], SIZE_CLASSES[@size] ], diff --git a/lib/ruby_ui/sidebar/sidebar_menu_sub.rb b/lib/ruby_ui/sidebar/sidebar_menu_sub.rb index 9375f887..ffcdba6a 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_sub.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_sub.rb @@ -13,7 +13,7 @@ def default_attrs class: [ "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l", "border-sidebar-border px-2.5 py-0.5", - "group-data-[collapsible=icon]/sidebar-wrapper:hidden" + "group-data-[collapsible=icon]/sidebar:hidden" ], data: { sidebar: "menu-sub" diff --git a/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb index 3dd8b1b0..0cc9bb45 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb @@ -36,7 +36,7 @@ def default_attrs "[&>svg]:text-sidebar-accent-foreground", "data-[active=true]:bg-sidebar-accent", "data-[active=true]:text-sidebar-accent-foreground", - "group-data-[collapsible=icon]/sidebar-wrapper:hidden", + "group-data-[collapsible=icon]/sidebar:hidden", SIZE_CLASSES[@size] ], data: { From 689e43a0cf0058d6651a2fc655ae1a6c1e236b0d Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 13:31:00 -0300 Subject: [PATCH 22/48] add the sidebar trigger component --- lib/ruby_ui/sidebar/sidebar_trigger.rb | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_trigger.rb diff --git a/lib/ruby_ui/sidebar/sidebar_trigger.rb b/lib/ruby_ui/sidebar/sidebar_trigger.rb new file mode 100644 index 00000000..6b022f4b --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_trigger.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarTrigger < Base + def view_template(&) + Button(variant: :ghost, size: :icon, **attrs) do + panel_left_icon + span(class: "sr-only") { "Toggle Sidebar" } + end + end + + private + + def default_attrs + { + class: "h-7 w-7", + data: { + sidebar: "trigger" + } + } + end + + def panel_left_icon + svg( + xmlns: "http://www.w3.org/2000/svg", + width: 24, + height: 24, + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + strokeWidth: 2, + strokeLinecap: "round", + strokeLinejoin: "round", + class: "lucide lucide-panel-left" + ) do |s| + s.rect(width: 18, height: 18, x: 3, y: 3, rx: 2) + s.path(d: "M9 3v18") + end + end + end +end From 1fb7eb250594cf16778fe14b8758cd7a3e959a0c Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 14:10:54 -0300 Subject: [PATCH 23/48] add the sidebar controller --- lib/ruby_ui/sidebar/sidebar_controller.js | 63 +++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_controller.js diff --git a/lib/ruby_ui/sidebar/sidebar_controller.js b/lib/ruby_ui/sidebar/sidebar_controller.js new file mode 100644 index 00000000..7aecf4e4 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_controller.js @@ -0,0 +1,63 @@ +import { Controller } from "@hotwired/stimulus"; + +const LOCAL_STORAGE_KEY = "sidebar:open"; +const TRIGGER_SELECTOR = "[data-sidebar='trigger']"; +const State = { + EXPANDED: "expanded", + COLLAPSED: "collapsed", +}; + +export default class extends Controller { + static values = { + open: { + type: Boolean, + default: true, + }, + collapsible: { + type: String, + default: "offcanvas", + }, + }; + + connect() { + this.#setupTriggers(); + } + + disconnect() { + this.#removeTriggers(); + } + + toggle() { + this.openValue = !this.openValue; + } + + openValueChanged() { + this.#toggleSidebarDataState(); + this.#persistSidebarState(); + } + + #setupTriggers() { + this.#triggerElements().forEach((trigger) => { + trigger.addEventListener("click", this.toggle.bind(this)); + }); + } + + #removeTriggers() { + this.#triggerElements().forEach((trigger) => { + trigger.removeEventListener("click", this.toggle.bind(this)); + }); + } + + #triggerElements() { + return document.querySelectorAll(TRIGGER_SELECTOR); + } + + #toggleSidebarDataState() { + this.element.dataset.state = this.openValue ? State.EXPANDED : State.COLLAPSED; + this.element.dataset.collapsible = this.openValue ? State.EXPANDED : this.collapsibleValue; + } + + #persistSidebarState() { + localStorage.setItem(LOCAL_STORAGE_KEY, this.openValue); + } +} From b4c3358f40d80398ef7a1f47fc3d4ceb5af1a62a Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 14:11:05 -0300 Subject: [PATCH 24/48] setup the sidebar controller --- lib/ruby_ui/sidebar/sidebar.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index 0b0915c7..e6c92273 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -20,7 +20,7 @@ class Sidebar < Base COLLAPSIBLES = %i[ offcanvas icon none ].freeze - def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, mobile: false, **attrs) + def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, **attrs) raise ArgumentError, "Invalid side: #{side}. Must be one of #{SIDES}." unless SIDES.include?(side) raise ArgumentError, "Invalid variant: #{variant}. Must be one of #{VARIANTS}." unless VARIANTS.include?(variant) raise ArgumentError, "Invalid collapsible: #{collapsible}. Must be one of #{COLLAPSIBLES}." unless COLLAPSIBLES.include?(collapsible) @@ -28,7 +28,6 @@ def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, mobile: @side = side @variant = variant @collapsible = collapsible - @mobile = mobile super(**attrs) end @@ -50,10 +49,12 @@ def default_attrs class: "group/sidebar has-[[data-variant=inset]]:bg-sidebar", style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", data: { + controller: "ruby-ui--sidebar", state: "expanded", - collapsible: @state == "collapsed" ? @collapsible : "expanded", + collapsible: "expanded", variant: @variant, - side: @side + side: @side, + ruby_ui__sidebar_collapsible_value: @collapsible, } } end From 6f17507d121aae34497d277544ad8161d56d02ca Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 14:13:29 -0300 Subject: [PATCH 25/48] add a open flag --- lib/ruby_ui/sidebar/sidebar.rb | 7 ++++--- lib/ruby_ui/sidebar/sidebar_controller.js | 8 ++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index e6c92273..342de2c7 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -20,7 +20,7 @@ class Sidebar < Base COLLAPSIBLES = %i[ offcanvas icon none ].freeze - def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, **attrs) + def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: true, **attrs) raise ArgumentError, "Invalid side: #{side}. Must be one of #{SIDES}." unless SIDES.include?(side) raise ArgumentError, "Invalid variant: #{variant}. Must be one of #{VARIANTS}." unless VARIANTS.include?(variant) raise ArgumentError, "Invalid collapsible: #{collapsible}. Must be one of #{COLLAPSIBLES}." unless COLLAPSIBLES.include?(collapsible) @@ -28,6 +28,7 @@ def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, **attrs) @side = side @variant = variant @collapsible = collapsible + @open = open super(**attrs) end @@ -50,8 +51,8 @@ def default_attrs style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", data: { controller: "ruby-ui--sidebar", - state: "expanded", - collapsible: "expanded", + state: @open ? "expanded" : "collapsed", + collapsible: @open ? "" : @collapsible, variant: @variant, side: @side, ruby_ui__sidebar_collapsible_value: @collapsible, diff --git a/lib/ruby_ui/sidebar/sidebar_controller.js b/lib/ruby_ui/sidebar/sidebar_controller.js index 7aecf4e4..317386fc 100644 --- a/lib/ruby_ui/sidebar/sidebar_controller.js +++ b/lib/ruby_ui/sidebar/sidebar_controller.js @@ -53,8 +53,12 @@ export default class extends Controller { } #toggleSidebarDataState() { - this.element.dataset.state = this.openValue ? State.EXPANDED : State.COLLAPSED; - this.element.dataset.collapsible = this.openValue ? State.EXPANDED : this.collapsibleValue; + this.element.dataset.state = this.openValue + ? State.EXPANDED + : State.COLLAPSED; + this.element.dataset.collapsible = this.openValue + ? this.collapsibleValue + : ""; } #persistSidebarState() { From b3fea80b17147e152cac37efcdc9bee45d99b49e Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 14:16:37 -0300 Subject: [PATCH 26/48] fix collapsible value --- lib/ruby_ui/sidebar/sidebar_controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar_controller.js b/lib/ruby_ui/sidebar/sidebar_controller.js index 317386fc..9702e614 100644 --- a/lib/ruby_ui/sidebar/sidebar_controller.js +++ b/lib/ruby_ui/sidebar/sidebar_controller.js @@ -57,8 +57,8 @@ export default class extends Controller { ? State.EXPANDED : State.COLLAPSED; this.element.dataset.collapsible = this.openValue - ? this.collapsibleValue - : ""; + ? "" + : this.collapsibleValue; } #persistSidebarState() { From ac23fd34bc6d1183a343bee4cba31025fd16ef31 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 14:30:16 -0300 Subject: [PATCH 27/48] persist sidebar state in a cookie --- lib/ruby_ui/sidebar/sidebar.rb | 1 + lib/ruby_ui/sidebar/sidebar_controller.js | 15 +++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index 342de2c7..4039355f 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -55,6 +55,7 @@ def default_attrs collapsible: @open ? "" : @collapsible, variant: @variant, side: @side, + ruby_ui__sidebar_open_value: @open.to_s, ruby_ui__sidebar_collapsible_value: @collapsible, } } diff --git a/lib/ruby_ui/sidebar/sidebar_controller.js b/lib/ruby_ui/sidebar/sidebar_controller.js index 9702e614..7cac96a2 100644 --- a/lib/ruby_ui/sidebar/sidebar_controller.js +++ b/lib/ruby_ui/sidebar/sidebar_controller.js @@ -1,6 +1,7 @@ import { Controller } from "@hotwired/stimulus"; -const LOCAL_STORAGE_KEY = "sidebar:open"; +const SIDEBAR_COOKIE_NAME = "sidebar_state"; +const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; const TRIGGER_SELECTOR = "[data-sidebar='trigger']"; const State = { EXPANDED: "expanded", @@ -53,15 +54,13 @@ export default class extends Controller { } #toggleSidebarDataState() { - this.element.dataset.state = this.openValue - ? State.EXPANDED - : State.COLLAPSED; - this.element.dataset.collapsible = this.openValue - ? "" - : this.collapsibleValue; + const { dataset } = this.element; + + dataset.state = this.openValue ? State.EXPANDED : State.COLLAPSED; + dataset.collapsible = this.openValue ? "" : this.collapsibleValue; } #persistSidebarState() { - localStorage.setItem(LOCAL_STORAGE_KEY, this.openValue); + document.cookie = `${SIDEBAR_COOKIE_NAME}=${this.openValue}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; } } From ce5c958c781b85ce92caac4d5363f7d4cb8df118 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 14:46:11 -0300 Subject: [PATCH 28/48] fix icon attributes --- lib/ruby_ui/sidebar/sidebar_trigger.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar_trigger.rb b/lib/ruby_ui/sidebar/sidebar_trigger.rb index 6b022f4b..dc0813d7 100644 --- a/lib/ruby_ui/sidebar/sidebar_trigger.rb +++ b/lib/ruby_ui/sidebar/sidebar_trigger.rb @@ -13,7 +13,7 @@ def view_template(&) def default_attrs { - class: "h-7 w-7", + class: "h-7 w-7 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", data: { sidebar: "trigger" } @@ -23,17 +23,17 @@ def default_attrs def panel_left_icon svg( xmlns: "http://www.w3.org/2000/svg", - width: 24, - height: 24, - viewBox: "0 0 24 24", - fill: "none", - stroke: "currentColor", - strokeWidth: 2, - strokeLinecap: "round", - strokeLinejoin: "round", + width: "24", + height: "24", + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + stroke_width: "2", + stroke_linecap: "round", + stroke_linejoin: "round", class: "lucide lucide-panel-left" ) do |s| - s.rect(width: 18, height: 18, x: 3, y: 3, rx: 2) + s.rect(width: "18", height: "18", x: "3", y: "3", rx: "2") s.path(d: "M9 3v18") end end From cc6e7d78259f2b020ce7a30fbf0aeb4700c6e13c Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 14:54:18 -0300 Subject: [PATCH 29/48] lint files --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 2 +- lib/ruby_ui/sidebar/sidebar.rb | 9 ++++----- lib/ruby_ui/sidebar/sidebar_group_action.rb | 10 +++++++--- lib/ruby_ui/sidebar/sidebar_group_label.rb | 4 ++-- lib/ruby_ui/sidebar/sidebar_menu_action.rb | 4 ++-- lib/ruby_ui/sidebar/sidebar_menu_badge.rb | 2 +- lib/ruby_ui/sidebar/sidebar_menu_button.rb | 4 ++-- lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb | 4 ++-- lib/ruby_ui/sidebar/sidebar_trigger.rb | 2 +- 9 files changed, 22 insertions(+), 19 deletions(-) diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb index 55cbfe15..a56e4266 100644 --- a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -43,7 +43,7 @@ def content_wrapper_attrs "fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width]", "transition-[left,right,width] duration-200 ease-linear md:flex", content_wrapper_side_classes, - content_wrapper_variant_classes, + content_wrapper_variant_classes ] } end diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index 4039355f..b82b9391 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -15,10 +15,9 @@ class Sidebar < Base SIDEBAR_WIDTH = "16rem" SIDEBAR_WIDTH_ICON = "3rem" - SIDES = %i[ left right ].freeze - VARIANTS = %i[ sidebar floating inset ].freeze - COLLAPSIBLES = %i[ offcanvas icon none ].freeze - + SIDES = %i[left right].freeze + VARIANTS = %i[sidebar floating inset].freeze + COLLAPSIBLES = %i[offcanvas icon none].freeze def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: true, **attrs) raise ArgumentError, "Invalid side: #{side}. Must be one of #{SIDES}." unless SIDES.include?(side) @@ -56,7 +55,7 @@ def default_attrs variant: @variant, side: @side, ruby_ui__sidebar_open_value: @open.to_s, - ruby_ui__sidebar_collapsible_value: @collapsible, + ruby_ui__sidebar_collapsible_value: @collapsible } } end diff --git a/lib/ruby_ui/sidebar/sidebar_group_action.rb b/lib/ruby_ui/sidebar/sidebar_group_action.rb index e03aa129..b698bd78 100644 --- a/lib/ruby_ui/sidebar/sidebar_group_action.rb +++ b/lib/ruby_ui/sidebar/sidebar_group_action.rb @@ -16,9 +16,13 @@ def view_template(&) def default_attrs { class: [ - "absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", - "after:absolute after:-inset-2 after:md:hidden", - "group-data-[collapsible=icon]/sidebar:hidden", + "absolute right-3 top-3.5 flex aspect-square w-5 items-center", + "justify-center rounded-md p-0 text-sidebar-foreground", + "outline-none ring-sidebar-ring transition-transform", + "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", + "focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", + "after:absolute after:-inset-2 after:md:hidden", + "group-data-[collapsible=icon]/sidebar:hidden" ], data: { sidebar: "group-action" diff --git a/lib/ruby_ui/sidebar/sidebar_group_label.rb b/lib/ruby_ui/sidebar/sidebar_group_label.rb index 0f42f297..ff0b9158 100644 --- a/lib/ruby_ui/sidebar/sidebar_group_label.rb +++ b/lib/ruby_ui/sidebar/sidebar_group_label.rb @@ -13,9 +13,9 @@ def default_attrs class: [ "flex h-8 shrink-0 items-center rounded-md px-2 text-xs", "font-medium text-sidebar-foreground/70 outline-none", - "ring-sidebar-ring transition-[margin,opacity] duration-200", + "ring-sidebar-ring transition-[margin,opacity] duration-200", "ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", - "group-data-[collapsible=icon]/sidebar:-mt-8 group-data-[collapsible=icon]/sidebar:opacity-0", + "group-data-[collapsible=icon]/sidebar:-mt-8 group-data-[collapsible=icon]/sidebar:opacity-0" ], data: { sidebar: "group-label" diff --git a/lib/ruby_ui/sidebar/sidebar_menu_action.rb b/lib/ruby_ui/sidebar/sidebar_menu_action.rb index 2f8b0ca2..f89dd7c0 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_action.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_action.rb @@ -18,7 +18,7 @@ def default_attrs class: [ "absolute right-1 top-1.5 flex aspect-square w-5 items-center", "justify-center rounded-md p-0 text-sidebar-foreground outline-none", - "ring-sidebar-ring transition-transform hover:bg-sidebar-accent", + "ring-sidebar-ring transition-transform hover:bg-sidebar-accent", "hover:text-sidebar-accent-foreground focus-visible:ring-2", "peer-hover/menu-button:text-sidebar-accent-foreground", "[&>svg]:size-4 [&>svg]:shrink-0", @@ -36,7 +36,7 @@ def default_attrs end def show_on_hover_classes - return unless @show_on_hover + return unless @show_on_hover [ "group-focus-within/menu-item:opacity-100", diff --git a/lib/ruby_ui/sidebar/sidebar_menu_badge.rb b/lib/ruby_ui/sidebar/sidebar_menu_badge.rb index 16f1fa08..40eaace3 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_badge.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_badge.rb @@ -19,7 +19,7 @@ def default_attrs "peer-data-[size=sm]/menu-button:top-1", "peer-data-[size=default]/menu-button:top-1.5", "peer-data-[size=lg]/menu-button:top-2.5", - "group-data-[collapsible=icon]/sidebar:hidden", + "group-data-[collapsible=icon]/sidebar:hidden" ], data: { sidebar: "menu-badge" diff --git a/lib/ruby_ui/sidebar/sidebar_menu_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_button.rb index 46ebf2fc..b03be6e3 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_button.rb @@ -5,13 +5,13 @@ class SidebarMenuButton < Base VARIANT_CLASSES = { default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", outline: - "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]", + "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]" }.freeze SIZE_CLASSES = { default: "h-8 text-sm", sm: "h-7 text-xs", - lg: "h-12 text-sm group-data-[collapsible=icon]/sidebar:!p-0", + lg: "h-12 text-sm group-data-[collapsible=icon]/sidebar:!p-0" }.freeze def initialize(as: "button", variant: :default, size: :default, active: false, **attrs) diff --git a/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb b/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb index 07324956..5190ddcd 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb @@ -11,7 +11,7 @@ def view_template(&) div(**attrs) do Skeleton(class: "size-4 rounded-md", data: {sidebar: "menu-skeleton-icon"}) if @show_icon Skeleton( - class: "h-4 max-w-[--skeleton-width] flex-1", + class: "h-4 max-w-[--skeleton-width] flex-1", data: {sidebar: "menu-skeleton-text"}, style: {"--skeleton-width" => "#{skeleton_width}%"} ) @@ -30,7 +30,7 @@ def default_attrs end def skeleton_width - @_skeleton_width ||= rand(40) + 50 + @_skeleton_width ||= rand(50..89) end end end diff --git a/lib/ruby_ui/sidebar/sidebar_trigger.rb b/lib/ruby_ui/sidebar/sidebar_trigger.rb index dc0813d7..dcc40271 100644 --- a/lib/ruby_ui/sidebar/sidebar_trigger.rb +++ b/lib/ruby_ui/sidebar/sidebar_trigger.rb @@ -22,7 +22,7 @@ def default_attrs def panel_left_icon svg( - xmlns: "http://www.w3.org/2000/svg", + xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", From cc64a324d03277b62e153c00592d10cc45f0e364 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 17:32:33 -0300 Subject: [PATCH 30/48] rename sidebar trigger data identifier --- lib/ruby_ui/sidebar/sidebar_controller.js | 2 +- lib/ruby_ui/sidebar/sidebar_trigger.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar_controller.js b/lib/ruby_ui/sidebar/sidebar_controller.js index 7cac96a2..a8fab2e5 100644 --- a/lib/ruby_ui/sidebar/sidebar_controller.js +++ b/lib/ruby_ui/sidebar/sidebar_controller.js @@ -2,7 +2,7 @@ import { Controller } from "@hotwired/stimulus"; const SIDEBAR_COOKIE_NAME = "sidebar_state"; const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; -const TRIGGER_SELECTOR = "[data-sidebar='trigger']"; +const TRIGGER_SELECTOR = "[data-sidebar-trigger]"; const State = { EXPANDED: "expanded", COLLAPSED: "collapsed", diff --git a/lib/ruby_ui/sidebar/sidebar_trigger.rb b/lib/ruby_ui/sidebar/sidebar_trigger.rb index dcc40271..f5521a92 100644 --- a/lib/ruby_ui/sidebar/sidebar_trigger.rb +++ b/lib/ruby_ui/sidebar/sidebar_trigger.rb @@ -15,7 +15,8 @@ def default_attrs { class: "h-7 w-7 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", data: { - sidebar: "trigger" + sidebar: "trigger", + sidebar_trigger: true } } end From 01fcede5d902c6307b525d39555ebda5426e350e Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 17:40:15 -0300 Subject: [PATCH 31/48] add the sidebar rail component --- lib/ruby_ui/sidebar/sidebar_rail.rb | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_rail.rb diff --git a/lib/ruby_ui/sidebar/sidebar_rail.rb b/lib/ruby_ui/sidebar/sidebar_rail.rb new file mode 100644 index 00000000..76f23b40 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_rail.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarRail < Base + def view_template(&) + button(**attrs, &) + end + private + + def default_attrs + { + class: [ + "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all", + "ease-linear after:absolute after:inset-y-0 after:left-1/2", + "after:w-[2px] hover:after:bg-sidebar-border", + "group-data-[side=left]/sidebar:-right-4 group-data-[side=right]/sidebar:left-0", + "sm:flex [[data-side=left]_&]:cursor-w-resize", + "[[data-side=right]_&]:cursor-e-resize", + "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize", + "[[data-side=right][data-state=collapsed]_&]:cursor-w-resize", + "group-data-[collapsible=offcanvas]/sidebar:translate-x-0", + "group-data-[collapsible=offcanvas]/sidebar:after:left-full", + "group-data-[collapsible=offcanvas]/sidebar:hover:bg-sidebar", + "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", + "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", + ], + data: { + sidebar: "rail", + sidebar_trigger: true, + tabindex: "-1" + } + } + end + end +end From 2f9b9313459fc010c1f27d59f3fca477cc421e45 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 17:59:26 -0300 Subject: [PATCH 32/48] add the sidebar input component --- lib/ruby_ui/sidebar/sidebar_input.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_input.rb diff --git a/lib/ruby_ui/sidebar/sidebar_input.rb b/lib/ruby_ui/sidebar/sidebar_input.rb new file mode 100644 index 00000000..89bfaed5 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_input.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarInput < Base + def view_template(&) + Input(**attrs, &) + end + + private + + def default_attrs + { + class: "h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring", + data: { + sidebar: "input" + } + } + end + end +end From 7abe27fb7c795842cdf54c70bf1848aea1024a05 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 18:22:43 -0300 Subject: [PATCH 33/48] convert attributes to symbol --- lib/ruby_ui/sidebar/sidebar.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index b82b9391..d4f60ee9 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -20,13 +20,13 @@ class Sidebar < Base COLLAPSIBLES = %i[offcanvas icon none].freeze def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: true, **attrs) - raise ArgumentError, "Invalid side: #{side}. Must be one of #{SIDES}." unless SIDES.include?(side) - raise ArgumentError, "Invalid variant: #{variant}. Must be one of #{VARIANTS}." unless VARIANTS.include?(variant) - raise ArgumentError, "Invalid collapsible: #{collapsible}. Must be one of #{COLLAPSIBLES}." unless COLLAPSIBLES.include?(collapsible) + raise ArgumentError, "Invalid side: #{side}. Must be one of #{SIDES}." unless SIDES.include?(side.to_sym) + raise ArgumentError, "Invalid variant: #{variant}. Must be one of #{VARIANTS}." unless VARIANTS.include?(variant.to_sym) + raise ArgumentError, "Invalid collapsible: #{collapsible}. Must be one of #{COLLAPSIBLES}." unless COLLAPSIBLES.include?(collapsible.to_sym) - @side = side - @variant = variant - @collapsible = collapsible + @side = side.to_sym + @variant = variant.to_sym + @collapsible = collapsible.to_sym @open = open super(**attrs) end @@ -37,7 +37,7 @@ def view_template(&) NonCollapsiableSidebar(&) else MobileSidebar(&) - CollapsiableSidebar(&) + CollapsiableSidebar(side: @side, variant: @variant, &) end end end @@ -46,7 +46,7 @@ def view_template(&) def default_attrs { - class: "group/sidebar has-[[data-variant=inset]]:bg-sidebar", + class: "peer group/sidebar has-[[data-variant=inset]]:bg-sidebar", style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", data: { controller: "ruby-ui--sidebar", From fc0068081fdbed1c6773ed31d67a63ba82c5cda4 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 18:22:49 -0300 Subject: [PATCH 34/48] add sidebar inset component --- lib/ruby_ui/sidebar/sidebar_inset.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_inset.rb diff --git a/lib/ruby_ui/sidebar/sidebar_inset.rb b/lib/ruby_ui/sidebar/sidebar_inset.rb new file mode 100644 index 00000000..e03d3fcf --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_inset.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarInset < Base + def view_template(&) + main(**attrs, &) + end + + private + + def default_attrs + { + class: [ + "relative flex w-full flex-1 flex-col bg-background", + "md:peer-data-[variant=inset]:m-2", + "md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2", + "md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl", + "md:peer-data-[variant=inset]:shadow" + ] + } + end + end +end From 952fcb664c48519182e2c357ce2d6ef5810c5a6c Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 19:21:12 -0300 Subject: [PATCH 35/48] setup the mobile sidebar --- lib/ruby_ui/sidebar/mobile_sidebar.rb | 30 ++++++++++++++++-- lib/ruby_ui/sidebar/sidebar.rb | 5 +-- lib/ruby_ui/sidebar/sidebar_controller.js | 38 +++++++++++++++++------ 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/lib/ruby_ui/sidebar/mobile_sidebar.rb b/lib/ruby_ui/sidebar/mobile_sidebar.rb index 3bcbd730..b6cc3742 100644 --- a/lib/ruby_ui/sidebar/mobile_sidebar.rb +++ b/lib/ruby_ui/sidebar/mobile_sidebar.rb @@ -2,15 +2,41 @@ module RubyUI class MobileSidebar < Base + SIDEBAR_WIDTH_MOBILE = "18rem" + + def initialize(side: :left, **attrs) + @side = side + super(**attrs) + end + def view_template(&) - div(**attrs) do + Sheet(**attrs) do + SheetContent( + side: @side, + class: "w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden", + style: { + "--sidebar-width": SIDEBAR_WIDTH_MOBILE + }, + data: { + sidebar: "sidebar", + mobile: "true" + }, + ) do + SheetHeader(class: "sr-only") do + SheetTitle { "Sidebar" } + SheetDescription { "Displays the mobile sidebar." } + end + div(class: "flex h-full w-full flex-col", &) + end end end private def default_attrs - {} + { + class: "ruby-ui--sidebar-sheet" + } end end end diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index d4f60ee9..9b70c78f 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -36,7 +36,7 @@ def view_template(&) if @collapsible == :none NonCollapsiableSidebar(&) else - MobileSidebar(&) + MobileSidebar(side: @side, &) CollapsiableSidebar(side: @side, variant: @variant, &) end end @@ -55,7 +55,8 @@ def default_attrs variant: @variant, side: @side, ruby_ui__sidebar_open_value: @open.to_s, - ruby_ui__sidebar_collapsible_value: @collapsible + ruby_ui__sidebar_collapsible_value: @collapsible, + ruby_ui__sidebar_ruby_ui__sheet_outlet: ".ruby-ui--sidebar-sheet" } } end diff --git a/lib/ruby_ui/sidebar/sidebar_controller.js b/lib/ruby_ui/sidebar/sidebar_controller.js index a8fab2e5..e368f64e 100644 --- a/lib/ruby_ui/sidebar/sidebar_controller.js +++ b/lib/ruby_ui/sidebar/sidebar_controller.js @@ -7,8 +7,10 @@ const State = { EXPANDED: "expanded", COLLAPSED: "collapsed", }; +const MOBILE_BREAKPOINT = 768; export default class extends Controller { + static outlets = ["ruby-ui--sheet"]; static values = { open: { type: Boolean, @@ -21,39 +23,45 @@ export default class extends Controller { }; connect() { - this.#setupTriggers(); + this.#setupSidebarTriggers(); } disconnect() { - this.#removeTriggers(); + this.#removeSidebarTriggers(); } toggle() { + if (this.#isMobile()) { + this.#openMobileSidebar(); + + return; + } + this.openValue = !this.openValue; } openValueChanged() { - this.#toggleSidebarDataState(); + this.#updateSidebarState(); this.#persistSidebarState(); } - #setupTriggers() { - this.#triggerElements().forEach((trigger) => { + #setupSidebarTriggers() { + this.#siderbarTriggerElements().forEach((trigger) => { trigger.addEventListener("click", this.toggle.bind(this)); }); } - #removeTriggers() { - this.#triggerElements().forEach((trigger) => { + #removeSidebarTriggers() { + this.#siderbarTriggerElements().forEach((trigger) => { trigger.removeEventListener("click", this.toggle.bind(this)); }); } - #triggerElements() { + #siderbarTriggerElements() { return document.querySelectorAll(TRIGGER_SELECTOR); } - #toggleSidebarDataState() { + #updateSidebarState() { const { dataset } = this.element; dataset.state = this.openValue ? State.EXPANDED : State.COLLAPSED; @@ -63,4 +71,16 @@ export default class extends Controller { #persistSidebarState() { document.cookie = `${SIDEBAR_COOKIE_NAME}=${this.openValue}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; } + + #isMobile() { + return window.innerWidth < MOBILE_BREAKPOINT; + } + + #openMobileSidebar() { + if (!this.rubyUiSheetOutlet) { + return; + } + + this.rubyUiSheetOutlet.open(); + } } From 25cab042c3574f66ad9c6f0da31d4ad8a24143b1 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sat, 22 Mar 2025 19:33:15 -0300 Subject: [PATCH 36/48] remove todo comments --- lib/ruby_ui/sidebar/sidebar.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index 9b70c78f..c67a139f 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -1,15 +1,5 @@ # frozen_string_literal: true -# "--sidebar-width": SIDEBAR_WIDTH, -# "--sidebar-width-icon": SIDEBAR_WIDTH_ICON, - -# TODO: Add keyboard events -# TODO: Open only mobile or normal sidebar -# TODO: state => expanded, collapsed -# TODO: cache - -# const MOBILE_BREAKPOINT = 768 - module RubyUI class Sidebar < Base SIDEBAR_WIDTH = "16rem" From dcad2f0d6d024ff4505a08f3e75c825e07ea3816 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sun, 23 Mar 2025 12:34:35 -0300 Subject: [PATCH 37/48] add sidebar wrapper --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 69 ++++++++++++++------- lib/ruby_ui/sidebar/mobile_sidebar.rb | 23 ++++--- lib/ruby_ui/sidebar/sidebar.rb | 31 ++------- lib/ruby_ui/sidebar/sidebar_controller.js | 67 +++++++------------- lib/ruby_ui/sidebar/sidebar_trigger.rb | 32 +++++----- lib/ruby_ui/sidebar/sidebar_wrapper.rb | 19 ++++++ 6 files changed, 122 insertions(+), 119 deletions(-) create mode 100644 lib/ruby_ui/sidebar/sidebar_wrapper.rb diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb index a56e4266..cb77b970 100644 --- a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -2,17 +2,25 @@ module RubyUI class CollapsiableSidebar < Base - def initialize(side: :left, variant: :sidebar, **attrs) + SIDEBAR_WIDTH = '16rem' + SIDEBAR_WIDTH_ICON = '3rem' + + def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: true, **attrs) @side = side @variant = variant + @collapsible = collapsible + @open = open super(**attrs) end def view_template(&) div(**attrs) do - div(**gap_element_attrs) - div(**content_wrapper_attrs) do - div(**content_attrs, &) + MobileSidebar(side: @side, &) + div(**wrapper_attrs) do + div(**gap_element_attrs) + div(**content_wrapper_attrs) do + div(**content_attrs, &) + end end end end @@ -21,17 +29,32 @@ def view_template(&) def default_attrs { - class: "peer hidden text-sidebar-foreground md:block" + class: 'group/sidebar', + style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", + data: { + state: @open ? 'expanded' : 'collapsed', + collapsible: @open ? '' : @collapsible, + variant: @variant, + side: @side, + collapsible_kind: @collapsible, + ruby_ui__sidebar_target: 'sidebar' + } + } + end + + def wrapper_attrs + { + class: 'peer hidden text-sidebar-foreground md:block' } end def gap_element_attrs { class: [ - "relative w-[--sidebar-width] bg-transparent transition-[width]", - "duration-200 ease-linear", - "group-data-[collapsible=offcanvas]/sidebar:w-0", - "group-data-[side=right]/sidebar:rotate-180", + 'relative w-[--sidebar-width] bg-transparent transition-[width]', + 'duration-200 ease-linear', + 'group-data-[collapsible=offcanvas]/sidebar:w-0', + 'group-data-[side=right]/sidebar:rotate-180', variant_classes ] } @@ -40,8 +63,8 @@ def gap_element_attrs def content_wrapper_attrs { class: [ - "fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width]", - "transition-[left,right,width] duration-200 ease-linear md:flex", + 'fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width]', + 'transition-[left,right,width] duration-200 ease-linear md:flex', content_wrapper_side_classes, content_wrapper_variant_classes ] @@ -51,37 +74,37 @@ def content_wrapper_attrs def content_attrs { class: [ - "flex h-full w-full flex-col bg-sidebar", - "group-data-[variant=floating]/sidebar:rounded-lg", - "group-data-[variant=floating]/sidebar:border", - "group-data-[variant=floating]/sidebar:border-sidebar-border", - "group-data-[variant=floating]/sidebar:shadow" + 'flex h-full w-full flex-col bg-sidebar', + 'group-data-[variant=floating]/sidebar:rounded-lg', + 'group-data-[variant=floating]/sidebar:border', + 'group-data-[variant=floating]/sidebar:border-sidebar-border', + 'group-data-[variant=floating]/sidebar:shadow' ], data: { - sidebar: "sidebar" + sidebar: 'sidebar' } } end def variant_classes if %i[floating inset].include?(@variant) - "group-data-[collapsible=icon]/sidebar:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" + 'group-data-[collapsible=icon]/sidebar:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]' else - "group-data-[collapsible=icon]/sidebar:w-[--sidebar-width-icon]" + 'group-data-[collapsible=icon]/sidebar:w-[--sidebar-width-icon]' end end def content_wrapper_side_classes - return "left-0 group-data-[collapsible=offcanvas]/sidebar:left-[calc(var(--sidebar-width)*-1)]" if @side == :left + return 'left-0 group-data-[collapsible=offcanvas]/sidebar:left-[calc(var(--sidebar-width)*-1)]' if @side == :left - "right-0 group-data-[collapsible=offcanvas]/sidebar:right-[calc(var(--sidebar-width)*-1)]" + 'right-0 group-data-[collapsible=offcanvas]/sidebar:right-[calc(var(--sidebar-width)*-1)]' end def content_wrapper_variant_classes if %i[floating inset].include?(@variant) - "p-2 group-data-[collapsible=icon]/sidebar:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" + 'p-2 group-data-[collapsible=icon]/sidebar:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]' else - "group-data-[collapsible=icon]/sidebar:w-[--sidebar-width-icon] group-data-[side=left]/sidebar:border-r group-data-[side=right]/sidebar:border-l" + 'group-data-[collapsible=icon]/sidebar:w-[--sidebar-width-icon] group-data-[side=left]/sidebar:border-r group-data-[side=right]/sidebar:border-l' end end end diff --git a/lib/ruby_ui/sidebar/mobile_sidebar.rb b/lib/ruby_ui/sidebar/mobile_sidebar.rb index b6cc3742..1f5b322e 100644 --- a/lib/ruby_ui/sidebar/mobile_sidebar.rb +++ b/lib/ruby_ui/sidebar/mobile_sidebar.rb @@ -2,7 +2,7 @@ module RubyUI class MobileSidebar < Base - SIDEBAR_WIDTH_MOBILE = "18rem" + SIDEBAR_WIDTH_MOBILE = '18rem' def initialize(side: :left, **attrs) @side = side @@ -13,20 +13,20 @@ def view_template(&) Sheet(**attrs) do SheetContent( side: @side, - class: "w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden", + class: 'w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden', style: { "--sidebar-width": SIDEBAR_WIDTH_MOBILE }, data: { - sidebar: "sidebar", - mobile: "true" - }, + sidebar: 'sidebar', + mobile: 'true' + } ) do - SheetHeader(class: "sr-only") do - SheetTitle { "Sidebar" } - SheetDescription { "Displays the mobile sidebar." } + SheetHeader(class: 'sr-only') do + SheetTitle { 'Sidebar' } + SheetDescription { 'Displays the mobile sidebar.' } end - div(class: "flex h-full w-full flex-col", &) + div(class: 'flex h-full w-full flex-col', &) end end end @@ -35,7 +35,10 @@ def view_template(&) def default_attrs { - class: "ruby-ui--sidebar-sheet" + data: { + ruby_ui__sidebar_target: 'mobileSidebar', + action: 'ruby--ui-sidebar:open->ruby-ui--sheet#open:self' + } } end end diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index c67a139f..235b2dcd 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -2,17 +2,14 @@ module RubyUI class Sidebar < Base - SIDEBAR_WIDTH = "16rem" - SIDEBAR_WIDTH_ICON = "3rem" - SIDES = %i[left right].freeze VARIANTS = %i[sidebar floating inset].freeze COLLAPSIBLES = %i[offcanvas icon none].freeze def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: true, **attrs) - raise ArgumentError, "Invalid side: #{side}. Must be one of #{SIDES}." unless SIDES.include?(side.to_sym) - raise ArgumentError, "Invalid variant: #{variant}. Must be one of #{VARIANTS}." unless VARIANTS.include?(variant.to_sym) - raise ArgumentError, "Invalid collapsible: #{collapsible}. Must be one of #{COLLAPSIBLES}." unless COLLAPSIBLES.include?(collapsible.to_sym) + raise ArgumentError, "Invalid side: #{side}." unless SIDES.include?(side.to_sym) + raise ArgumentError "Invalid variant: #{variant}." unless VARIANTS.include?(variant.to_sym) + raise ArgumentError, "Invalid collapsible: #{collapsible}." unless COLLAPSIBLES.include?(collapsible.to_sym) @side = side.to_sym @variant = variant.to_sym @@ -26,29 +23,9 @@ def view_template(&) if @collapsible == :none NonCollapsiableSidebar(&) else - MobileSidebar(side: @side, &) - CollapsiableSidebar(side: @side, variant: @variant, &) + CollapsiableSidebar(side: @side, variant: @variant, collapsible: @collapsible, open: @open, &) end end end - - private - - def default_attrs - { - class: "peer group/sidebar has-[[data-variant=inset]]:bg-sidebar", - style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", - data: { - controller: "ruby-ui--sidebar", - state: @open ? "expanded" : "collapsed", - collapsible: @open ? "" : @collapsible, - variant: @variant, - side: @side, - ruby_ui__sidebar_open_value: @open.to_s, - ruby_ui__sidebar_collapsible_value: @collapsible, - ruby_ui__sidebar_ruby_ui__sheet_outlet: ".ruby-ui--sidebar-sheet" - } - } - end end end diff --git a/lib/ruby_ui/sidebar/sidebar_controller.js b/lib/ruby_ui/sidebar/sidebar_controller.js index e368f64e..c789438d 100644 --- a/lib/ruby_ui/sidebar/sidebar_controller.js +++ b/lib/ruby_ui/sidebar/sidebar_controller.js @@ -2,7 +2,6 @@ import { Controller } from "@hotwired/stimulus"; const SIDEBAR_COOKIE_NAME = "sidebar_state"; const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; -const TRIGGER_SELECTOR = "[data-sidebar-trigger]"; const State = { EXPANDED: "expanded", COLLAPSED: "collapsed", @@ -10,66 +9,46 @@ const State = { const MOBILE_BREAKPOINT = 768; export default class extends Controller { - static outlets = ["ruby-ui--sheet"]; - static values = { - open: { - type: Boolean, - default: true, - }, - collapsible: { - type: String, - default: "offcanvas", - }, - }; - - connect() { - this.#setupSidebarTriggers(); - } + static targets = ["sidebar", "mobileSidebar"]; + + sidebarTargetConnected() { + const { state, collapsibleKind } = this.sidebarTarget.dataset; - disconnect() { - this.#removeSidebarTriggers(); + this.open = state === State.EXPANDED; + this.collapsibleKind = collapsibleKind; } - toggle() { + toggle(e) { + e.preventDefault(); + if (this.#isMobile()) { this.#openMobileSidebar(); return; } - this.openValue = !this.openValue; + this.open = !this.open; + this.onToggle(); } - openValueChanged() { + onToggle() { this.#updateSidebarState(); this.#persistSidebarState(); } - #setupSidebarTriggers() { - this.#siderbarTriggerElements().forEach((trigger) => { - trigger.addEventListener("click", this.toggle.bind(this)); - }); - } - - #removeSidebarTriggers() { - this.#siderbarTriggerElements().forEach((trigger) => { - trigger.removeEventListener("click", this.toggle.bind(this)); - }); - } - - #siderbarTriggerElements() { - return document.querySelectorAll(TRIGGER_SELECTOR); - } - #updateSidebarState() { - const { dataset } = this.element; + if (!this.hasSidebarTarget) { + return; + } + + const { dataset } = this.sidebarTarget; - dataset.state = this.openValue ? State.EXPANDED : State.COLLAPSED; - dataset.collapsible = this.openValue ? "" : this.collapsibleValue; + dataset.state = this.open ? State.EXPANDED : State.COLLAPSED; + dataset.collapsible = this.open ? "" : this.collapsibleKind; } #persistSidebarState() { - document.cookie = `${SIDEBAR_COOKIE_NAME}=${this.openValue}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; + document.cookie = `${SIDEBAR_COOKIE_NAME}=${this.open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; } #isMobile() { @@ -77,10 +56,12 @@ export default class extends Controller { } #openMobileSidebar() { - if (!this.rubyUiSheetOutlet) { + if (!this.hasMobileSidebarTarget) { return; } - this.rubyUiSheetOutlet.open(); + this.mobileSidebarTarget.dispatchEvent( + new CustomEvent("ruby--ui-sidebar:open"), + ); } } diff --git a/lib/ruby_ui/sidebar/sidebar_trigger.rb b/lib/ruby_ui/sidebar/sidebar_trigger.rb index f5521a92..707c6d8f 100644 --- a/lib/ruby_ui/sidebar/sidebar_trigger.rb +++ b/lib/ruby_ui/sidebar/sidebar_trigger.rb @@ -5,7 +5,7 @@ class SidebarTrigger < Base def view_template(&) Button(variant: :ghost, size: :icon, **attrs) do panel_left_icon - span(class: "sr-only") { "Toggle Sidebar" } + span(class: 'sr-only') { 'Toggle Sidebar' } end end @@ -13,29 +13,29 @@ def view_template(&) def default_attrs { - class: "h-7 w-7 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + class: 'h-7 w-7 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', data: { - sidebar: "trigger", - sidebar_trigger: true + sidebar: 'trigger', + action: 'click->ruby-ui--sidebar#toggle' } } end def panel_left_icon svg( - xmlns: "http://www.w3.org/2000/svg", - width: "24", - height: "24", - viewBox: "0 0 24 24", - fill: "none", - stroke: "currentColor", - stroke_width: "2", - stroke_linecap: "round", - stroke_linejoin: "round", - class: "lucide lucide-panel-left" + xmlns: 'http://www.w3.org/2000/svg', + width: '24', + height: '24', + viewBox: '0 0 24 24', + fill: 'none', + stroke: 'currentColor', + stroke_width: '2', + stroke_linecap: 'round', + stroke_linejoin: 'round', + class: 'lucide lucide-panel-left' ) do |s| - s.rect(width: "18", height: "18", x: "3", y: "3", rx: "2") - s.path(d: "M9 3v18") + s.rect(width: '18', height: '18', x: '3', y: '3', rx: '2') + s.path(d: 'M9 3v18') end end end diff --git a/lib/ruby_ui/sidebar/sidebar_wrapper.rb b/lib/ruby_ui/sidebar/sidebar_wrapper.rb new file mode 100644 index 00000000..3474a947 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_wrapper.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarWrapper < Base + def view_template(&) + div(**attrs, &) + end + private + + def default_attrs + { + class: "group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full", + data: { + controller: "ruby-ui--sidebar" + } + } + end + end +end From c9c5eb9ea455fec695c4dae4883217c009b44309 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sun, 23 Mar 2025 12:45:22 -0300 Subject: [PATCH 38/48] move sidebar to another component --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 44 +++++++------------ lib/ruby_ui/sidebar/sidebar_content.rb | 2 +- lib/ruby_ui/sidebar/sidebar_group_action.rb | 2 +- lib/ruby_ui/sidebar/sidebar_group_label.rb | 2 +- lib/ruby_ui/sidebar/sidebar_menu_action.rb | 2 +- lib/ruby_ui/sidebar/sidebar_menu_badge.rb | 2 +- lib/ruby_ui/sidebar/sidebar_menu_button.rb | 4 +- lib/ruby_ui/sidebar/sidebar_menu_sub.rb | 2 +- .../sidebar/sidebar_menu_sub_button.rb | 2 +- lib/ruby_ui/sidebar/sidebar_rail.rb | 8 ++-- lib/ruby_ui/sidebar/sidebar_wrapper.rb | 9 +++- 11 files changed, 37 insertions(+), 42 deletions(-) diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb index cb77b970..120c8448 100644 --- a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -2,9 +2,6 @@ module RubyUI class CollapsiableSidebar < Base - SIDEBAR_WIDTH = '16rem' - SIDEBAR_WIDTH_ICON = '3rem' - def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: true, **attrs) @side = side @variant = variant @@ -14,9 +11,9 @@ def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: tr end def view_template(&) - div(**attrs) do - MobileSidebar(side: @side, &) - div(**wrapper_attrs) do + div do + MobileSidebar(side: @side, **attrs, &) + div(**mix(sidebar_attrs, attrs)) do div(**gap_element_attrs) div(**content_wrapper_attrs) do div(**content_attrs, &) @@ -27,10 +24,9 @@ def view_template(&) private - def default_attrs + def sidebar_attrs { - class: 'group/sidebar', - style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", + class: 'group peer hidden text-sidebar-foreground md:block', data: { state: @open ? 'expanded' : 'collapsed', collapsible: @open ? '' : @collapsible, @@ -42,19 +38,13 @@ def default_attrs } end - def wrapper_attrs - { - class: 'peer hidden text-sidebar-foreground md:block' - } - end - def gap_element_attrs { class: [ 'relative w-[--sidebar-width] bg-transparent transition-[width]', 'duration-200 ease-linear', - 'group-data-[collapsible=offcanvas]/sidebar:w-0', - 'group-data-[side=right]/sidebar:rotate-180', + 'group-data-[collapsible=offcanvas]:w-0', + 'group-data-[side=right]:rotate-180', variant_classes ] } @@ -75,10 +65,10 @@ def content_attrs { class: [ 'flex h-full w-full flex-col bg-sidebar', - 'group-data-[variant=floating]/sidebar:rounded-lg', - 'group-data-[variant=floating]/sidebar:border', - 'group-data-[variant=floating]/sidebar:border-sidebar-border', - 'group-data-[variant=floating]/sidebar:shadow' + 'group-data-[variant=floating]:rounded-lg', + 'group-data-[variant=floating]:border', + 'group-data-[variant=floating]:border-sidebar-border', + 'group-data-[variant=floating]:shadow' ], data: { sidebar: 'sidebar' @@ -88,23 +78,23 @@ def content_attrs def variant_classes if %i[floating inset].include?(@variant) - 'group-data-[collapsible=icon]/sidebar:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]' + 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]' else - 'group-data-[collapsible=icon]/sidebar:w-[--sidebar-width-icon]' + 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]' end end def content_wrapper_side_classes - return 'left-0 group-data-[collapsible=offcanvas]/sidebar:left-[calc(var(--sidebar-width)*-1)]' if @side == :left + return 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]' if @side == :left - 'right-0 group-data-[collapsible=offcanvas]/sidebar:right-[calc(var(--sidebar-width)*-1)]' + 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]' end def content_wrapper_variant_classes if %i[floating inset].include?(@variant) - 'p-2 group-data-[collapsible=icon]/sidebar:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]' + 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]' else - 'group-data-[collapsible=icon]/sidebar:w-[--sidebar-width-icon] group-data-[side=left]/sidebar:border-r group-data-[side=right]/sidebar:border-l' + 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l' end end end diff --git a/lib/ruby_ui/sidebar/sidebar_content.rb b/lib/ruby_ui/sidebar/sidebar_content.rb index 2aa968d8..0874ce71 100644 --- a/lib/ruby_ui/sidebar/sidebar_content.rb +++ b/lib/ruby_ui/sidebar/sidebar_content.rb @@ -10,7 +10,7 @@ def view_template(&) def default_attrs { - class: "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]/sidebar:overflow-hidden", + class: "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden", data: { sidebar: "content" } diff --git a/lib/ruby_ui/sidebar/sidebar_group_action.rb b/lib/ruby_ui/sidebar/sidebar_group_action.rb index b698bd78..d84b8d3d 100644 --- a/lib/ruby_ui/sidebar/sidebar_group_action.rb +++ b/lib/ruby_ui/sidebar/sidebar_group_action.rb @@ -22,7 +22,7 @@ def default_attrs "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", "focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", "after:absolute after:-inset-2 after:md:hidden", - "group-data-[collapsible=icon]/sidebar:hidden" + "group-data-[collapsible=icon]:hidden" ], data: { sidebar: "group-action" diff --git a/lib/ruby_ui/sidebar/sidebar_group_label.rb b/lib/ruby_ui/sidebar/sidebar_group_label.rb index ff0b9158..77ab53a8 100644 --- a/lib/ruby_ui/sidebar/sidebar_group_label.rb +++ b/lib/ruby_ui/sidebar/sidebar_group_label.rb @@ -15,7 +15,7 @@ def default_attrs "font-medium text-sidebar-foreground/70 outline-none", "ring-sidebar-ring transition-[margin,opacity] duration-200", "ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", - "group-data-[collapsible=icon]/sidebar:-mt-8 group-data-[collapsible=icon]/sidebar:opacity-0" + "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0" ], data: { sidebar: "group-label" diff --git a/lib/ruby_ui/sidebar/sidebar_menu_action.rb b/lib/ruby_ui/sidebar/sidebar_menu_action.rb index f89dd7c0..9e4a3901 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_action.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_action.rb @@ -26,7 +26,7 @@ def default_attrs "peer-data-[size=sm]/menu-button:top-1", "peer-data-[size=default]/menu-button:top-1.5", "peer-data-[size=lg]/menu-button:top-2.5", - "group-data-[collapsible=icon]/sidebar:hidden", + "group-data-[collapsible=icon]:hidden", show_on_hover_classes ], data: { diff --git a/lib/ruby_ui/sidebar/sidebar_menu_badge.rb b/lib/ruby_ui/sidebar/sidebar_menu_badge.rb index 40eaace3..101b0bbb 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_badge.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_badge.rb @@ -19,7 +19,7 @@ def default_attrs "peer-data-[size=sm]/menu-button:top-1", "peer-data-[size=default]/menu-button:top-1.5", "peer-data-[size=lg]/menu-button:top-2.5", - "group-data-[collapsible=icon]/sidebar:hidden" + "group-data-[collapsible=icon]:hidden" ], data: { sidebar: "menu-badge" diff --git a/lib/ruby_ui/sidebar/sidebar_menu_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_button.rb index b03be6e3..c9ed3d19 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_button.rb @@ -11,7 +11,7 @@ class SidebarMenuButton < Base SIZE_CLASSES = { default: "h-8 text-sm", sm: "h-7 text-xs", - lg: "h-12 text-sm group-data-[collapsible=icon]/sidebar:!p-0" + lg: "h-12 text-sm group-data-[collapsible=icon]:!p-0" }.freeze def initialize(as: "button", variant: :default, size: :default, active: false, **attrs) @@ -34,7 +34,7 @@ def view_template(&) def default_attrs { class: [ - "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]/sidebar:!size-8 group-data-[collapsible=icon]/sidebar:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", + "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", VARIANT_CLASSES[@variant], SIZE_CLASSES[@size] ], diff --git a/lib/ruby_ui/sidebar/sidebar_menu_sub.rb b/lib/ruby_ui/sidebar/sidebar_menu_sub.rb index ffcdba6a..573ae854 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_sub.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_sub.rb @@ -13,7 +13,7 @@ def default_attrs class: [ "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l", "border-sidebar-border px-2.5 py-0.5", - "group-data-[collapsible=icon]/sidebar:hidden" + "group-data-[collapsible=icon]:hidden" ], data: { sidebar: "menu-sub" diff --git a/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb index 0cc9bb45..318cd57c 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb @@ -36,7 +36,7 @@ def default_attrs "[&>svg]:text-sidebar-accent-foreground", "data-[active=true]:bg-sidebar-accent", "data-[active=true]:text-sidebar-accent-foreground", - "group-data-[collapsible=icon]/sidebar:hidden", + "group-data-[collapsible=icon]:hidden", SIZE_CLASSES[@size] ], data: { diff --git a/lib/ruby_ui/sidebar/sidebar_rail.rb b/lib/ruby_ui/sidebar/sidebar_rail.rb index 76f23b40..67f2f1b5 100644 --- a/lib/ruby_ui/sidebar/sidebar_rail.rb +++ b/lib/ruby_ui/sidebar/sidebar_rail.rb @@ -13,14 +13,14 @@ def default_attrs "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all", "ease-linear after:absolute after:inset-y-0 after:left-1/2", "after:w-[2px] hover:after:bg-sidebar-border", - "group-data-[side=left]/sidebar:-right-4 group-data-[side=right]/sidebar:left-0", + "group-data-[side=left]:-right-4 group-data-[side=right]:left-0", "sm:flex [[data-side=left]_&]:cursor-w-resize", "[[data-side=right]_&]:cursor-e-resize", "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize", "[[data-side=right][data-state=collapsed]_&]:cursor-w-resize", - "group-data-[collapsible=offcanvas]/sidebar:translate-x-0", - "group-data-[collapsible=offcanvas]/sidebar:after:left-full", - "group-data-[collapsible=offcanvas]/sidebar:hover:bg-sidebar", + "group-data-[collapsible=offcanvas]:translate-x-0", + "group-data-[collapsible=offcanvas]:after:left-full", + "group-data-[collapsible=offcanvas]:hover:bg-sidebar", "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", ], diff --git a/lib/ruby_ui/sidebar/sidebar_wrapper.rb b/lib/ruby_ui/sidebar/sidebar_wrapper.rb index 3474a947..adefe16f 100644 --- a/lib/ruby_ui/sidebar/sidebar_wrapper.rb +++ b/lib/ruby_ui/sidebar/sidebar_wrapper.rb @@ -2,16 +2,21 @@ module RubyUI class SidebarWrapper < Base + SIDEBAR_WIDTH = '16rem' + SIDEBAR_WIDTH_ICON = '3rem' + def view_template(&) div(**attrs, &) end + private def default_attrs { - class: "group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full", + class: 'group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full', + style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", data: { - controller: "ruby-ui--sidebar" + controller: 'ruby-ui--sidebar' } } end From 819b34db7a5b79914fc1138f5a1a4de67970719a Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sun, 23 Mar 2025 12:46:37 -0300 Subject: [PATCH 39/48] fix sidebar rail --- lib/ruby_ui/sidebar/sidebar_rail.rb | 33 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar_rail.rb b/lib/ruby_ui/sidebar/sidebar_rail.rb index 67f2f1b5..967e6b4e 100644 --- a/lib/ruby_ui/sidebar/sidebar_rail.rb +++ b/lib/ruby_ui/sidebar/sidebar_rail.rb @@ -5,29 +5,30 @@ class SidebarRail < Base def view_template(&) button(**attrs, &) end + private def default_attrs { class: [ - "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all", - "ease-linear after:absolute after:inset-y-0 after:left-1/2", - "after:w-[2px] hover:after:bg-sidebar-border", - "group-data-[side=left]:-right-4 group-data-[side=right]:left-0", - "sm:flex [[data-side=left]_&]:cursor-w-resize", - "[[data-side=right]_&]:cursor-e-resize", - "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize", - "[[data-side=right][data-state=collapsed]_&]:cursor-w-resize", - "group-data-[collapsible=offcanvas]:translate-x-0", - "group-data-[collapsible=offcanvas]:after:left-full", - "group-data-[collapsible=offcanvas]:hover:bg-sidebar", - "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", - "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", + 'absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all', + 'ease-linear after:absolute after:inset-y-0 after:left-1/2', + 'after:w-[2px] hover:after:bg-sidebar-border', + 'group-data-[side=left]:-right-4 group-data-[side=right]:left-0', + 'sm:flex [[data-side=left]_&]:cursor-w-resize', + '[[data-side=right]_&]:cursor-e-resize', + '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize', + '[[data-side=right][data-state=collapsed]_&]:cursor-w-resize', + 'group-data-[collapsible=offcanvas]:translate-x-0', + 'group-data-[collapsible=offcanvas]:after:left-full', + 'group-data-[collapsible=offcanvas]:hover:bg-sidebar', + '[[data-side=left][data-collapsible=offcanvas]_&]:-right-2', + '[[data-side=right][data-collapsible=offcanvas]_&]:-left-2' ], data: { - sidebar: "rail", - sidebar_trigger: true, - tabindex: "-1" + sidebar: 'rail', + tabindex: '-1', + action: 'click->ruby-ui--sidebar#toggle' } } end From 13e22d2bffaa59b49549c322d1132b32a4e9a2e4 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sun, 23 Mar 2025 17:06:02 -0300 Subject: [PATCH 40/48] fix inset styling --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 12 +++++------- lib/ruby_ui/sidebar/sidebar.rb | 10 ++++------ lib/ruby_ui/sidebar/sidebar_wrapper.rb | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb index 120c8448..1eda2028 100644 --- a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -11,13 +11,11 @@ def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: tr end def view_template(&) - div do - MobileSidebar(side: @side, **attrs, &) - div(**mix(sidebar_attrs, attrs)) do - div(**gap_element_attrs) - div(**content_wrapper_attrs) do - div(**content_attrs, &) - end + MobileSidebar(side: @side, **attrs, &) + div(**mix(sidebar_attrs, attrs)) do + div(**gap_element_attrs) + div(**content_wrapper_attrs) do + div(**content_attrs, &) end end end diff --git a/lib/ruby_ui/sidebar/sidebar.rb b/lib/ruby_ui/sidebar/sidebar.rb index 235b2dcd..eef92c83 100644 --- a/lib/ruby_ui/sidebar/sidebar.rb +++ b/lib/ruby_ui/sidebar/sidebar.rb @@ -19,12 +19,10 @@ def initialize(side: :left, variant: :sidebar, collapsible: :offcanvas, open: tr end def view_template(&) - div(**attrs) do - if @collapsible == :none - NonCollapsiableSidebar(&) - else - CollapsiableSidebar(side: @side, variant: @variant, collapsible: @collapsible, open: @open, &) - end + if @collapsible == :none + NonCollapsiableSidebar(**attrs, &) + else + CollapsiableSidebar(side: @side, variant: @variant, collapsible: @collapsible, open: @open, **attrs, &) end end end diff --git a/lib/ruby_ui/sidebar/sidebar_wrapper.rb b/lib/ruby_ui/sidebar/sidebar_wrapper.rb index adefe16f..665d64d6 100644 --- a/lib/ruby_ui/sidebar/sidebar_wrapper.rb +++ b/lib/ruby_ui/sidebar/sidebar_wrapper.rb @@ -13,7 +13,7 @@ def view_template(&) def default_attrs { - class: 'group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full', + class: 'group/sidebar-wrapper [&:has([data-variant=inset])]:bg-sidebar flex min-h-svh w-full', style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", data: { controller: 'ruby-ui--sidebar' From c87a95c02e01b4fa7a14f165a776956654520593 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Sun, 23 Mar 2025 17:56:18 -0300 Subject: [PATCH 41/48] add tests --- test/ruby_ui/sidebar_test.rb | 104 +++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 test/ruby_ui/sidebar_test.rb diff --git a/test/ruby_ui/sidebar_test.rb b/test/ruby_ui/sidebar_test.rb new file mode 100644 index 00000000..e75922f9 --- /dev/null +++ b/test/ruby_ui/sidebar_test.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +require 'test_helper' + +class RubyUI::SidebarTest < ComponentTest + def test_render_with_all_items + output = phlex do + RubyUI.SidebarWrapper do + RubyUI.Sidebar do + RubyUI.SidebarHeader do + RubyUI.SidebarGroup do + RubyUI.SidebarGroupContent do + RubyUI.SidebarInput(id: 'search', placeholder: 'Search the docs') + end + end + end + RubyUI.SidebarContent do + RubyUI.SidebarGroup do + RubyUI.SidebarGroupLabel { 'Application' } + RubyUI.SidebarGroupAction { 'Group Action' } + RubyUI.SidebarGroupContent do + RubyUI.SidebarMenu do + RubyUI.SidebarMenuItem do + RubyUI.SidebarMenuSub do + RubyUI.SidebarMenuSubItem do + RubyUI.SidebarMenuSubButton(as: 'a', href: '#') { 'Sub Item 1' } + end + end + end + RubyUI.SidebarMenuItem do + RubyUI.SidebarMenuButton(as: 'a', href: '#') { 'Settings' } + RubyUI.SidebarMenuAction { 'Settings' } + end + RubyUI.SidebarMenuItem do + RubyUI.SidebarMenuButton { 'Dashboard' } + RubyUI.SidebarMenuAction { 'Dashboard' } + RubyUI.SidebarMenuBadge { 'Dashboard Badge' } + end + RubyUI.SidebarMenuItem do + RubyUI.SidebarMenuSkeleton() + end + end + end + end + end + RubyUI.SidebarFooter { 'Footer' } + RubyUI.SidebarRail() + end + RubyUI.SidebarInset do + RubyUI.SidebarTrigger() + end + end + end + + assert_match(/Search the docs/, output) + assert_match(/Application/, output) + assert_match(/Group Action/, output) + assert_match(/Sub Item 1/, output) + assert_match(/Settings/, output) + assert_match(/Dashboard/, output) + assert_match(/Dashboard Badge/, output) + assert_match(/Footer/, output) + end + + def test_with_side_right + output = phlex do + RubyUI.Sidebar(side: :right) + end + + assert_match(/data-side="right"/, output) + end + + def test_with_variant_floating + output = phlex do + RubyUI.Sidebar(variant: :floating) + end + + assert_match(/data-variant="floating"/, output) + end + + def test_with_collapsible_icon + output = phlex do + RubyUI.Sidebar(collapsible: :icon) + end + + assert_match(/data-collapsible-kind="icon"/, output) + end + + def test_with_open_false + output = phlex do + RubyUI.Sidebar(open: false) + end + + assert_match(/data-state="collapsed"/, output) + end + + def test_with_collapsible_offcanvas + output = phlex do + RubyUI.Sidebar(collapsible: :offcanvas) + end + + assert_match(/data-collapsible-kind="offcanvas"/, output) + end +end From eca518649a4058bcfe995220d55d51b504b1e14f Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Mon, 24 Mar 2025 08:10:40 -0300 Subject: [PATCH 42/48] fix lint --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 44 ++++++++++----------- lib/ruby_ui/sidebar/mobile_sidebar.rb | 20 +++++----- lib/ruby_ui/sidebar/sidebar_rail.rb | 32 +++++++-------- lib/ruby_ui/sidebar/sidebar_trigger.rb | 32 +++++++-------- lib/ruby_ui/sidebar/sidebar_wrapper.rb | 8 ++-- test/ruby_ui/sidebar_test.rb | 22 +++++------ 6 files changed, 79 insertions(+), 79 deletions(-) diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb index 1eda2028..70ff7c97 100644 --- a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -24,14 +24,14 @@ def view_template(&) def sidebar_attrs { - class: 'group peer hidden text-sidebar-foreground md:block', + class: "group peer hidden text-sidebar-foreground md:block", data: { - state: @open ? 'expanded' : 'collapsed', - collapsible: @open ? '' : @collapsible, + state: @open ? "expanded" : "collapsed", + collapsible: @open ? "" : @collapsible, variant: @variant, side: @side, collapsible_kind: @collapsible, - ruby_ui__sidebar_target: 'sidebar' + ruby_ui__sidebar_target: "sidebar" } } end @@ -39,10 +39,10 @@ def sidebar_attrs def gap_element_attrs { class: [ - 'relative w-[--sidebar-width] bg-transparent transition-[width]', - 'duration-200 ease-linear', - 'group-data-[collapsible=offcanvas]:w-0', - 'group-data-[side=right]:rotate-180', + "relative w-[--sidebar-width] bg-transparent transition-[width]", + "duration-200 ease-linear", + "group-data-[collapsible=offcanvas]:w-0", + "group-data-[side=right]:rotate-180", variant_classes ] } @@ -51,8 +51,8 @@ def gap_element_attrs def content_wrapper_attrs { class: [ - 'fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width]', - 'transition-[left,right,width] duration-200 ease-linear md:flex', + "fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width]", + "transition-[left,right,width] duration-200 ease-linear md:flex", content_wrapper_side_classes, content_wrapper_variant_classes ] @@ -62,37 +62,37 @@ def content_wrapper_attrs def content_attrs { class: [ - 'flex h-full w-full flex-col bg-sidebar', - 'group-data-[variant=floating]:rounded-lg', - 'group-data-[variant=floating]:border', - 'group-data-[variant=floating]:border-sidebar-border', - 'group-data-[variant=floating]:shadow' + "flex h-full w-full flex-col bg-sidebar", + "group-data-[variant=floating]:rounded-lg", + "group-data-[variant=floating]:border", + "group-data-[variant=floating]:border-sidebar-border", + "group-data-[variant=floating]:shadow" ], data: { - sidebar: 'sidebar' + sidebar: "sidebar" } } end def variant_classes if %i[floating inset].include?(@variant) - 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]' + "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" else - 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]' + "group-data-[collapsible=icon]:w-[--sidebar-width-icon]" end end def content_wrapper_side_classes - return 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]' if @side == :left + return "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" if @side == :left - 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]' + "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]" end def content_wrapper_variant_classes if %i[floating inset].include?(@variant) - 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]' + "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" else - 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l' + "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l" end end end diff --git a/lib/ruby_ui/sidebar/mobile_sidebar.rb b/lib/ruby_ui/sidebar/mobile_sidebar.rb index 1f5b322e..6d1579cc 100644 --- a/lib/ruby_ui/sidebar/mobile_sidebar.rb +++ b/lib/ruby_ui/sidebar/mobile_sidebar.rb @@ -2,7 +2,7 @@ module RubyUI class MobileSidebar < Base - SIDEBAR_WIDTH_MOBILE = '18rem' + SIDEBAR_WIDTH_MOBILE = "18rem" def initialize(side: :left, **attrs) @side = side @@ -13,20 +13,20 @@ def view_template(&) Sheet(**attrs) do SheetContent( side: @side, - class: 'w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden', + class: "w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden", style: { "--sidebar-width": SIDEBAR_WIDTH_MOBILE }, data: { - sidebar: 'sidebar', - mobile: 'true' + sidebar: "sidebar", + mobile: "true" } ) do - SheetHeader(class: 'sr-only') do - SheetTitle { 'Sidebar' } - SheetDescription { 'Displays the mobile sidebar.' } + SheetHeader(class: "sr-only") do + SheetTitle { "Sidebar" } + SheetDescription { "Displays the mobile sidebar." } end - div(class: 'flex h-full w-full flex-col', &) + div(class: "flex h-full w-full flex-col", &) end end end @@ -36,8 +36,8 @@ def view_template(&) def default_attrs { data: { - ruby_ui__sidebar_target: 'mobileSidebar', - action: 'ruby--ui-sidebar:open->ruby-ui--sheet#open:self' + ruby_ui__sidebar_target: "mobileSidebar", + action: "ruby--ui-sidebar:open->ruby-ui--sheet#open:self" } } end diff --git a/lib/ruby_ui/sidebar/sidebar_rail.rb b/lib/ruby_ui/sidebar/sidebar_rail.rb index 967e6b4e..c4e64f26 100644 --- a/lib/ruby_ui/sidebar/sidebar_rail.rb +++ b/lib/ruby_ui/sidebar/sidebar_rail.rb @@ -11,24 +11,24 @@ def view_template(&) def default_attrs { class: [ - 'absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all', - 'ease-linear after:absolute after:inset-y-0 after:left-1/2', - 'after:w-[2px] hover:after:bg-sidebar-border', - 'group-data-[side=left]:-right-4 group-data-[side=right]:left-0', - 'sm:flex [[data-side=left]_&]:cursor-w-resize', - '[[data-side=right]_&]:cursor-e-resize', - '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize', - '[[data-side=right][data-state=collapsed]_&]:cursor-w-resize', - 'group-data-[collapsible=offcanvas]:translate-x-0', - 'group-data-[collapsible=offcanvas]:after:left-full', - 'group-data-[collapsible=offcanvas]:hover:bg-sidebar', - '[[data-side=left][data-collapsible=offcanvas]_&]:-right-2', - '[[data-side=right][data-collapsible=offcanvas]_&]:-left-2' + "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all", + "ease-linear after:absolute after:inset-y-0 after:left-1/2", + "after:w-[2px] hover:after:bg-sidebar-border", + "group-data-[side=left]:-right-4 group-data-[side=right]:left-0", + "sm:flex [[data-side=left]_&]:cursor-w-resize", + "[[data-side=right]_&]:cursor-e-resize", + "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize", + "[[data-side=right][data-state=collapsed]_&]:cursor-w-resize", + "group-data-[collapsible=offcanvas]:translate-x-0", + "group-data-[collapsible=offcanvas]:after:left-full", + "group-data-[collapsible=offcanvas]:hover:bg-sidebar", + "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", + "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2" ], data: { - sidebar: 'rail', - tabindex: '-1', - action: 'click->ruby-ui--sidebar#toggle' + sidebar: "rail", + tabindex: "-1", + action: "click->ruby-ui--sidebar#toggle" } } end diff --git a/lib/ruby_ui/sidebar/sidebar_trigger.rb b/lib/ruby_ui/sidebar/sidebar_trigger.rb index 707c6d8f..64dfaf78 100644 --- a/lib/ruby_ui/sidebar/sidebar_trigger.rb +++ b/lib/ruby_ui/sidebar/sidebar_trigger.rb @@ -5,7 +5,7 @@ class SidebarTrigger < Base def view_template(&) Button(variant: :ghost, size: :icon, **attrs) do panel_left_icon - span(class: 'sr-only') { 'Toggle Sidebar' } + span(class: "sr-only") { "Toggle Sidebar" } end end @@ -13,29 +13,29 @@ def view_template(&) def default_attrs { - class: 'h-7 w-7 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', + class: "h-7 w-7 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", data: { - sidebar: 'trigger', - action: 'click->ruby-ui--sidebar#toggle' + sidebar: "trigger", + action: "click->ruby-ui--sidebar#toggle" } } end def panel_left_icon svg( - xmlns: 'http://www.w3.org/2000/svg', - width: '24', - height: '24', - viewBox: '0 0 24 24', - fill: 'none', - stroke: 'currentColor', - stroke_width: '2', - stroke_linecap: 'round', - stroke_linejoin: 'round', - class: 'lucide lucide-panel-left' + xmlns: "http://www.w3.org/2000/svg", + width: "24", + height: "24", + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + stroke_width: "2", + stroke_linecap: "round", + stroke_linejoin: "round", + class: "lucide lucide-panel-left" ) do |s| - s.rect(width: '18', height: '18', x: '3', y: '3', rx: '2') - s.path(d: 'M9 3v18') + s.rect(width: "18", height: "18", x: "3", y: "3", rx: "2") + s.path(d: "M9 3v18") end end end diff --git a/lib/ruby_ui/sidebar/sidebar_wrapper.rb b/lib/ruby_ui/sidebar/sidebar_wrapper.rb index 665d64d6..f964860c 100644 --- a/lib/ruby_ui/sidebar/sidebar_wrapper.rb +++ b/lib/ruby_ui/sidebar/sidebar_wrapper.rb @@ -2,8 +2,8 @@ module RubyUI class SidebarWrapper < Base - SIDEBAR_WIDTH = '16rem' - SIDEBAR_WIDTH_ICON = '3rem' + SIDEBAR_WIDTH = "16rem" + SIDEBAR_WIDTH_ICON = "3rem" def view_template(&) div(**attrs, &) @@ -13,10 +13,10 @@ def view_template(&) def default_attrs { - class: 'group/sidebar-wrapper [&:has([data-variant=inset])]:bg-sidebar flex min-h-svh w-full', + class: "group/sidebar-wrapper [&:has([data-variant=inset])]:bg-sidebar flex min-h-svh w-full", style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};", data: { - controller: 'ruby-ui--sidebar' + controller: "ruby-ui--sidebar" } } end diff --git a/test/ruby_ui/sidebar_test.rb b/test/ruby_ui/sidebar_test.rb index e75922f9..4efdb7f1 100644 --- a/test/ruby_ui/sidebar_test.rb +++ b/test/ruby_ui/sidebar_test.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'test_helper' +require "test_helper" class RubyUI::SidebarTest < ComponentTest def test_render_with_all_items @@ -10,31 +10,31 @@ def test_render_with_all_items RubyUI.SidebarHeader do RubyUI.SidebarGroup do RubyUI.SidebarGroupContent do - RubyUI.SidebarInput(id: 'search', placeholder: 'Search the docs') + RubyUI.SidebarInput(id: "search", placeholder: "Search the docs") end end end RubyUI.SidebarContent do RubyUI.SidebarGroup do - RubyUI.SidebarGroupLabel { 'Application' } - RubyUI.SidebarGroupAction { 'Group Action' } + RubyUI.SidebarGroupLabel { "Application" } + RubyUI.SidebarGroupAction { "Group Action" } RubyUI.SidebarGroupContent do RubyUI.SidebarMenu do RubyUI.SidebarMenuItem do RubyUI.SidebarMenuSub do RubyUI.SidebarMenuSubItem do - RubyUI.SidebarMenuSubButton(as: 'a', href: '#') { 'Sub Item 1' } + RubyUI.SidebarMenuSubButton(as: "a", href: "#") { "Sub Item 1" } end end end RubyUI.SidebarMenuItem do - RubyUI.SidebarMenuButton(as: 'a', href: '#') { 'Settings' } - RubyUI.SidebarMenuAction { 'Settings' } + RubyUI.SidebarMenuButton(as: "a", href: "#") { "Settings" } + RubyUI.SidebarMenuAction { "Settings" } end RubyUI.SidebarMenuItem do - RubyUI.SidebarMenuButton { 'Dashboard' } - RubyUI.SidebarMenuAction { 'Dashboard' } - RubyUI.SidebarMenuBadge { 'Dashboard Badge' } + RubyUI.SidebarMenuButton { "Dashboard" } + RubyUI.SidebarMenuAction { "Dashboard" } + RubyUI.SidebarMenuBadge { "Dashboard Badge" } end RubyUI.SidebarMenuItem do RubyUI.SidebarMenuSkeleton() @@ -43,7 +43,7 @@ def test_render_with_all_items end end end - RubyUI.SidebarFooter { 'Footer' } + RubyUI.SidebarFooter { "Footer" } RubyUI.SidebarRail() end RubyUI.SidebarInset do From fa64b691a4b38c96efb6822c3176cb706ca9b641 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Tue, 25 Mar 2025 20:20:18 -0300 Subject: [PATCH 43/48] add sidebar separator component --- lib/ruby_ui/sidebar/sidebar_separator.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 lib/ruby_ui/sidebar/sidebar_separator.rb diff --git a/lib/ruby_ui/sidebar/sidebar_separator.rb b/lib/ruby_ui/sidebar/sidebar_separator.rb new file mode 100644 index 00000000..fb00e609 --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_separator.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module RubyUI + class SidebarSeparator < Base + def view_template(&) + Separator(**attrs, &) + end + + private + + def default_attrs + { + class: "mx-2 w-auto bg-sidebar-border", + data: { + sidebar: "separator" + } + } + end + end +end From 0107a416ed03aed17bced92b62a216b71e9e938a Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Tue, 25 Mar 2025 20:32:55 -0300 Subject: [PATCH 44/48] add separator to tests --- test/ruby_ui/sidebar_test.rb | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/test/ruby_ui/sidebar_test.rb b/test/ruby_ui/sidebar_test.rb index 4efdb7f1..ba4a2968 100644 --- a/test/ruby_ui/sidebar_test.rb +++ b/test/ruby_ui/sidebar_test.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "test_helper" +require 'test_helper' class RubyUI::SidebarTest < ComponentTest def test_render_with_all_items @@ -10,31 +10,31 @@ def test_render_with_all_items RubyUI.SidebarHeader do RubyUI.SidebarGroup do RubyUI.SidebarGroupContent do - RubyUI.SidebarInput(id: "search", placeholder: "Search the docs") + RubyUI.SidebarInput(id: 'search', placeholder: 'Search the docs') end end end RubyUI.SidebarContent do RubyUI.SidebarGroup do - RubyUI.SidebarGroupLabel { "Application" } - RubyUI.SidebarGroupAction { "Group Action" } + RubyUI.SidebarGroupLabel { 'Application' } + RubyUI.SidebarGroupAction { 'Group Action' } RubyUI.SidebarGroupContent do RubyUI.SidebarMenu do RubyUI.SidebarMenuItem do RubyUI.SidebarMenuSub do RubyUI.SidebarMenuSubItem do - RubyUI.SidebarMenuSubButton(as: "a", href: "#") { "Sub Item 1" } + RubyUI.SidebarMenuSubButton(as: 'a', href: '#') { 'Sub Item 1' } end end end RubyUI.SidebarMenuItem do - RubyUI.SidebarMenuButton(as: "a", href: "#") { "Settings" } - RubyUI.SidebarMenuAction { "Settings" } + RubyUI.SidebarMenuButton(as: 'a', href: '#') { 'Settings' } + RubyUI.SidebarMenuAction { 'Settings' } end RubyUI.SidebarMenuItem do - RubyUI.SidebarMenuButton { "Dashboard" } - RubyUI.SidebarMenuAction { "Dashboard" } - RubyUI.SidebarMenuBadge { "Dashboard Badge" } + RubyUI.SidebarMenuButton { 'Dashboard' } + RubyUI.SidebarMenuAction { 'Dashboard' } + RubyUI.SidebarMenuBadge { 'Dashboard Badge' } end RubyUI.SidebarMenuItem do RubyUI.SidebarMenuSkeleton() @@ -42,8 +42,9 @@ def test_render_with_all_items end end end + RubyUI.SidebarSeparator() end - RubyUI.SidebarFooter { "Footer" } + RubyUI.SidebarFooter { 'Footer' } RubyUI.SidebarRail() end RubyUI.SidebarInset do From cf0e94dbb986647fc1e88a39b0cff98135ba9f24 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Tue, 25 Mar 2025 21:16:05 -0300 Subject: [PATCH 45/48] fix broken variables --- lib/ruby_ui/sidebar/collapsiable_sidebar.rb | 8 ++++---- lib/ruby_ui/sidebar/mobile_sidebar.rb | 2 +- lib/ruby_ui/sidebar/non_collapsible_sidebar.rb | 2 +- lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb index 70ff7c97..2dbb90e0 100644 --- a/lib/ruby_ui/sidebar/collapsiable_sidebar.rb +++ b/lib/ruby_ui/sidebar/collapsiable_sidebar.rb @@ -39,7 +39,7 @@ def sidebar_attrs def gap_element_attrs { class: [ - "relative w-[--sidebar-width] bg-transparent transition-[width]", + "relative w-[var(--sidebar-width)] bg-transparent transition-[width]", "duration-200 ease-linear", "group-data-[collapsible=offcanvas]:w-0", "group-data-[side=right]:rotate-180", @@ -51,7 +51,7 @@ def gap_element_attrs def content_wrapper_attrs { class: [ - "fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width]", + "fixed inset-y-0 z-10 hidden h-svh w-[var(--sidebar-width)]", "transition-[left,right,width] duration-200 ease-linear md:flex", content_wrapper_side_classes, content_wrapper_variant_classes @@ -78,7 +78,7 @@ def variant_classes if %i[floating inset].include?(@variant) "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" else - "group-data-[collapsible=icon]:w-[--sidebar-width-icon]" + "group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)]" end end @@ -92,7 +92,7 @@ def content_wrapper_variant_classes if %i[floating inset].include?(@variant) "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" else - "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l" + "group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)] group-data-[side=left]:border-r group-data-[side=right]:border-l" end end end diff --git a/lib/ruby_ui/sidebar/mobile_sidebar.rb b/lib/ruby_ui/sidebar/mobile_sidebar.rb index 6d1579cc..3ecc6976 100644 --- a/lib/ruby_ui/sidebar/mobile_sidebar.rb +++ b/lib/ruby_ui/sidebar/mobile_sidebar.rb @@ -13,7 +13,7 @@ def view_template(&) Sheet(**attrs) do SheetContent( side: @side, - class: "w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden", + class: "w-[var(--sidebar-width)] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden", style: { "--sidebar-width": SIDEBAR_WIDTH_MOBILE }, diff --git a/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb b/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb index 6d08e3f4..37f85f5b 100644 --- a/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb +++ b/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb @@ -10,7 +10,7 @@ def view_template(&) def default_attrs { - class: "flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground" + class: "flex h-full w-[var(--sidebar-width)] flex-col bg-sidebar text-sidebar-foreground" } end end diff --git a/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb b/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb index 5190ddcd..acc42853 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb @@ -11,7 +11,7 @@ def view_template(&) div(**attrs) do Skeleton(class: "size-4 rounded-md", data: {sidebar: "menu-skeleton-icon"}) if @show_icon Skeleton( - class: "h-4 max-w-[--skeleton-width] flex-1", + class: "h-4 max-w-[var(--skeleton-width)] flex-1", data: {sidebar: "menu-skeleton-text"}, style: {"--skeleton-width" => "#{skeleton_width}%"} ) From 3ebad7c8dd11f9d31ad7e4dd64998d2337ab234c Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Tue, 25 Mar 2025 21:44:58 -0300 Subject: [PATCH 46/48] add .to_s to boolean data attributes --- lib/ruby_ui/sidebar/sidebar_menu_button.rb | 2 +- lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar_menu_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_button.rb index c9ed3d19..fdb4c968 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_button.rb @@ -41,7 +41,7 @@ def default_attrs data: { sidebar: "menu-button", size: @size, - active: @active + active: @active.to_s } } end diff --git a/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb index 318cd57c..1c135cd7 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb @@ -42,7 +42,7 @@ def default_attrs data: { sidebar: "menu-sub-button", size: @size, - active: @active + active: @active.to_s } } end From 7814ba3a1ba24f46d0005ad6e698617f8e8563f6 Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 27 Mar 2025 18:43:33 -0300 Subject: [PATCH 47/48] lint code --- test/ruby_ui/sidebar_test.rb | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/ruby_ui/sidebar_test.rb b/test/ruby_ui/sidebar_test.rb index ba4a2968..bff9ee13 100644 --- a/test/ruby_ui/sidebar_test.rb +++ b/test/ruby_ui/sidebar_test.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'test_helper' +require "test_helper" class RubyUI::SidebarTest < ComponentTest def test_render_with_all_items @@ -10,31 +10,31 @@ def test_render_with_all_items RubyUI.SidebarHeader do RubyUI.SidebarGroup do RubyUI.SidebarGroupContent do - RubyUI.SidebarInput(id: 'search', placeholder: 'Search the docs') + RubyUI.SidebarInput(id: "search", placeholder: "Search the docs") end end end RubyUI.SidebarContent do RubyUI.SidebarGroup do - RubyUI.SidebarGroupLabel { 'Application' } - RubyUI.SidebarGroupAction { 'Group Action' } + RubyUI.SidebarGroupLabel { "Application" } + RubyUI.SidebarGroupAction { "Group Action" } RubyUI.SidebarGroupContent do RubyUI.SidebarMenu do RubyUI.SidebarMenuItem do RubyUI.SidebarMenuSub do RubyUI.SidebarMenuSubItem do - RubyUI.SidebarMenuSubButton(as: 'a', href: '#') { 'Sub Item 1' } + RubyUI.SidebarMenuSubButton(as: "a", href: "#") { "Sub Item 1" } end end end RubyUI.SidebarMenuItem do - RubyUI.SidebarMenuButton(as: 'a', href: '#') { 'Settings' } - RubyUI.SidebarMenuAction { 'Settings' } + RubyUI.SidebarMenuButton(as: "a", href: "#") { "Settings" } + RubyUI.SidebarMenuAction { "Settings" } end RubyUI.SidebarMenuItem do - RubyUI.SidebarMenuButton { 'Dashboard' } - RubyUI.SidebarMenuAction { 'Dashboard' } - RubyUI.SidebarMenuBadge { 'Dashboard Badge' } + RubyUI.SidebarMenuButton { "Dashboard" } + RubyUI.SidebarMenuAction { "Dashboard" } + RubyUI.SidebarMenuBadge { "Dashboard Badge" } end RubyUI.SidebarMenuItem do RubyUI.SidebarMenuSkeleton() @@ -44,7 +44,7 @@ def test_render_with_all_items end RubyUI.SidebarSeparator() end - RubyUI.SidebarFooter { 'Footer' } + RubyUI.SidebarFooter { "Footer" } RubyUI.SidebarRail() end RubyUI.SidebarInset do From 9172804852f38a37e39d6d1695b1a0f7d6c04c7e Mon Sep 17 00:00:00 2001 From: Lucas Sousa Date: Thu, 27 Mar 2025 18:46:48 -0300 Subject: [PATCH 48/48] replace public_send with tag --- lib/ruby_ui/sidebar/sidebar_group_action.rb | 4 ++-- lib/ruby_ui/sidebar/sidebar_menu_action.rb | 4 ++-- lib/ruby_ui/sidebar/sidebar_menu_button.rb | 20 ++++++++++++++++--- .../sidebar/sidebar_menu_sub_button.rb | 4 ++-- test/ruby_ui/sidebar_test.rb | 4 ++-- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/ruby_ui/sidebar/sidebar_group_action.rb b/lib/ruby_ui/sidebar/sidebar_group_action.rb index d84b8d3d..b6833d56 100644 --- a/lib/ruby_ui/sidebar/sidebar_group_action.rb +++ b/lib/ruby_ui/sidebar/sidebar_group_action.rb @@ -2,13 +2,13 @@ module RubyUI class SidebarGroupAction < Base - def initialize(as: "button", **attrs) + def initialize(as: :button, **attrs) @as = as super(**attrs) end def view_template(&) - public_send(@as, **attrs, &) + tag(@as, **attrs, &) end private diff --git a/lib/ruby_ui/sidebar/sidebar_menu_action.rb b/lib/ruby_ui/sidebar/sidebar_menu_action.rb index 9e4a3901..21c48d09 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_action.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_action.rb @@ -2,13 +2,13 @@ module RubyUI class SidebarMenuAction < Base - def initialize(as: "button", show_on_hover: false, **attrs) + def initialize(as: :button, show_on_hover: false, **attrs) @as = as super(**attrs) end def view_template(&) - public_send(@as, **attrs, &) + tag(@as, **attrs, &) end private diff --git a/lib/ruby_ui/sidebar/sidebar_menu_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_button.rb index fdb4c968..5480c276 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_button.rb @@ -14,7 +14,7 @@ class SidebarMenuButton < Base lg: "h-12 text-sm group-data-[collapsible=icon]:!p-0" }.freeze - def initialize(as: "button", variant: :default, size: :default, active: false, **attrs) + def initialize(as: :button, variant: :default, size: :default, active: false, **attrs) raise ArgumentError, "Invalid variant: #{variant}" unless VARIANT_CLASSES.key?(variant) raise ArgumentError, "Invalid size: #{size}" unless SIZE_CLASSES.key?(size) @@ -26,7 +26,7 @@ def initialize(as: "button", variant: :default, size: :default, active: false, * end def view_template(&) - public_send(@as, **attrs, &) + tag(@as, **attrs, &) end private @@ -34,7 +34,21 @@ def view_template(&) def default_attrs { class: [ - "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", + "peer/menu-button flex w-full items-center gap-2 overflow-hidden", + "rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring", + "transition-[width,height,padding] hover:bg-sidebar-accent", + "hover:text-sidebar-accent-foreground focus-visible:ring-2", + "active:bg-sidebar-accent active:text-sidebar-accent-foreground", + "disabled:pointer-events-none disabled:opacity-50", + "group-has-[[data-sidebar=menu-action]]/menu-item:pr-8", + "aria-disabled:pointer-events-none aria-disabled:opacity-50", + "data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium", + "data-[active=true]:text-sidebar-accent-foreground", + "data-[state=open]:hover:bg-sidebar-accent", + "data-[state=open]:hover:text-sidebar-accent-foreground", + "group-data-[collapsible=icon]:!size-8", + "group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate", + "[&>svg]:size-4 [&>svg]:shrink-0", VARIANT_CLASSES[@variant], SIZE_CLASSES[@size] ], diff --git a/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb b/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb index 1c135cd7..1c4abef6 100644 --- a/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb +++ b/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb @@ -7,7 +7,7 @@ class SidebarMenuSubButton < Base md: "text-sm" }.freeze - def initialize(as: "button", size: :md, active: false, **attrs) + def initialize(as: :button, size: :md, active: false, **attrs) raise ArgumentError, "Invalid size: #{size}" unless SIZE_CLASSES.key?(size) @as = as @@ -17,7 +17,7 @@ def initialize(as: "button", size: :md, active: false, **attrs) end def view_template(&) - public_send(@as, **attrs, &) + tag(@as, **attrs, &) end private diff --git a/test/ruby_ui/sidebar_test.rb b/test/ruby_ui/sidebar_test.rb index bff9ee13..08a1c87b 100644 --- a/test/ruby_ui/sidebar_test.rb +++ b/test/ruby_ui/sidebar_test.rb @@ -23,12 +23,12 @@ def test_render_with_all_items RubyUI.SidebarMenuItem do RubyUI.SidebarMenuSub do RubyUI.SidebarMenuSubItem do - RubyUI.SidebarMenuSubButton(as: "a", href: "#") { "Sub Item 1" } + RubyUI.SidebarMenuSubButton(as: :a, href: "#") { "Sub Item 1" } end end end RubyUI.SidebarMenuItem do - RubyUI.SidebarMenuButton(as: "a", href: "#") { "Settings" } + RubyUI.SidebarMenuButton(as: :a, href: "#") { "Settings" } RubyUI.SidebarMenuAction { "Settings" } end RubyUI.SidebarMenuItem do