# Conflicts:
#	frontend-web/src/position-roundtable/components/PositionBuiltinAgentChat.tsx
#	frontend-web/src/position-roundtable/components/PositionNodeChat.tsx
This commit is contained in:
董宏凯 committed 2026-07-24 10:41:38 +08:00
commit 28bf1ac7b2
8 files changed
+184 -32

No files matched your search

+8 -7
View File
@@ -90,12 +90,13 @@ git-clone/
# Repo-root offline dependency pack (local only) # Repo-root offline dependency pack (local only)
/dist/ /dist/
# Frontend offline pack working directories # Frontend offline pack working directories
frontend-web/.offline-pack-build/ frontend-web/.offline-pack-build/
frontend-web/.offline-extract-test/ frontend-web/.offline-extract-test/
frontend-web-node_modules-offline-*.tar.gz
.codegraph
codegraph.mdc .codegraph
codegraph.mdc
docs/aidev-docs docs/aidev-docs
docs/backups docs/backups
@@ -112,4 +113,4 @@ offline-backend-20260512/backend/uv.lock
__pycache__/ __pycache__/
# misc # misc
.DS_Store .DS_Store
@@ -603,12 +603,12 @@ export function PositionBuiltinAgentChat({
return ( return (
<ThreadContext.Provider value={threadContextValue}> <ThreadContext.Provider value={threadContextValue}>
<div className="flex min-h-0 flex-1 flex-col"> <div className="position-roundtable-agent-analysis-page position-roundtable-builtin-chat flex min-h-0 flex-1 flex-col">
<header className="flex min-h-12 shrink-0 items-center gap-2 border-b border-slate-100 px-4 py-2 dark:border-[#2b8ffe]/20"> <header className="position-roundtable-agent-header flex min-h-12 shrink-0 items-center gap-2 border-b border-slate-100 px-4 py-2 dark:border-[#2b8ffe]/20">
<span className="flex size-7 items-center justify-center rounded-lg bg-primary/10 text-primary"> <span className="position-roundtable-agent-avatar flex size-7 items-center justify-center rounded-lg bg-primary/10 text-primary">
{canWrite ? <Icon className="size-4" /> : <LockKeyhole className="size-3.5" />} {canWrite ? <Icon className="size-4" /> : <LockKeyhole className="size-3.5" />}
</span> </span>
<div className="min-w-0 flex-1"> <div className="position-roundtable-agent-title min-w-0 flex-1">
<h2 className="truncate text-sm font-extrabold text-slate-900 dark:text-[#e8edf5]"> <h2 className="truncate text-sm font-extrabold text-slate-900 dark:text-[#e8edf5]">
{agentDisplayName} {agentDisplayName}
</h2> </h2>
@@ -639,7 +639,7 @@ export function PositionBuiltinAgentChat({
</header> </header>
{persistedArtifacts.length > 0 && ( {persistedArtifacts.length > 0 && (
<section className="shrink-0 border-b border-slate-100 bg-slate-50/70 px-4 py-2.5 dark:border-[#2b8ffe]/20 dark:bg-[#032650]/50"> <section className="position-roundtable-agent-artifacts shrink-0 border-b border-slate-100 bg-slate-50/70 px-4 py-2.5 dark:border-[#2b8ffe]/20 dark:bg-[#032650]/50">
<div className="mb-1.5 flex items-center gap-1.5 text-[11px] font-semibold text-slate-600 dark:text-[#c5cfe0]"> <div className="mb-1.5 flex items-center gap-1.5 text-[11px] font-semibold text-slate-600 dark:text-[#c5cfe0]">
<FileText className="size-3.5 text-primary" /> <FileText className="size-3.5 text-primary" />
阶段产物 阶段产物
@@ -675,7 +675,7 @@ export function PositionBuiltinAgentChat({
{boundThreadId || recoveredMessages.length > 0 ? ( {boundThreadId || recoveredMessages.length > 0 ? (
<MessageList <MessageList
className="min-h-0 flex-1" className="position-roundtable-agent-message-list min-h-0 flex-1"
threadId={boundThreadId ?? displayThreadId} threadId={boundThreadId ?? displayThreadId}
thread={displayThread} thread={displayThread}
paddingBottom={24} paddingBottom={24}
@@ -716,7 +716,7 @@ export function PositionBuiltinAgentChat({
</div> </div>
)} )}
<div className="shrink-0 border-t border-slate-100 px-4 py-3 dark:border-[#2b8ffe]/20"> <div className="position-roundtable-agent-composer-bar shrink-0 border-t border-slate-100 px-4 py-3 dark:border-[#2b8ffe]/20">
<PositionAgentInput <PositionAgentInput
className="w-full" className="w-full"
isNewThread={!boundThreadId} isNewThread={!boundThreadId}
@@ -71,10 +71,10 @@ export function PositionIntentInput({
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
return ( return (
<div className="position-roundtable-intent-input shrink-0 border-t border-slate-200 bg-[#f7faff] px-4 py-3 dark:border-[#2b8ffe]/35 dark:bg-[#071a38]"> <div className="position-roundtable-intent-input position-roundtable-intent-composer shrink-0 border-t border-slate-200 bg-[#f7faff] px-4 py-3 dark:border-[#2b8ffe]/35 dark:bg-[#071a38]">
<div className="relative overflow-hidden rounded-[4px] border border-slate-300 bg-white shadow-[0_2px_10px_rgba(15,23,42,0.08)] transition-all focus-within:border-primary focus-within:ring-2 focus-within:ring-[var(--brand-200)]/45 dark:border-[#2b8ffe]/55 dark:bg-[#0d2855] dark:shadow-none dark:focus-within:border-[#56baff] dark:focus-within:ring-[#2b8ffe]/25"> <div className="position-roundtable-intent-composer-frame relative overflow-hidden rounded-[4px] border border-slate-300 bg-white shadow-[0_2px_10px_rgba(15,23,42,0.08)] transition-all focus-within:border-primary focus-within:ring-2 focus-within:ring-[var(--brand-200)]/45 dark:border-[#2b8ffe]/55 dark:bg-[#0d2855] dark:shadow-none dark:focus-within:border-[#56baff] dark:focus-within:ring-[#2b8ffe]/25">
{attachedFiles.length > 0 && ( {attachedFiles.length > 0 && (
<div className="mx-3 mb-2 flex flex-wrap gap-1.5 border-b border-slate-100 pb-2 pt-2.5 dark:border-[#2b8ffe]/25"> <div className="position-roundtable-intent-attachments mx-3 mb-2 flex flex-wrap gap-1.5 border-b border-slate-100 pb-2 pt-2.5 dark:border-[#2b8ffe]/25">
{attachedFiles.map((file, index) => ( {attachedFiles.map((file, index) => (
<span <span
key={`${file.name}-${file.size}-${index}`} key={`${file.name}-${file.size}-${index}`}
@@ -113,7 +113,7 @@ export function PositionIntentInput({
? "也可在此输入自定义回答(Enter 发送 / Shift+Enter 换行)" ? "也可在此输入自定义回答(Enter 发送 / Shift+Enter 换行)"
: "请输入补充信息 / 回答问题 / 继续澄清(Enter 发送 / Shift+Enter 换行)" : "请输入补充信息 / 回答问题 / 继续澄清(Enter 发送 / Shift+Enter 换行)"
} }
className="min-h-[74px] w-full max-h-80 bg-transparent px-3 py-2.5 text-sm font-normal leading-relaxed text-slate-700 placeholder:text-slate-400 focus:outline-none dark:text-[#e7f0ff] dark:placeholder:text-[#7e9bc5]" className="position-roundtable-intent-textarea min-h-[74px] w-full max-h-80 bg-transparent px-3 py-2.5 text-sm font-normal leading-relaxed text-slate-700 placeholder:text-slate-400 focus:outline-none dark:text-[#e7f0ff] dark:placeholder:text-[#7e9bc5]"
maxHeight={320} maxHeight={320}
maxLength={500} maxLength={500}
/> />
@@ -154,7 +154,7 @@ export function PositionIntentInput({
Parent pages can still hide optional actions by their stable ids Parent pages can still hide optional actions by their stable ids
without changing this component's layout or global input styles. without changing this component's layout or global input styles.
*/} */}
<div className="flex flex-wrap items-center gap-3 border-t border-slate-100 bg-white px-3 py-2.5 dark:border-[#2b8ffe]/25 dark:bg-[#0b234c]"> <div className="position-roundtable-intent-toolbar flex flex-wrap items-center gap-3 border-t border-slate-100 bg-white px-3 py-2.5 dark:border-[#2b8ffe]/25 dark:bg-[#0b234c]">
<div className="flex shrink-0 items-center"> <div className="flex shrink-0 items-center">
<input <input
ref={fileInputRef} ref={fileInputRef}
@@ -171,15 +171,15 @@ export function PositionIntentInput({
onClick={() => fileInputRef.current?.click()} onClick={() => fileInputRef.current?.click()}
title="上传参考文件" title="上传参考文件"
aria-label="上传参考文件" aria-label="上传参考文件"
className="flex size-10 items-center justify-center rounded-[4px] border border-slate-200 bg-white text-slate-500 transition hover:border-primary/45 hover:text-primary dark:border-[#2b8ffe]/35 dark:bg-[#102f63] dark:text-[#b9d3f7] dark:hover:bg-[#1a417b] dark:hover:text-[#73c8ff]" className="position-roundtable-intent-upload-btn flex size-10 items-center justify-center rounded-[4px] border border-slate-200 bg-white text-slate-500 transition hover:border-primary/45 hover:text-primary dark:border-[#2b8ffe]/35 dark:bg-[#102f63] dark:text-[#b9d3f7] dark:hover:bg-[#1a417b] dark:hover:text-[#73c8ff]"
> >
<Paperclip className="size-4" /> <Paperclip className="size-4" />
</button> </button>
</div> </div>
<div className="ml-auto flex min-w-0 flex-wrap items-center justify-end gap-1.5"> <div className="position-roundtable-intent-actions ml-auto flex min-w-0 flex-wrap items-center justify-end gap-1.5">
{modelOptions.length > 0 && ( {modelOptions.length > 0 && (
<div <div
className="flex h-10 shrink-0 items-center gap-1.5 rounded-[4px] border border-slate-200 bg-white pl-2 text-xs font-bold text-slate-700 shadow-sm dark:border-[#2b8ffe]/35 dark:bg-[#102f63] dark:text-[#b9d3f7]" className="position-roundtable-intent-model-switch flex h-10 shrink-0 items-center gap-1.5 rounded-[4px] border border-slate-200 bg-white pl-2 text-xs font-bold text-slate-700 shadow-sm dark:border-[#2b8ffe]/35 dark:bg-[#102f63] dark:text-[#b9d3f7]"
title="切换意图理解模型" title="切换意图理解模型"
> >
<Sparkles className="size-3.5 shrink-0 text-primary dark:text-[#73c8ff]" /> <Sparkles className="size-3.5 shrink-0 text-primary dark:text-[#73c8ff]" />
@@ -200,7 +200,7 @@ export function PositionIntentInput({
type="button" type="button"
onClick={onSend} onClick={onSend}
disabled={!canSend} disabled={!canSend}
className="flex h-10 shrink-0 items-center gap-1.5 rounded-[4px] bg-primary px-3 text-xs font-bold text-white shadow-[0_2px_8px_rgba(245,34,45,0.15)] transition-all active:scale-[0.98] hover:bg-[var(--brand-900)] disabled:cursor-not-allowed disabled:bg-slate-300 dark:bg-[#1478e8] dark:hover:bg-[#2995ff] dark:disabled:bg-[#28476f]" className="position-roundtable-intent-send-btn flex h-10 shrink-0 items-center gap-1.5 rounded-[4px] bg-primary px-3 text-xs font-bold text-white shadow-[0_2px_8px_rgba(245,34,45,0.15)] transition-all active:scale-[0.98] hover:bg-[var(--brand-900)] disabled:cursor-not-allowed disabled:bg-slate-300 dark:bg-[#1478e8] dark:hover:bg-[#2995ff] dark:disabled:bg-[#28476f]"
> >
{isSending ? <Loader2 className="size-3 animate-spin" /> : <Send className="size-3" />} {isSending ? <Loader2 className="size-3 animate-spin" /> : <Send className="size-3" />}
{isSending ? "发送中" : "发送"} {isSending ? "发送中" : "发送"}
@@ -668,12 +668,12 @@ export function PositionNodeChat({
return ( return (
<ThreadContext.Provider value={threadContextValue}> <ThreadContext.Provider value={threadContextValue}>
<div className="flex min-h-0 flex-1 flex-col"> <div className="position-roundtable-agent-analysis-page position-roundtable-node-chat flex min-h-0 flex-1 flex-col">
<header className="flex min-h-12 shrink-0 items-center gap-2 border-b border-slate-100 px-4 py-2 dark:border-[#2b8ffe]/20"> <header className="position-roundtable-agent-header flex min-h-12 shrink-0 items-center gap-2 border-b border-slate-100 px-4 py-2 dark:border-[#2b8ffe]/20">
<span className="flex size-7 items-center justify-center rounded-lg bg-primary/10 text-primary"> <span className="position-roundtable-agent-avatar flex size-7 items-center justify-center rounded-lg bg-primary/10 text-primary">
{node.status === "locked" ? <LockKeyhole className="size-3.5" /> : <Bot className="size-4" />} {node.status === "locked" ? <LockKeyhole className="size-3.5" /> : <Bot className="size-4" />}
</span> </span>
<div className="min-w-0 flex-1"> <div className="position-roundtable-agent-title min-w-0 flex-1">
<h2 className="truncate text-sm font-extrabold text-slate-900 dark:text-[#e8edf5]"> <h2 className="truncate text-sm font-extrabold text-slate-900 dark:text-[#e8edf5]">
{agentDisplayName} {agentDisplayName}
</h2> </h2>
@@ -742,7 +742,7 @@ export function PositionNodeChat({
</header> </header>
{nodeArtifacts.length > 0 && ( {nodeArtifacts.length > 0 && (
<section className="shrink-0 border-b border-slate-100 bg-slate-50/70 px-4 py-2.5 dark:border-[#2b8ffe]/20 dark:bg-[#032650]/50"> <section className="position-roundtable-agent-artifacts shrink-0 border-b border-slate-100 bg-slate-50/70 px-4 py-2.5 dark:border-[#2b8ffe]/20 dark:bg-[#032650]/50">
<div className="mb-1.5 flex items-center gap-1.5 text-[11px] font-semibold text-slate-600 dark:text-[#c5cfe0]"> <div className="mb-1.5 flex items-center gap-1.5 text-[11px] font-semibold text-slate-600 dark:text-[#c5cfe0]">
<FileText className="size-3.5 text-primary" /> <FileText className="size-3.5 text-primary" />
节点产物 节点产物
@@ -778,7 +778,7 @@ export function PositionNodeChat({
{boundThreadId || recoveredMessages.length > 0 ? ( {boundThreadId || recoveredMessages.length > 0 ? (
<MessageList <MessageList
className="min-h-0 flex-1" className="position-roundtable-agent-message-list min-h-0 flex-1"
threadId={boundThreadId ?? displayThreadId} threadId={boundThreadId ?? displayThreadId}
thread={displayThread} thread={displayThread}
paddingBottom={24} paddingBottom={24}
@@ -811,7 +811,7 @@ export function PositionNodeChat({
</div> </div>
)} )}
<div className="shrink-0 border-t border-slate-100 px-4 py-3 dark:border-[#2b8ffe]/20"> <div className="position-roundtable-agent-composer-bar shrink-0 border-t border-slate-100 px-4 py-3 dark:border-[#2b8ffe]/20">
<PositionAgentInput <PositionAgentInput
className="w-full" className="w-full"
isNewThread={!boundThreadId} isNewThread={!boundThreadId}
@@ -76,6 +76,8 @@ import { listChains } from "@/roundtable-planning/api/chains";
import { Step1Panel } from "@/roundtable-planning/components/Step1Panel"; import { Step1Panel } from "@/roundtable-planning/components/Step1Panel";
import { PositionIntentInput } from "@/position-roundtable/components/PositionIntentInput"; import { PositionIntentInput } from "@/position-roundtable/components/PositionIntentInput";
import { PositionNodeChat } from "@/position-roundtable/components/PositionNodeChat"; import { PositionNodeChat } from "@/position-roundtable/components/PositionNodeChat";
import "@/position-roundtable/styles/intent-understanding.css";
import "@/position-roundtable/styles/agent-analysis.css";
import { getAvatar } from "@/roundtable-planning/components/Avatars"; import { getAvatar } from "@/roundtable-planning/components/Avatars";
import { import {
useStep1Intent, useStep1Intent,
@@ -2109,7 +2111,7 @@ export default function PositionRoundtablePage({
[closeSandbox, searchParamsString, setSearchParams], [closeSandbox, searchParamsString, setSearchParams],
); );
const renderIntentChatPanel = (chainStarted: boolean) => ( const renderIntentChatPanel = (chainStarted: boolean) => (
<div className="contents"> <div className="position-roundtable-intent-page contents">
{intent.intentInitError && ( {intent.intentInitError && (
<div className="flex shrink-0 items-center justify-between gap-3 border-b border-amber-200 bg-amber-50 px-4 py-2 text-xs text-amber-800 dark:border-amber-900/60 dark:bg-amber-950/30 dark:text-amber-200"> <div className="flex shrink-0 items-center justify-between gap-3 border-b border-amber-200 bg-amber-50 px-4 py-2 text-xs text-amber-800 dark:border-amber-900/60 dark:bg-amber-950/30 dark:text-amber-200">
<span className="line-clamp-2">对话初始化失败:{intent.intentInitError}</span> <span className="line-clamp-2">对话初始化失败:{intent.intentInitError}</span>
@@ -2121,6 +2123,7 @@ export default function PositionRoundtablePage({
{/* Step1Panel retains intent state; only the composer is replaced so this {/* Step1Panel retains intent state; only the composer is replaced so this
workspace can evolve its visual language without changing other Step 1 pages. */} workspace can evolve its visual language without changing other Step 1 pages. */}
<Step1Panel <Step1Panel
rootClassName="position-roundtable-intent-panel"
headerLeftSlot={ headerLeftSlot={
<div className="flex min-w-0 items-center gap-2"> <div className="flex min-w-0 items-center gap-2">
<MessageSquareText className="size-4 text-primary" /> <MessageSquareText className="size-4 text-primary" />
@@ -0,0 +1,75 @@
/*
* 岗位会商 - 其他岗位智能体分析页面专属样式
*
* 覆盖范围:
* - 普通业务链节点:PositionNodeChat
* - 内置收口节点:PositionBuiltinAgentChat(方案总结 / 行动规划)
*
* 后续如果要调岗位智能体聊天页、产物条、输入区,优先改这个文件。
*/
.position-roundtable-agent-analysis-page {
--prt-agent-panel-bg: #ffffff;
--prt-agent-header-bg: #ffffff;
--prt-agent-header-border: rgb(241 245 249);
--prt-agent-artifact-bg: rgba(248, 250, 252, 0.72);
--prt-agent-composer-bg: #ffffff;
--prt-agent-border: rgb(241 245 249);
--prt-agent-title-color: rgb(15 23 42);
--prt-agent-muted-color: rgb(100 116 139);
--prt-agent-avatar-bg: rgba(245, 34, 45, 0.1);
--prt-agent-avatar-color: var(--primary);
}
.dark .position-roundtable-agent-analysis-page {
--prt-agent-panel-bg: rgba(3, 38, 80, 0.62);
--prt-agent-header-bg: rgba(3, 38, 80, 0.74);
--prt-agent-header-border: rgba(43, 143, 254, 0.2);
--prt-agent-artifact-bg: rgba(3, 38, 80, 0.5);
--prt-agent-composer-bg: rgba(3, 38, 80, 0.64);
--prt-agent-border: rgba(43, 143, 254, 0.2);
--prt-agent-title-color: #e8edf5;
--prt-agent-muted-color: #8aa0c4;
--prt-agent-avatar-bg: rgba(43, 143, 254, 0.16);
--prt-agent-avatar-color: #73c8ff;
}
.position-roundtable-agent-analysis-page {
background: var(--prt-agent-panel-bg);
}
.position-roundtable-agent-header {
border-color: var(--prt-agent-header-border);
background: var(--prt-agent-header-bg);
}
.position-roundtable-agent-avatar {
background: var(--prt-agent-avatar-bg);
color: var(--prt-agent-avatar-color);
}
.position-roundtable-agent-title h2 {
color: var(--prt-agent-title-color);
}
.position-roundtable-agent-title p {
color: var(--prt-agent-muted-color);
}
.position-roundtable-agent-artifacts {
border-color: var(--prt-agent-border);
background: var(--prt-agent-artifact-bg);
}
.position-roundtable-agent-message-list {
background: var(--prt-agent-panel-bg);
}
.position-roundtable-agent-composer-bar {
border-color: var(--prt-agent-border);
background: var(--prt-agent-composer-bg);
}
.position-roundtable-agent-input {
--prt-agent-input-radius: 14px;
}
@@ -0,0 +1,71 @@
/*
* 岗位会商 - 意图理解页面专属样式
*
* 这个文件只服务 `PositionRoundtablePage` 里的意图理解区域。
* 后续手写样式优先改这里,尽量不要再往 globals.css 或组件 className 里堆。
*/
.position-roundtable-intent-page {
--prt-intent-panel-bg: #ffffff;
--prt-intent-panel-border: rgb(226 232 240);
--prt-intent-composer-bg: #f7faff;
--prt-intent-composer-frame-bg: #ffffff;
--prt-intent-composer-border: rgb(203 213 225);
--prt-intent-toolbar-bg: #ffffff;
--prt-intent-text-color: rgb(51 65 85);
--prt-intent-muted-color: rgb(100 116 139);
--prt-intent-radius: 4px;
}
.dark .position-roundtable-intent-page {
--prt-intent-panel-bg: rgba(3, 38, 80, 0.72);
--prt-intent-panel-border: rgba(43, 143, 254, 0.28);
--prt-intent-composer-bg: #071a38;
--prt-intent-composer-frame-bg: #0d2855;
--prt-intent-composer-border: rgba(43, 143, 254, 0.55);
--prt-intent-toolbar-bg: #0b234c;
--prt-intent-text-color: #e7f0ff;
--prt-intent-muted-color: #8aa0c4;
}
.position-roundtable-intent-panel {
background: var(--prt-intent-panel-bg);
}
.position-roundtable-intent-panel > div:first-child {
border-color: var(--prt-intent-panel-border);
}
.position-roundtable-intent-panel > div:nth-child(2) > div:first-child {
background: var(--prt-intent-panel-bg);
}
.position-roundtable-intent-composer {
background: var(--prt-intent-composer-bg);
}
.position-roundtable-intent-composer-frame {
border-color: var(--prt-intent-composer-border);
border-radius: var(--prt-intent-radius);
background: var(--prt-intent-composer-frame-bg);
}
.position-roundtable-intent-textarea {
color: var(--prt-intent-text-color);
}
.position-roundtable-intent-toolbar {
background: var(--prt-intent-toolbar-bg);
}
.position-roundtable-intent-attachments {
color: var(--prt-intent-muted-color);
}
.position-roundtable-intent-actions {
row-gap: 6px;
}
.position-roundtable-intent-model-switch {
border-radius: var(--prt-intent-radius);
}
@@ -95,6 +95,7 @@ export interface Step1InputAreaProps {
} }
export interface Step1PanelProps { export interface Step1PanelProps {
rootClassName?: string;
// ─── State ──────────────────────────────────────────────────── // ─── State ────────────────────────────────────────────────────
/** /**
* 头部左侧自定义内容(深链 taskId 模式:用「策划流程」小图取代默认标题)。 * 头部左侧自定义内容(深链 taskId 模式:用「策划流程」小图取代默认标题)。
@@ -145,6 +146,7 @@ export function Step1Panel(props: Step1PanelProps) {
const { const {
headerLeftSlot, headerLeftSlot,
headerRightSlot, headerRightSlot,
rootClassName,
interactiveMessages, interactiveMessages,
intentThreadId, intentThreadId,
intentReady, intentReady,
@@ -230,7 +232,7 @@ export function Step1Panel(props: Step1PanelProps) {
const headerDzRef = useDesensitizeSubtree<HTMLDivElement>(); const headerDzRef = useDesensitizeSubtree<HTMLDivElement>();
return ( return (
<div className="flex-1 flex flex-col min-h-0"> <div className={`flex-1 flex flex-col min-h-0 ${rootClassName ?? ""}`}>
{/* Dialogue Header */} {/* Dialogue Header */}
<div ref={headerDzRef} className="shrink-0 px-6 py-4.5 border-b border-slate-100 flex items-center justify-between gap-3 bg-slate-50/50"> <div ref={headerDzRef} className="shrink-0 px-6 py-4.5 border-b border-slate-100 flex items-center justify-between gap-3 bg-slate-50/50">
{headerLeftSlot ?? ( {headerLeftSlot ?? (