File size: 2,828 Bytes
52efc7b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import type React from 'react';
import { useMemo } from 'react';
import { Box, Text, useIsScreenReaderEnabled } from 'ink';
import { useUIState } from '../../contexts/UIStateContext.js';
import { theme } from '../../semantic-colors.js';
import { interpolateColor, resolveColor } from '../../themes/color-utils.js';
import { supportsTrueColor } from '@google/gemini-cli-core';

export interface HalfLinePaddedBoxProps {
  /**
   * The base color to blend with the terminal background.
   */
  backgroundBaseColor: string;

  /**
   * The opacity (0-1) for blending the backgroundBaseColor onto the terminal background.
   */
  backgroundOpacity: number;

  /**
   * Whether to render the solid background color.
   */
  useBackgroundColor?: boolean;

  children: React.ReactNode;
}

/**
 * A container component that renders a solid background with half-line padding
 * at the top and bottom using block characters (▀/▄).
 */
export const HalfLinePaddedBox: React.FC<HalfLinePaddedBoxProps> = (props) => {
  const isScreenReaderEnabled = useIsScreenReaderEnabled();
  if (props.useBackgroundColor === false || isScreenReaderEnabled) {
    return <>{props.children}</>;
  }

  return <HalfLinePaddedBoxInternal {...props} />;
};

const HalfLinePaddedBoxInternal: React.FC<HalfLinePaddedBoxProps> = ({
  backgroundBaseColor,
  backgroundOpacity,
  children,
}) => {
  const { terminalWidth } = useUIState();
  const terminalBg = theme.background.primary || 'black';

  const backgroundColor = useMemo(() => {
    const resolvedBase =
      resolveColor(backgroundBaseColor) || backgroundBaseColor;
    const resolvedTerminalBg = resolveColor(terminalBg) || terminalBg;

    return interpolateColor(
      resolvedTerminalBg,
      resolvedBase,
      backgroundOpacity,
    );
  }, [backgroundBaseColor, backgroundOpacity, terminalBg]);

  if (!backgroundColor) {
    return <>{children}</>;
  }

  const noTrueColor = !supportsTrueColor();

  if (noTrueColor) {
    return (
      <Box width={terminalWidth} backgroundColor={backgroundColor} paddingY={1}>
        {children}
      </Box>
    );
  }

  return (
    <Box
      width={terminalWidth}
      flexDirection="column"
      alignItems="stretch"
      minHeight={1}
      flexShrink={0}
    >
      <Box width={terminalWidth} flexDirection="row">
        <Text color={backgroundColor}>{'▄'.repeat(terminalWidth)}</Text>
      </Box>
      <Box
        width={terminalWidth}
        flexDirection="column"
        alignItems="stretch"
        backgroundColor={backgroundColor}
      >
        {children}
      </Box>
      <Box width={terminalWidth} flexDirection="row">
        <Text color={backgroundColor}>{'▀'.repeat(terminalWidth)}</Text>
      </Box>
    </Box>
  );
};