ui(sidebars): add subtle vertical separators and improve sidebar collapse behavior (#1416)

* ui(sidebars): add subtle vertical separators and improve sidebar collapse behavior

* ui(sidebars): stabilize vertical separators and refine layout transitions

* ui(sidebars): make settings sidebar dynamic and fix theme-switching border persistence

* ui(sidebars): improve accessibility by toggling inert attribute on collapse

* ui(sidebars): eliminate ghost borders on collapse by precisely toggling width classes

* ui(sidebars): use semantic border-divider token
This commit is contained in:
Louis
2026-04-11 19:33:30 +02:00
committed by GitHub
parent 0ffd911ea0
commit 9d3553f8c9
3 changed files with 34 additions and 25 deletions

View File

@@ -21,22 +21,27 @@ export default class extends Controller {
toggleLeftSidebar() {
const isOpen = this.leftSidebarTarget.classList.contains("w-full");
this.#updateUserPreference("show_sidebar", !isOpen);
this.#toggleSidebarWidth(this.leftSidebarTarget, isOpen);
this.#toggleSidebarWidth(this.leftSidebarTarget, isOpen, "left");
}
toggleRightSidebar() {
const isOpen = this.rightSidebarTarget.classList.contains("w-full");
this.#updateUserPreference("show_ai_sidebar", !isOpen);
this.#toggleSidebarWidth(this.rightSidebarTarget, isOpen);
this.#toggleSidebarWidth(this.rightSidebarTarget, isOpen, "right");
}
#toggleSidebarWidth(el, isCurrentlyOpen) {
#toggleSidebarWidth(el, isCurrentlyOpen, side) {
const expandedClasses = side === "left" ? [...this.expandedSidebarClasses, "border-r"] : [...this.expandedSidebarClasses, "border-l"];
const collapsedClasses = side === "left" ? [...this.collapsedSidebarClasses, "border-r-0"] : [...this.collapsedSidebarClasses, "border-l-0"];
if (isCurrentlyOpen) {
el.classList.remove(...this.expandedSidebarClasses);
el.classList.add(...this.collapsedSidebarClasses);
el.classList.remove(...expandedClasses);
el.classList.add(...collapsedClasses);
el.inert = true;
} else {
el.classList.add(...this.expandedSidebarClasses);
el.classList.remove(...this.collapsedSidebarClasses);
el.classList.add(...expandedClasses);
el.classList.remove(...collapsedClasses);
el.inert = false;
}
}

View File

@@ -17,7 +17,7 @@ end %>
<% desktop_nav_items = mobile_nav_items.reject { |item| item[:mobile_only] } %>
<% expanded_sidebar_class = "w-full" %>
<% collapsed_sidebar_class = "w-0" %>
<% collapsed_sidebar_class = "w-0 overflow-hidden" %>
<%= render "layouts/shared/htmldoc" do %>
<div
@@ -70,8 +70,8 @@ end %>
</nav>
<%# DESKTOP - Left navbar %>
<div class="hidden lg:block">
<nav class="h-full flex flex-col shrink-0 w-[84px] py-4 mr-3">
<div class="hidden lg:block border-r border-divider">
<nav class="h-full flex flex-col shrink-0 w-[84px] py-4">
<div class="pl-2 mb-3">
<%= link_to home_path, class: "block" do %>
<%= image_tag "logomark-color.svg", class: "w-9 h-9 mx-auto" %>
@@ -101,15 +101,16 @@ end %>
<%# DESKTOP - Left sidebar %>
<%= tag.div class: class_names(
"hidden lg:block py-4 overflow-y-auto shrink-0 max-w-[320px] transition-all duration-300",
Current.user.show_sidebar? ? expanded_sidebar_class : collapsed_sidebar_class,
"hidden lg:block py-4 shrink-0 max-w-[320px] transition-all duration-300 border-divider",
Current.user.show_sidebar? ? [expanded_sidebar_class, "border-r"] : [collapsed_sidebar_class, "border-r-0"],
),
inert: !Current.user.show_sidebar?,
data: { app_layout_target: "leftSidebar" } do %>
<% if content_for?(:sidebar) %>
<%= yield :sidebar %>
<% else %>
<div class="h-full flex flex-col">
<div class="overflow-y-auto grow">
<div class="px-4 h-full flex flex-col overflow-y-auto">
<% if content_for?(:sidebar) %>
<%= yield :sidebar %>
<% else %>
<div class="grow">
<%= render "accounts/account_sidebar_tabs", family: Current.family, active_tab: @account_group_tab %>
</div>
@@ -133,8 +134,8 @@ end %>
</div>
</div>
<% end %>
</div>
<% end %>
<% end %>
</div>
<% end %>
<%# SHARED - Main content %>
@@ -177,11 +178,12 @@ end %>
<%# DESKTOP - Right sidebar %>
<%= tag.div class: class_names(
"hidden lg:block h-full overflow-y-auto shrink-0 max-w-[400px] transition-all duration-300",
Current.user.show_ai_sidebar? ? expanded_sidebar_class : collapsed_sidebar_class,
"hidden lg:block h-full shrink-0 max-w-[400px] transition-all duration-300 border-divider",
Current.user.show_ai_sidebar? ? [expanded_sidebar_class, "border-l"] : [collapsed_sidebar_class, "border-l-0"],
),
inert: !Current.user.show_ai_sidebar?,
data: { app_layout_target: "rightSidebar" } do %>
<%= tag.div id: "chat-container", class: "relative h-full", data: { controller: "chat hotkey", turbo_permanent: true } do %>
<%= tag.div id: "chat-container", class: "relative h-full px-4 overflow-y-auto", data: { controller: "chat hotkey", turbo_permanent: true } do %>
<div class="flex flex-col h-full justify-between shrink-0">
<%= turbo_frame_tag chat_frame, src: chat_view_path(@chat), loading: "lazy", class: "h-full" do %>
<div class="flex justify-center items-center h-full">
@@ -191,7 +193,7 @@ end %>
</div>
<% unless Current.user.ai_enabled? %>
<div class="absolute backdrop-blur-lg inset-0 h-full w-full flex flex-col justify-center items-center pl-0.5 pr-4">
<div class="absolute backdrop-blur-lg inset-0 h-full w-full flex flex-col justify-center items-center px-4">
<%= render "chats/ai_consent" %>
</div>
<% end %>

View File

@@ -1,7 +1,9 @@
<%= render "layouts/shared/htmldoc" do %>
<div class="flex flex-col md:flex-row h-full bg-surface pt-[env(safe-area-inset-top)]">
<div class="p-4 w-full md:w-96 shrink-0 md:h-full md:overflow-y-auto">
<%= render "settings/settings_nav" %>
<div class="w-full md:w-auto md:min-w-64 shrink-0 md:h-full md:overflow-y-auto border-divider md:border-r">
<div class="p-4">
<%= render "settings/settings_nav" %>
</div>
</div>
<main class="grow flex h-full">