From a7a5aee9824094e17a6a3c5b65720a04302db1ab Mon Sep 17 00:00:00 2001 From: Jon Kazama Date: Sat, 30 May 2026 18:22:38 +0200 Subject: [PATCH] feat(sidebar): wire configurable expanded width through a single source --- .../SelfTests/SidebarModeAutoSwitchStep.cs | 42 +++++++++++++++++++ .../Components/Settings/Tabs/ChannelsTab.cs | 10 ++--- HellionChat/Ui/Components/Sidebar.cs | 15 +++++-- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/HellionChat/SelfTests/SidebarModeAutoSwitchStep.cs b/HellionChat/SelfTests/SidebarModeAutoSwitchStep.cs index 56f15bf..cb9e41a 100644 --- a/HellionChat/SelfTests/SidebarModeAutoSwitchStep.cs +++ b/HellionChat/SelfTests/SidebarModeAutoSwitchStep.cs @@ -58,6 +58,48 @@ internal sealed class SidebarModeAutoSwitchStep : ISelfTestStep return SelfTestStepResult.Fail; } + // B1-3a: the expanded width must come from Config.SidebarWidth, not the + // old fixed 150 constant. Drive the REAL GetWidth (the single source + // Sidebar.Draw consumes) with concrete values and assert the OBSERVED + // effect — in-range passthrough plus clamping — instead of mirroring the + // Math.Clamp logic (SelfTests/README.md forbids re-implementing helper + // logic in the test). Restore the config in finally so the live render + // path is untouched. + var savedSidebarWidth = Plugin.Config.SidebarWidth; + try + { + Plugin.Config.SidebarWidth = 220; + if (sidebar.GetWidth(threshold + 100f) != 220f) + { + ImGui.Text( + $"GetWidth expanded = {sidebar.GetWidth(threshold + 100f)}, expected in-range Config.SidebarWidth 220" + ); + return SelfTestStepResult.Fail; + } + + Plugin.Config.SidebarWidth = 9999; + if (sidebar.GetWidth(threshold + 100f) != Sidebar.MaxSidebarWidth) + { + ImGui.Text( + $"GetWidth expanded = {sidebar.GetWidth(threshold + 100f)}, expected clamp to MaxSidebarWidth {Sidebar.MaxSidebarWidth}" + ); + return SelfTestStepResult.Fail; + } + + Plugin.Config.SidebarWidth = 1; + if (sidebar.GetWidth(threshold + 100f) != Sidebar.MinSidebarWidth) + { + ImGui.Text( + $"GetWidth expanded = {sidebar.GetWidth(threshold + 100f)}, expected clamp to MinSidebarWidth {Sidebar.MinSidebarWidth}" + ); + return SelfTestStepResult.Fail; + } + } + finally + { + Plugin.Config.SidebarWidth = savedSidebarWidth; + } + return SelfTestStepResult.Pass; } diff --git a/HellionChat/Ui/Components/Settings/Tabs/ChannelsTab.cs b/HellionChat/Ui/Components/Settings/Tabs/ChannelsTab.cs index 9096774..6e036b8 100644 --- a/HellionChat/Ui/Components/Settings/Tabs/ChannelsTab.cs +++ b/HellionChat/Ui/Components/Settings/Tabs/ChannelsTab.cs @@ -60,16 +60,14 @@ internal sealed class ChannelsTab () => Plugin.Config.SidebarTabView, v => Plugin.Config.SidebarTabView = v ); - // Range covers the on-disk default (44) plus Master-Spec §4.1 reference - // (38px icon-only, 150px expanded). An earlier 120-400 range would clamp - // the default 44 up to 120 silently. 30 leaves headroom for a future - // ultra-tight icon-only mode; 300 stays above the 150 expanded reference - // without giving the slider an absurd ceiling. + // Range matches Sidebar.MinSidebarWidth/MaxSidebarWidth (40-300). The + // lower bound sits just above the 38px icon-only threshold; the + // on-disk default (44) and the 150px expanded reference both fit. DrawSliderInt( "Sidebar width", () => Plugin.Config.SidebarWidth, v => Plugin.Config.SidebarWidth = v, - 30, + 40, 300 ); } diff --git a/HellionChat/Ui/Components/Sidebar.cs b/HellionChat/Ui/Components/Sidebar.cs index e99c55e..536306e 100644 --- a/HellionChat/Ui/Components/Sidebar.cs +++ b/HellionChat/Ui/Components/Sidebar.cs @@ -11,7 +11,7 @@ using Microsoft.Extensions.Logging; namespace HellionChat.Ui.Components; // Channel-list panel pinned to the left of the chat window. Auto-switches -// between an icon-only column (38px) and an expanded column (150px) once +// between an icon-only column (38px) and an expanded column (Config.SidebarWidth) once // the outer window crosses Config.SidebarAutoSwitchThresholdPx. The // pop-out affordance (hover button + right-click menu) routes through the // injected ChannelPopoutPool via TryOpen, which reserves a slot and binds @@ -19,7 +19,12 @@ namespace HellionChat.Ui.Components; internal sealed class Sidebar { public const float IconOnlyWidth = 38f; - public const float ExpandedWidth = 150f; + + // B1-3a: expanded sidebar width is user-configurable (Config.SidebarWidth), + // clamped to these bounds (matches the ChannelsTab slider range). Replaces + // the old fixed 150px ExpandedWidth constant. + public const float MinSidebarWidth = 40f; + public const float MaxSidebarWidth = 300f; private const float RowHeight = 32f; private const float PopOutHitWidth = 22f; @@ -72,7 +77,9 @@ internal sealed class Sidebar windowWidth >= Plugin.Config.SidebarAutoSwitchThresholdPx; public float GetWidth(float windowWidth) => - IsExpanded(windowWidth) ? ExpandedWidth : IconOnlyWidth; + IsExpanded(windowWidth) + ? Math.Clamp((float)Plugin.Config.SidebarWidth, MinSidebarWidth, MaxSidebarWidth) + : IconOnlyWidth; public void Draw(float windowWidth, IList tabs, ref Tab? activeTab) { @@ -83,7 +90,7 @@ internal sealed class Sidebar } var expanded = IsExpanded(windowWidth); - var width = expanded ? ExpandedWidth : IconOnlyWidth; + var width = GetWidth(windowWidth); using var child = ImRaii.Child("##hellion-sidebar", new Vector2(width, 0)); if (!child.Success) return;