automagik-cli
Version:
Automagik CLI - A powerful command-line interface for interacting with Automagik Hive multi-agent AI systems
109 lines (108 loc) • 4.17 kB
JavaScript
import { useState, useEffect, useMemo } from 'react';
import { useTerminalSize } from './useTerminalSize.js';
// Breakpoint thresholds
const BREAKPOINTS = {
small: 80, // < 80 columns
medium: 120, // 80-120 columns
// large: > 120 columns
};
const HEIGHT_THRESHOLDS = {
short: 20, // < 20 rows
tall: 40, // > 40 rows
};
export const useResponsiveLayout = (options = {}) => {
const { debounceMs = 150, minInputWidth = 20, widthFraction = 0.9, } = options;
const terminalSize = useTerminalSize();
const [debouncedSize, setDebouncedSize] = useState(terminalSize);
// Debounce terminal size changes for performance
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedSize(terminalSize);
}, debounceMs);
return () => clearTimeout(timer);
}, [terminalSize, debounceMs]);
// Breakpoint detection
const breakpoint = useMemo(() => {
if (debouncedSize.columns < BREAKPOINTS.small)
return 'small';
if (debouncedSize.columns < BREAKPOINTS.medium)
return 'medium';
return 'large';
}, [debouncedSize.columns]);
// Responsive layout calculations
const layout = useMemo(() => {
const { columns: width, rows: height } = debouncedSize;
// Breakpoint flags
const isSmall = breakpoint === 'small';
const isMedium = breakpoint === 'medium';
const isLarge = breakpoint === 'large';
const isNarrow = width < BREAKPOINTS.small;
const isWide = width >= BREAKPOINTS.medium;
// Height flags
const isShort = height < HEIGHT_THRESHOLDS.short;
const isTall = height > HEIGHT_THRESHOLDS.tall;
// Content sizing based on breakpoint
let maxContentWidth;
let inputWidthCalc;
let suggestionsWidthCalc;
if (isSmall) {
// Small screens: use most of the width, minimal padding
maxContentWidth = Math.max(width - 4, 20);
inputWidthCalc = Math.max(minInputWidth, width - 8);
suggestionsWidthCalc = Math.max(30, width - 10);
}
else if (isMedium) {
// Medium screens: balanced approach
maxContentWidth = Math.floor(width * 0.85);
inputWidthCalc = Math.max(minInputWidth, Math.floor(width * widthFraction) - 3);
suggestionsWidthCalc = Math.max(50, Math.floor(width * 0.75));
}
else {
// Large screens: comfortable spacing
maxContentWidth = Math.floor(width * 0.8);
inputWidthCalc = Math.max(minInputWidth, Math.floor(width * widthFraction) - 3);
suggestionsWidthCalc = Math.max(60, Math.floor(width * 0.8));
}
// Height calculations
const headerHeight = isShort ? 1 : 2;
const footerHeight = isShort ? 1 : 2;
const maxContentHeight = Math.max(height - headerHeight - footerHeight - 2, 5);
return {
width,
height,
breakpoint,
isSmall,
isMedium,
isLarge,
isNarrow,
isWide,
isShort,
isTall,
maxContentWidth,
maxContentHeight,
inputWidth: inputWidthCalc,
suggestionsWidth: suggestionsWidthCalc,
headerHeight,
footerHeight,
};
}, [debouncedSize, breakpoint, minInputWidth, widthFraction]);
return layout;
};
// Utility function for responsive text truncation
export const useResponsiveText = (text, maxWidth, suffix = '...') => {
return useMemo(() => {
if (text.length <= maxWidth)
return text;
const truncateAt = Math.max(maxWidth - suffix.length, 1);
return text.slice(0, truncateAt) + suffix;
}, [text, maxWidth, suffix]);
};
// Utility function for responsive spacing
export const useResponsiveSpacing = (layout) => {
return useMemo(() => ({
marginX: layout.isSmall ? 0 : layout.isMedium ? 1 : 2,
marginY: layout.isShort ? 0 : 1,
paddingX: layout.isSmall ? 1 : 2,
paddingY: layout.isShort ? 0 : 1,
}), [layout]);
};