feat: add position prop to ClaudeLogsSection for flexible rendering

- Introduced an optional `position` prop to the ClaudeLogsSection component, allowing it to be rendered in either 'sidebar' or 'inline' formats.
- Updated the TeamDetailView to utilize the new `position` prop, ensuring consistent layout in the sidebar.
- Enhanced styling in ClaudeLogsSection to adapt based on the position, improving overall UI consistency and user experience.
This commit is contained in:
iliya 2026-03-13 18:23:42 +02:00
parent b76be0f634
commit daae1ba82b
3 changed files with 18 additions and 7 deletions

View file

@ -22,6 +22,7 @@ type StreamType = 'stdout' | 'stderr';
interface ClaudeLogsSectionProps {
teamName: string;
position?: 'sidebar' | 'inline';
}
function isRecent(updatedAt: string | undefined): boolean {
@ -367,7 +368,10 @@ function filterStreamJsonText(
return out.join('\n');
}
export const ClaudeLogsSection = ({ teamName }: ClaudeLogsSectionProps): React.JSX.Element => {
export const ClaudeLogsSection = ({
teamName,
position = 'inline',
}: ClaudeLogsSectionProps): React.JSX.Element => {
const isAlive = useStore((s) => s.selectedTeamData?.isAlive ?? false);
const [loadedCount, setLoadedCount] = useState(PAGE_SIZE);
const [data, setData] = useState<TeamClaudeLogsResponse>({ lines: [], total: 0, hasMore: false });
@ -390,6 +394,7 @@ export const ClaudeLogsSection = ({ teamName }: ClaudeLogsSectionProps): React.J
kinds: new Set(DEFAULT_CLAUDE_LOGS_FILTER.kinds),
}));
const [filterOpen, setFilterOpen] = useState(false);
const isSidebar = position === 'sidebar';
const isNearBottom = useCallback(
(scrollTop: number, scrollHeight: number, clientHeight: number) => {
return scrollHeight - scrollTop - clientHeight <= LOAD_MORE_THRESHOLD_PX;
@ -571,10 +576,15 @@ export const ClaudeLogsSection = ({ teamName }: ClaudeLogsSectionProps): React.J
<CollapsibleTeamSection
sectionId="claude-logs"
title="Claude logs"
icon={<Terminal size={14} />}
icon={
<span className="inline-flex h-5 w-5 items-center justify-center rounded-md border border-[var(--color-border)] bg-[var(--color-bg-secondary)] text-[var(--color-text-secondary)] shadow-sm">
<Terminal size={12} />
</span>
}
badge={badge}
headerContentClassName={isSidebar ? 'flex-wrap items-center gap-y-1 py-1' : undefined}
headerExtra={
<>
<span className={cn('flex min-w-0 items-center gap-2', isSidebar && 'basis-full pt-0.5')}>
{online ? (
<span
className="pointer-events-none relative inline-flex size-2 shrink-0"
@ -585,7 +595,7 @@ export const ClaudeLogsSection = ({ teamName }: ClaudeLogsSectionProps): React.J
</span>
) : null}
{lastLogPreview ? <LogPreviewInline preview={lastLogPreview} /> : null}
</>
</span>
}
defaultOpen={false}
// Prevent scroll anchoring from "pulling" the parent container when logs update.

View file

@ -964,9 +964,10 @@ export const TeamDetailView = ({ teamName }: TeamDetailViewProps): React.JSX.Ele
>
<div className="flex size-full min-h-0 flex-col overflow-hidden bg-[var(--color-surface)]">
<div className="shrink-0 overflow-hidden px-3">
<ClaudeLogsSection teamName={teamName} />
<ClaudeLogsSection teamName={teamName} position="sidebar" />
</div>
<div className="min-h-0 flex-1 border-t border-[var(--color-border)]">
<div className="bg-[var(--color-text-muted)]/35 mx-3 h-px shrink-0" />
<div className="min-h-0 flex-1">
<MessagesPanel
teamName={teamName}
position="sidebar"

View file

@ -366,7 +366,7 @@ export const MessagesPanel = ({
return (
<div className="flex size-full flex-col overflow-hidden bg-[var(--color-surface)]">
{/* Header */}
<div className="flex shrink-0 items-center gap-2 border-b border-[var(--color-border)] px-3 py-2">
<div className="flex shrink-0 items-center gap-2 border-b border-[var(--color-border)] bg-[var(--color-section-bg)] px-3 py-2">
<MessageSquare size={14} className="shrink-0 text-[var(--color-text-muted)]" />
<span className="text-sm font-medium text-[var(--color-text)]">Messages</span>
{filteredMessages.length > 0 && (