diff options
Diffstat (limited to 'extension/react-app/src/components')
| -rw-r--r-- | extension/react-app/src/components/CodeBlock.tsx | 4 | ||||
| -rw-r--r-- | extension/react-app/src/components/ComboBox.tsx | 191 | ||||
| -rw-r--r-- | extension/react-app/src/components/ContinueButton.tsx | 2 | ||||
| -rw-r--r-- | extension/react-app/src/components/HeaderButtonWithText.tsx | 44 | ||||
| -rw-r--r-- | extension/react-app/src/components/Loader.tsx | 40 | ||||
| -rw-r--r-- | extension/react-app/src/components/PillButton.tsx | 144 | ||||
| -rw-r--r-- | extension/react-app/src/components/StepContainer.tsx | 13 | ||||
| -rw-r--r-- | extension/react-app/src/components/TextDialog.tsx | 2 | ||||
| -rw-r--r-- | extension/react-app/src/components/UserInputContainer.tsx | 6 | ||||
| -rw-r--r-- | extension/react-app/src/components/index.ts | 22 | 
10 files changed, 304 insertions, 164 deletions
| diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx index 17f5626b..fe9b3a95 100644 --- a/extension/react-app/src/components/CodeBlock.tsx +++ b/extension/react-app/src/components/CodeBlock.tsx @@ -52,9 +52,9 @@ function CopyButton(props: { textToCopy: string; visible: boolean }) {          }}        >          {clicked ? ( -          <CheckCircle color="#00ff00" size="1.4em" /> +          <CheckCircle color="#00ff00" size="1.5em" />          ) : ( -          <Clipboard color={hovered ? "#00ff00" : "white"} size="1.4em" /> +          <Clipboard color={hovered ? "#00ff00" : "white"} size="1.5em" />          )}        </StyledCopyButton>      </> diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index 81b148b9..7ee5dc24 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -4,6 +4,7 @@ import styled from "styled-components";  import {    buttonColor,    defaultBorderRadius, +  lightGray,    secondaryDark,    vscBackground,  } from "."; @@ -16,11 +17,32 @@ import {    LockClosed,    LockOpen,    Plus, +  DocumentPlus,  } from "@styled-icons/heroicons-outline"; +import { HighlightedRangeContext } from "../../../schema/FullState";  // #region styled components  const mainInputFontSize = 16; +const EmptyPillDiv = styled.div` +  padding: 8px; +  border-radius: ${defaultBorderRadius}; +  border: 1px dashed ${lightGray}; +  color: ${lightGray}; +  background-color: ${vscBackground}; +  overflow: hidden; +  display: flex; +  align-items: center; +  text-align: center; +  cursor: pointer; +  font-size: 13px; + +  &:hover { +    background-color: ${lightGray}; +    color: ${vscBackground}; +  } +`; +  const ContextDropdown = styled.div`    position: absolute;    padding: 4px; @@ -41,17 +63,19 @@ const MainTextInput = styled.textarea`    padding: 8px;    font-size: ${mainInputFontSize}px; +  font-family: inherit; +  border: 1px solid transparent;    border-radius: ${defaultBorderRadius}; -  border: 1px solid white;    margin: 8px auto; +  height: auto;    width: 100%; -  background-color: ${vscBackground}; +  background-color: ${secondaryDark};    color: white;    z-index: 1;    &:focus { +    outline: 1px solid #ff000066;      border: 1px solid transparent; -    outline: 1px solid orange;    }  `; @@ -69,7 +93,6 @@ const Ul = styled.ul<{    background: ${vscBackground};    background-color: ${secondaryDark};    color: white; -  font-family: "Fira Code", monospace;    max-height: ${UlMaxHeight}px;    overflow: scroll;    padding: 0; @@ -102,7 +125,7 @@ interface ComboBoxProps {    onInputValueChange: (inputValue: string) => void;    disabled?: boolean;    onEnter: (e: React.KeyboardEvent<HTMLInputElement>) => void; -  highlightedCodeSections: (RangeInFile & { contents: string })[]; +  highlightedCodeSections: HighlightedRangeContext[];    deleteContextItems: (indices: number[]) => void;    onTogglePin: () => void;    onToggleAddContext: () => void; @@ -119,16 +142,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {      React.useState(false);    const [pinned, setPinned] = useState(false);    const [highlightedCodeSections, setHighlightedCodeSections] = React.useState( -    props.highlightedCodeSections || [ -      { -        filepath: "test.ts", -        range: { -          start: { line: 0, character: 0 }, -          end: { line: 0, character: 0 }, -        }, -        contents: "import * as a from 'a';", -      }, -    ] +    props.highlightedCodeSections || []    );    useEffect(() => { @@ -169,6 +183,71 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {    return (      <> +      <div className="px-2 flex gap-2 items-center flex-wrap mt-2"> +        {highlightedCodeSections.length > 1 && ( +          <> +            <HeaderButtonWithText +              text="Clear Context" +              onClick={() => { +                props.deleteContextItems( +                  highlightedCodeSections.map((_, idx) => idx) +                ); +              }} +            > +              <Trash size="1.6em" /> +            </HeaderButtonWithText> +          </> +        )} +        {highlightedCodeSections.map((section, idx) => ( +          <PillButton +            editing={section.editing} +            pinned={section.pinned} +            index={idx} +            key={`${section.filepath}${idx}`} +            title={`${section.range.filepath} (${ +              section.range.range.start.line + 1 +            }-${section.range.range.end.line + 1})`} +            onDelete={() => { +              if (props.deleteContextItems) { +                props.deleteContextItems([idx]); +              } +              setHighlightedCodeSections((prev) => { +                const newSections = [...prev]; +                newSections.splice(idx, 1); +                return newSections; +              }); +            }} +            onHover={(val: boolean) => { +              if (val) { +                setHoveringButton(val); +              } else { +                setTimeout(() => { +                  setHoveringButton(val); +                }, 100); +              } +            }} +          /> +        ))} +        {props.highlightedCodeSections.length > 0 && +          (props.addingHighlightedCode ? ( +            <EmptyPillDiv +              onClick={() => { +                props.onToggleAddContext(); +              }} +            > +              Highlight to Add Context +            </EmptyPillDiv> +          ) : ( +            <HeaderButtonWithText +              text="Add to Context" +              onClick={() => { +                props.onToggleAddContext(); +              }} +            > +              <DocumentPlus width="1.6em"></DocumentPlus> +            </HeaderButtonWithText> +          ))} +      </div>        <div className="flex px-2" ref={divRef} hidden={!isOpen}>          <MainTextInput            disabled={props.disabled} @@ -260,80 +339,10 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {              ))}          </Ul>        </div> -      <div className="px-2 flex gap-2 items-center flex-wrap"> -        {highlightedCodeSections.length === 0 && ( -          <HeaderButtonWithText -            text={ -              props.addingHighlightedCode ? "Adding Context" : "Add Context" -            } -            onClick={() => { -              props.onToggleAddContext(); -            }} -            inverted={props.addingHighlightedCode} -          > -            <Plus size="1.6em" /> -          </HeaderButtonWithText> -        )} -        {highlightedCodeSections.length > 0 && ( -          <> -            <HeaderButtonWithText -              text="Clear Context" -              onClick={() => { -                props.deleteContextItems( -                  highlightedCodeSections.map((_, idx) => idx) -                ); -              }} -            > -              <Trash size="1.6em" /> -            </HeaderButtonWithText> -            <HeaderButtonWithText -              text={pinned ? "Unpin Context" : "Pin Context"} -              inverted={pinned} -              onClick={() => { -                setPinned((prev) => !prev); -                props.onTogglePin(); -              }} -            > -              {pinned ? ( -                <LockClosed size="1.6em"></LockClosed> -              ) : ( -                <LockOpen size="1.6em"></LockOpen> -              )} -            </HeaderButtonWithText> -          </> -        )} -        {highlightedCodeSections.map((section, idx) => ( -          <PillButton -            title={`${section.filepath} (${section.range.start.line + 1}-${ -              section.range.end.line + 1 -            })`} -            onDelete={() => { -              if (props.deleteContextItems) { -                props.deleteContextItems([idx]); -              } -              setHighlightedCodeSections((prev) => { -                const newSections = [...prev]; -                newSections.splice(idx, 1); -                return newSections; -              }); -            }} -            onHover={(val: boolean) => { -              if (val) { -                setHoveringButton(val); -              } else { -                setTimeout(() => { -                  setHoveringButton(val); -                }, 100); -              } -            }} -          /> -        ))} - -        <span className="text-trueGray-400 ml-auto mr-4 text-xs text-right"> -          Highlight code to include as context. Currently open file included by -          default. {highlightedCodeSections.length === 0 && ""} -        </span> -      </div> +      {/* <span className="text-trueGray-400 ml-auto m-auto text-xs text-right"> +        Highlight code to include as context. Currently open file included by +        default. {highlightedCodeSections.length === 0 && ""} +      </span> */}        <ContextDropdown          onMouseEnter={() => {            setHoveringContextDropdown(true); @@ -345,9 +354,9 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => {        >          {highlightedCodeSections.map((section, idx) => (            <> -            <p>{section.filepath}</p> +            <p>{section.range.filepath}</p>              <CodeBlock showCopy={false} key={idx}> -              {section.contents} +              {section.range.contents}              </CodeBlock>            </>          ))} diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx index 5295799a..462f2b46 100644 --- a/extension/react-app/src/components/ContinueButton.tsx +++ b/extension/react-app/src/components/ContinueButton.tsx @@ -18,7 +18,7 @@ let StyledButton = styled(Button)`    &:hover {      transition-delay: 0.5s; -    transition-property: background; +    transition-property: "background";      background: linear-gradient(        45deg,        #be1a55 14.44%, diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx index 72a653c5..de8e3c98 100644 --- a/extension/react-app/src/components/HeaderButtonWithText.tsx +++ b/extension/react-app/src/components/HeaderButtonWithText.tsx @@ -1,6 +1,7 @@  import React, { useState } from "react"; - -import { HeaderButton } from "."; +import { Tooltip } from "react-tooltip"; +import styled from "styled-components"; +import { HeaderButton, StyledTooltip, defaultBorderRadius } from ".";  interface HeaderButtonWithTextProps {    text: string; @@ -13,25 +14,28 @@ interface HeaderButtonWithTextProps {  const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => {    const [hover, setHover] = useState(false); -  const paddingLeft = (props.disabled ? (props.active ?  "3px" : "1px"): (hover ? "4px" : "1px"));    return ( -    <HeaderButton -      inverted={props.inverted} -      disabled={props.disabled} -      style={{ padding: (props.active ?  "3px" : "1px"), paddingLeft, borderRadius: (props.active ?  "50%" : undefined) }} -      onMouseEnter={() => { -        if (!props.disabled) { -          setHover(true); -        } -      }} -      onMouseLeave={() => { -        setHover(false); -      }} -      onClick={props.onClick} -    > -      <span hidden={!hover}>{props.text}</span> -      {props.children} -    </HeaderButton> +    <> +      <HeaderButton +        data-tooltip-id={`header_button_${props.text}`} +        inverted={props.inverted} +        disabled={props.disabled} +        onMouseEnter={() => { +          if (!props.disabled) { +            setHover(true); +          } +        }} +        onMouseLeave={() => { +          setHover(false); +        }} +        onClick={props.onClick} +      > +        {props.children} +      </HeaderButton> +      <StyledTooltip id={`header_button_${props.text}`} place="bottom"> +        {props.text} +      </StyledTooltip> +    </>    );  }; diff --git a/extension/react-app/src/components/Loader.tsx b/extension/react-app/src/components/Loader.tsx new file mode 100644 index 00000000..90eff793 --- /dev/null +++ b/extension/react-app/src/components/Loader.tsx @@ -0,0 +1,40 @@ +import { Play } from "@styled-icons/heroicons-outline"; +import { useSelector } from "react-redux"; +import styled from "styled-components"; +import { RootStore } from "../redux/store"; + +const DEFAULT_SIZE = "28px"; + +const FlashingDiv = styled.div` +  margin: auto; +  width: ${DEFAULT_SIZE}; +  animation: flash 1.2s infinite ease-in-out; +  @keyframes flash { +    0% { +      opacity: 0.4; +    } +    50% { +      opacity: 1; +    } +    100% { +      opacity: 0.4; +    } +  } +`; + +function Loader(props: { size?: string }) { +  const vscMediaUrl = useSelector( +    (state: RootStore) => state.config.vscMediaUrl +  ); +  return ( +    <FlashingDiv> +      {vscMediaUrl ? ( +        <img src={`${vscMediaUrl}/play_button.png`} width="22px" /> +      ) : ( +        <Play width={props.size || DEFAULT_SIZE} /> +      )} +    </FlashingDiv> +  ); +} + +export default Loader; diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx index 5a02c6b2..a384832e 100644 --- a/extension/react-app/src/components/PillButton.tsx +++ b/extension/react-app/src/components/PillButton.tsx @@ -1,54 +1,136 @@ -import { useState } from "react"; +import { useContext, useState } from "react";  import styled from "styled-components"; -import { defaultBorderRadius } from "."; -import { XMark } from "@styled-icons/heroicons-outline"; +import { +  StyledTooltip, +  defaultBorderRadius, +  lightGray, +  secondaryDark, +} from "."; +import { Trash, PaintBrush, MapPin } from "@styled-icons/heroicons-outline"; +import { GUIClientContext } from "../App";  const Button = styled.button`    border: none;    color: white; -  background-color: transparent; -  border: 1px solid white; +  background-color: ${secondaryDark};    border-radius: ${defaultBorderRadius}; -  padding: 3px 6px; +  padding: 8px; +  overflow: hidden; + +  cursor: pointer; +`; + +const GridDiv = styled.div` +  position: absolute; +  left: 0px; +  top: 0px; +  width: 100%; +  height: 100%; +  display: grid; +  grid-gap: 0; +  grid-template-columns: 1fr 1fr; +  align-items: center; +  border-radius: ${defaultBorderRadius}; +  overflow: hidden; + +  background-color: ${secondaryDark}; +`; + +const ButtonDiv = styled.div<{ backgroundColor: string }>` +  background-color: ${secondaryDark}; +  padding: 3px; +  height: 100%; +  display: flex; +  align-items: center;    &:hover { -    background-color: white; -    color: black; +    background-color: ${(props) => props.backgroundColor};    } - -  cursor: pointer;  `;  interface PillButtonProps {    onHover?: (arg0: boolean) => void;    onDelete?: () => void;    title: string; +  index: number; +  editing: boolean; +  pinned: boolean;  }  const PillButton = (props: PillButtonProps) => {    const [isHovered, setIsHovered] = useState(false); +  const client = useContext(GUIClientContext); +    return ( -    <Button -      onMouseEnter={() => { -        setIsHovered(true); -        if (props.onHover) { -          props.onHover(true); -        } -      }} -      onMouseLeave={() => { -        setIsHovered(false); -        if (props.onHover) { -          props.onHover(false); -        } -      }} -      onClick={() => { -        if (props.onDelete) { -          props.onDelete(); -        } -      }} -    > -      {props.title} -    </Button> +    <> +      <Button +        style={{ +          position: "relative", +          borderColor: props.editing +            ? "#8800aa" +            : props.pinned +            ? "#ffff0099" +            : "transparent", +          borderWidth: "1px", +          borderStyle: "solid", +        }} +        onMouseEnter={() => { +          setIsHovered(true); +          if (props.onHover) { +            props.onHover(true); +          } +        }} +        onMouseLeave={() => { +          setIsHovered(false); +          if (props.onHover) { +            props.onHover(false); +          } +        }} +      > +        {isHovered && ( +          <GridDiv> +            <ButtonDiv +              data-tooltip-id={`edit-${props.index}`} +              backgroundColor={"#8800aa55"} +              onClick={() => { +                client?.setEditingAtIndices([props.index]); +              }} +            > +              <PaintBrush style={{ margin: "auto" }} width="1.6em"></PaintBrush> +            </ButtonDiv> + +            {/* <ButtonDiv +            data-tooltip-id={`pin-${props.index}`} +            backgroundColor={"#ffff0055"} +            onClick={() => { +              client?.setPinnedAtIndices([props.index]); +            }} +          > +            <MapPin style={{ margin: "auto" }} width="1.6em"></MapPin> +          </ButtonDiv> */} +            <StyledTooltip id={`pin-${props.index}`}> +              Edit this range +            </StyledTooltip> +            <ButtonDiv +              data-tooltip-id={`delete-${props.index}`} +              backgroundColor={"#cc000055"} +              onClick={() => { +                if (props.onDelete) { +                  props.onDelete(); +                } +              }} +            > +              <Trash style={{ margin: "auto" }} width="1.6em"></Trash> +            </ButtonDiv> +          </GridDiv> +        )} +        {props.title} +      </Button> +      <StyledTooltip id={`edit-${props.index}`}> +        {props.editing ? "Editing this range" : "Edit this range"} +      </StyledTooltip> +      <StyledTooltip id={`delete-${props.index}`}>Delete</StyledTooltip> +    </>    );  }; diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index 2aed2e72..91d7b8ef 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -13,7 +13,7 @@ import {    ArrowPath,    XMark,  } from "@styled-icons/heroicons-outline"; -import { Stop } from "@styled-icons/heroicons-solid"; +import { StopCircle } from "@styled-icons/heroicons-solid";  import { HistoryNode } from "../../../schema/HistoryNode";  import ReactMarkdown from "react-markdown";  import HeaderButtonWithText from "./HeaderButtonWithText"; @@ -67,7 +67,6 @@ const HeaderDiv = styled.div<{ error: boolean; loading: boolean }>`  const ContentDiv = styled.div<{ isUserInput: boolean }>`    padding: 8px; -  padding-left: 16px;    background-color: ${(props) =>      props.isUserInput ? secondaryDark : vscBackground};    font-size: 13px; @@ -167,7 +166,7 @@ function StepContainer(props: StepContainerProps) {                ? "#f00"                : props.historyNode.active                ? undefined -              : "white" +              : "transparent"            }            className="overflow-hidden cursor-pointer"            onClick={(e) => { @@ -182,7 +181,7 @@ function StepContainer(props: StepContainerProps) {              loading={props.historyNode.active as boolean | false}              error={props.historyNode.observation?.error ? true : false}            > -            <h4 className="m-2"> +            <div className="m-2">                {!isUserInput &&                  (props.open ? (                    <ChevronDown size="1.4em" /> @@ -191,7 +190,7 @@ function StepContainer(props: StepContainerProps) {                  ))}                {props.historyNode.observation?.title ||                  (props.historyNode.step.name as any)} -            </h4> +            </div>              {/* <HeaderButton                onClick={(e) => {                  e.stopPropagation(); @@ -203,16 +202,14 @@ function StepContainer(props: StepContainerProps) {              <>                <HeaderButtonWithText -                disabled={props.historyNode.active as boolean}                  onClick={(e) => {                    e.stopPropagation();                    props.onDelete();                  }}                  text={props.historyNode.active ? "Stop" : "Delete"} -                active={props.historyNode.active}                >                  {props.historyNode.active ? ( -                  <Stop size="1.2em" onClick={props.onDelete} /> +                  <StopCircle size="1.6em" onClick={props.onDelete} />                  ) : (                    <XMark size="1.6em" onClick={props.onDelete} />                  )} diff --git a/extension/react-app/src/components/TextDialog.tsx b/extension/react-app/src/components/TextDialog.tsx index a564f884..ea5727f0 100644 --- a/extension/react-app/src/components/TextDialog.tsx +++ b/extension/react-app/src/components/TextDialog.tsx @@ -8,6 +8,7 @@ const ScreenCover = styled.div`    width: 100%;    height: 100%;    background-color: rgba(168, 168, 168, 0.5); +  z-index: 100;  `;  const DialogContainer = styled.div` @@ -35,7 +36,6 @@ const TextArea = styled.textarea`    border-radius: 8px;    padding: 8px;    outline: 1px solid black; -  font-family: Arial, Helvetica, sans-serif;    resize: none;    &:focus { diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx index 28437d35..f51f0cb5 100644 --- a/extension/react-app/src/components/UserInputContainer.tsx +++ b/extension/react-app/src/components/UserInputContainer.tsx @@ -15,12 +15,10 @@ interface UserInputContainerProps {  }  const StyledDiv = styled.div` -  background-color: rgb(45 45 45); +  background-color: ${secondaryDark};    padding: 8px;    padding-left: 16px;    padding-right: 16px; -  border-bottom: 1px solid white; -  border-top: 1px solid white;    font-size: 13px;    display: flex;    align-items: center; @@ -29,7 +27,7 @@ const StyledDiv = styled.div`  const UserInputContainer = (props: UserInputContainerProps) => {    return (      <StyledDiv> -      <b>{props.children}</b> +      {props.children}        <div style={{ marginLeft: "auto" }}>          <HeaderButtonWithText            onClick={(e) => { diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts index db1925ed..9ae0f097 100644 --- a/extension/react-app/src/components/index.ts +++ b/extension/react-app/src/components/index.ts @@ -1,7 +1,9 @@ +import { Tooltip } from "react-tooltip";  import styled, { keyframes } from "styled-components";  export const defaultBorderRadius = "5px"; -export const secondaryDark = "rgb(42 42 42)"; +export const lightGray = "rgb(100 100 100)"; +export const secondaryDark = "rgb(45 45 45)";  export const vscBackground = "rgb(30 30 30)";  export const vscBackgroundTransparent = "#1e1e1ede";  export const buttonColor = "rgb(113 28 59)"; @@ -26,6 +28,16 @@ export const Button = styled.button`    }  `; +export const StyledTooltip = styled(Tooltip)` +  font-size: 12px; +  background-color: rgb(60 60 60); +  border-radius: ${defaultBorderRadius}; +  padding: 6px; +  padding-left: 12px; +  padding-right: 12px; +  z-index: 100; +`; +  export const TextArea = styled.textarea`    width: 100%;    border-radius: ${defaultBorderRadius}; @@ -128,19 +140,17 @@ export const HeaderButton = styled.button<{ inverted: boolean | undefined }>`    background-color: ${({ inverted }) => (inverted ? "white" : "transparent")};    color: ${({ inverted }) => (inverted ? "black" : "white")}; -  border: 1px solid white; +  border: none;    border-radius: ${defaultBorderRadius};    cursor: pointer;    &:hover {      background-color: ${({ inverted }) => -      typeof inverted === "undefined" || inverted ? "white" : "transparent"}; -    color: ${({ inverted }) => -      typeof inverted === "undefined" || inverted ? "black" : "white"}; +      typeof inverted === "undefined" || inverted ? lightGray : "transparent"};    }    display: flex;    align-items: center;    justify-content: center;    gap: 4px; -  padding: 1px; +  padding: 2px;  `; | 
