refactor(desktop): extract auxiliary pane layout

Signed-off-by: Carl <1f967df5817845a2a5d74c82ac3098dea0bb7342665352af6643c5ac5c878dd3@buzz.block.builderlab.xyz>
This commit is contained in:
Carl
2026-08-27 16:20:37 -07:00
parent 25cf2a7f29
commit 263e1aeed1
2 changed files with 99 additions and 40 deletions

View File

@@ -31,6 +31,7 @@ import { ChannelManagementAuxiliaryPanel } from "@/features/channels/ui/ChannelM
import { IdleAuxiliaryPanel } from "@/features/channels/ui/IdleAuxiliaryPanel";
import { MarkdownDocAuxiliaryPanel } from "@/features/channels/ui/MarkdownDocAuxiliaryPanel";
import { RightAuxiliaryPane } from "@/features/channels/ui/RightAuxiliaryPane";
import { createChannelPaneAuxiliaryLayout } from "@/features/channels/ui/channelPaneAuxiliaryLayout";
import {
ThreadPanelSurface,
useThreadPanelSurface,
@@ -51,11 +52,7 @@ import {
WelcomeComposerGuidanceLayer,
} from "@/features/channels/ui/WelcomeComposerBanner";
import { useWelcomeComposerBanner } from "@/features/channels/ui/useWelcomeComposerBanner";
import {
mentionsKnownAgent,
shouldPrioritizeIdleAuxiliary,
shouldUseFocusIdleDrawer,
} from "@/features/channels/ui/ChannelPane.helpers";
import { mentionsKnownAgent } from "@/features/channels/ui/ChannelPane.helpers";
import { HuddleStartingView, HuddleTranscriptIntro } from "@/features/huddle";
import { ChannelGlyph } from "@/features/channels/ui/ChannelGlyph";
import { useSearchHighlightProps } from "@/features/channels/ui/useSearchHighlightProps";
@@ -425,12 +422,7 @@ export const ChannelPane = React.memo(function ChannelPane({
threadHeadMessage,
]);
const isOverlay = useIsThreadPanelOverlay();
const useSplitAuxiliaryPane = !isSinglePanelView && !isOverlay;
const threadViewMode = useThreadViewMode();
const hasThreadSurface =
Boolean(threadHeadMessage) || shouldShowThreadSkeleton;
const useFocusThreadDrawer =
threadViewMode === "focus" && useSplitAuxiliaryPane && hasThreadSurface;
const selectedAgent = React.useMemo(
() =>
agentSessionSelection.resolveSelectedAgentSession({
@@ -441,28 +433,29 @@ export const ChannelPane = React.memo(function ChannelPane({
}),
[agentSessionAgents, openAgentSessionPubkey, profilePanelPubkey, profiles],
);
const hasIdleAuxiliary =
Boolean(idleAuxiliaryPanel) && Boolean(onCloseIdleAuxiliaryPanel);
const priorityIdleAuxiliary = shouldPrioritizeIdleAuxiliary(
idleAuxiliaryOverridesThread,
hasIdleAuxiliary,
);
const overlayIdleAuxiliaryOverThread =
priorityIdleAuxiliary && hasThreadSurface && !isOverlay;
const replaceThreadWithIdleAuxiliary =
priorityIdleAuxiliary && hasThreadSurface && isOverlay;
const useFocusIdleDrawer = shouldUseFocusIdleDrawer({
const {
hasSplitAuxiliaryPane,
openMarkdownDoc,
priorityIdleAuxiliary,
replaceThreadWithIdleAuxiliary,
showIdleAuxiliaryOverThread,
useFocusIdleDrawer,
useFocusThreadDrawer,
useSplitAuxiliaryPane,
} = createChannelPaneAuxiliaryLayout({
channelManagementOpen,
hasAgentSession: Boolean(activeChannel && selectedAgent),
hasIdleAuxiliaryPanel: Boolean(idleAuxiliaryPanel),
hasIdlePanelCloseHandler: Boolean(onCloseIdleAuxiliaryPanel),
hasProfilePanel: Boolean(profilePanelPubkey),
hasThreadSurface,
overrideThread: overlayIdleAuxiliaryOverThread,
useSplitAuxiliaryPane,
hasThreadSurface: Boolean(threadHeadMessage) || shouldShowThreadSkeleton,
idleAuxiliaryOverridesThread,
isOverlay,
isSinglePanelView,
markdownDocName,
markdownDocUrl,
threadViewMode,
});
const showIdleAuxiliaryOverThread =
overlayIdleAuxiliaryOverThread && useFocusIdleDrawer;
const { channelIsCovered, markExitComplete } = useFocusDrawerPresence(
useFocusThreadDrawer || useFocusIdleDrawer,
priorityIdleAuxiliary
@@ -499,17 +492,6 @@ export const ChannelPane = React.memo(function ChannelPane({
threadMessages: threadMessages.map((entry) => entry.message),
useFocusThreadDrawer,
});
const openMarkdownDoc =
markdownDocUrl && markdownDocName
? { filename: markdownDocName, url: markdownDocUrl }
: null;
const hasSplitAuxiliaryPane =
useSplitAuxiliaryPane &&
(channelManagementOpen ||
Boolean(threadHeadMessage) ||
shouldShowThreadSkeleton ||
Boolean(activeChannel && selectedAgent) ||
Boolean(profilePanelPubkey));
const wrapAux = (
panel: React.ReactNode,
testId: string,
@@ -803,8 +785,6 @@ export const ChannelPane = React.memo(function ChannelPane({
}
showTopBorder={false}
/>
{/* The reserved bottom rail keeps accessory fades from moving
the conversation while content remains responsive. */}
<ChannelComposerActivityAccessory
agents={activityAgents}
channel={activeChannel}
@@ -825,7 +805,6 @@ export const ChannelPane = React.memo(function ChannelPane({
</div>
</section>
) : null}
{/* Serialize replacements so focus drawers keep one travel direction. */}
<AnimatePresence mode="wait" onExitComplete={markExitComplete}>
{channelManagementOpen && activeChannel ? (
<ChannelManagementAuxiliaryPanel

View File

@@ -0,0 +1,80 @@
import {
shouldPrioritizeIdleAuxiliary,
shouldUseFocusIdleDrawer,
} from "./ChannelPane.helpers";
type ChannelPaneAuxiliaryLayoutOptions = {
channelManagementOpen: boolean;
hasAgentSession: boolean;
hasIdleAuxiliaryPanel: boolean;
hasIdlePanelCloseHandler: boolean;
hasProfilePanel: boolean;
hasThreadSurface: boolean;
idleAuxiliaryOverridesThread: boolean;
isOverlay: boolean;
isSinglePanelView: boolean;
markdownDocName?: string | null;
markdownDocUrl?: string | null;
threadViewMode: string;
};
export function createChannelPaneAuxiliaryLayout({
channelManagementOpen,
hasAgentSession,
hasIdleAuxiliaryPanel,
hasIdlePanelCloseHandler,
hasProfilePanel,
hasThreadSurface,
idleAuxiliaryOverridesThread,
isOverlay,
isSinglePanelView,
markdownDocName,
markdownDocUrl,
threadViewMode,
}: ChannelPaneAuxiliaryLayoutOptions) {
const useSplitAuxiliaryPane = !isSinglePanelView && !isOverlay;
const useFocusThreadDrawer =
threadViewMode === "focus" && useSplitAuxiliaryPane && hasThreadSurface;
const hasIdleAuxiliary = hasIdleAuxiliaryPanel && hasIdlePanelCloseHandler;
const priorityIdleAuxiliary = shouldPrioritizeIdleAuxiliary(
idleAuxiliaryOverridesThread,
hasIdleAuxiliary,
);
const overlayIdleAuxiliaryOverThread =
priorityIdleAuxiliary && hasThreadSurface && !isOverlay;
const replaceThreadWithIdleAuxiliary =
priorityIdleAuxiliary && hasThreadSurface && isOverlay;
const useFocusIdleDrawer = shouldUseFocusIdleDrawer({
channelManagementOpen,
hasAgentSession,
hasIdleAuxiliaryPanel,
hasIdlePanelCloseHandler,
hasProfilePanel,
hasThreadSurface,
overrideThread: overlayIdleAuxiliaryOverThread,
useSplitAuxiliaryPane,
});
const openMarkdownDoc =
markdownDocUrl && markdownDocName
? { filename: markdownDocName, url: markdownDocUrl }
: null;
const hasSplitAuxiliaryPane =
useSplitAuxiliaryPane &&
(channelManagementOpen ||
hasThreadSurface ||
hasAgentSession ||
hasProfilePanel);
return {
hasSplitAuxiliaryPane,
openMarkdownDoc,
priorityIdleAuxiliary,
replaceThreadWithIdleAuxiliary,
showIdleAuxiliaryOverThread:
overlayIdleAuxiliaryOverThread && useFocusIdleDrawer,
useFocusIdleDrawer,
useFocusThreadDrawer,
useSplitAuxiliaryPane,
};
}