From 95363a5b52f3bf73531ac76b00178fa79ca97661 Mon Sep 17 00:00:00 2001 From: Nate Sesti <33237525+sestinj@users.noreply.github.com> Date: Thu, 28 Sep 2023 01:02:52 -0700 Subject: Past input (#513) * feat: :construction: use ComboBox in place of UserInputContainer * feat: :construction: adding context to previous inputs steps * feat: :sparkles: preview context items on click * feat: :construction: more work on context items ui * style: :construction: working out the details of ctx item buttons * feat: :sparkles: getting the final details * fix: :bug: fix height of ctx items bar * fix: :bug: last couple of details * fix: :bug: pass model param through to hf inference api * fix: :loud_sound: better logging for timeout * feat: :sparkles: option to set the meilisearch url * fix: :bug: fix height of past inputs --- extension/react-app/src/components/ComboBox.tsx | 776 +++++++++++++++------ .../src/components/ErrorStepContainer.tsx | 5 +- .../src/components/HeaderButtonWithText.tsx | 2 + extension/react-app/src/components/PillButton.tsx | 257 ++++--- .../react-app/src/components/StepContainer.tsx | 6 +- .../src/components/StyledMarkdownPreview.tsx | 12 +- extension/react-app/src/components/Suggestions.tsx | 2 + .../react-app/src/components/TimelineItem.tsx | 2 +- .../src/components/UserInputContainer.tsx | 1 - extension/react-app/src/components/index.ts | 7 +- 10 files changed, 729 insertions(+), 341 deletions(-) (limited to 'extension/react-app/src/components') diff --git a/extension/react-app/src/components/ComboBox.tsx b/extension/react-app/src/components/ComboBox.tsx index 934b7337..6c99a650 100644 --- a/extension/react-app/src/components/ComboBox.tsx +++ b/extension/react-app/src/components/ComboBox.tsx @@ -7,7 +7,7 @@ import React, { useState, } from "react"; import { useCombobox } from "downshift"; -import styled from "styled-components"; +import styled, { keyframes } from "styled-components"; import { buttonColor, defaultBorderRadius, @@ -21,8 +21,10 @@ import HeaderButtonWithText from "./HeaderButtonWithText"; import { ArrowLeftIcon, ArrowRightIcon, - MagnifyingGlassIcon, + ArrowUpLeftIcon, + StopCircleIcon, TrashIcon, + XMarkIcon, } from "@heroicons/react/24/outline"; import { postVscMessage } from "../vscode"; import { GUIClientContext } from "../App"; @@ -31,12 +33,58 @@ import { setBottomMessage } from "../redux/slices/uiStateSlice"; import { useDispatch, useSelector } from "react-redux"; import { RootStore } from "../redux/store"; import ContinueButton from "./ContinueButton"; -import { getFontSize } from "../util"; +import { + getFontSize, + getMarkdownLanguageTagForFile, + getMetaKeyLabel, +} from "../util"; +import { ContextItem } from "../../../schema/FullState"; +import StyledMarkdownPreview from "./StyledMarkdownPreview"; const SEARCH_INDEX_NAME = "continue_context_items"; // #region styled components +const gradient = keyframes` + 0% { + background-position: 0px 0; + } + 100% { + background-position: 100em 0; + } +`; + +const GradientBorder = styled.div<{ + borderRadius?: string; + borderColor?: string; + isFirst: boolean; + isLast: boolean; + loading: boolean; +}>` + border-radius: ${(props) => props.borderRadius || "0"}; + padding: 1px; + background: ${(props) => + props.borderColor + ? props.borderColor + : `repeating-linear-gradient( + 101.79deg, + #1BBE84 0%, + #331BBE 16%, + #BE1B55 33%, + #A6BE1B 55%, + #BE1B55 67%, + #331BBE 85%, + #1BBE84 99% + )`}; + animation: ${(props) => (props.loading ? gradient : "")} 6s linear infinite; + background-size: 200% 200%; + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + margin-top: 8px; +`; + const HiddenHeaderButtonWithText = styled.button` opacity: 0; background-color: transparent; @@ -75,7 +123,7 @@ const MainTextInput = styled.textarea<{ font-size: ${(props) => props.fontSize || mainInputFontSize}px; font-family: inherit; border-radius: ${defaultBorderRadius}; - margin: 8px auto; + margin: 0; height: auto; width: 100%; background-color: ${secondaryDark}; @@ -98,6 +146,15 @@ const MainTextInput = styled.textarea<{ } `; +const DeleteButtonDiv = styled.div` + position: absolute; + top: 14px; + right: 12px; + background-color: ${secondaryDark}; + border-radius: ${defaultBorderRadius}; + z-index: 100; +`; + const DynamicQueryTitleDiv = styled.div` position: absolute; right: 0px; @@ -119,12 +176,14 @@ const Ul = styled.ul<{ ulHeightPixels: number; inputBoxHeight?: string; fontSize?: number; + isMainInput: boolean; }>` ${(props) => props.showAbove ? `transform: translateY(-${props.ulHeightPixels + 8}px);` : `transform: translateY(${ - 5 * (props.fontSize || mainInputFontSize) - 2 + (props.isMainInput ? 5 : 4) * (props.fontSize || mainInputFontSize) - + (props.isMainInput ? 2 : 4) }px);`} position: absolute; background: ${vscBackground}; @@ -137,11 +196,11 @@ const Ul = styled.ul<{ ${({ hidden }) => hidden && "display: none;"} border-radius: ${defaultBorderRadius}; outline: 0.5px solid ${lightGray}; - z-index: 2; -ms-overflow-style: none; font-size: ${(props) => props.fontSize || mainInputFontSize}px; scrollbar-width: none; /* Firefox */ + z-index: 500; /* Hide scrollbar for Chrome, Safari and Opera */ &::-webkit-scrollbar { @@ -165,6 +224,7 @@ const Li = styled.li<{ ${({ isLastItem }) => isLastItem && "border-bottom: 1px solid gray;"} /* border-top: 1px solid gray; */ cursor: pointer; + z-index: 500; `; // #endregion @@ -176,14 +236,39 @@ interface ComboBoxItem { content?: string; } interface ComboBoxProps { - onInputValueChange: (inputValue: string) => void; + onInputValueChange?: (inputValue: string) => void; disabled?: boolean; - onEnter: (e?: React.KeyboardEvent) => void; - onToggleAddContext: () => void; + onEnter?: (e?: React.KeyboardEvent, value?: string) => void; + onToggleAddContext?: () => void; + + isMainInput: boolean; + value?: string; + active?: boolean; + groupIndices?: number[]; + onToggle?: (arg0: boolean) => void; + onToggleAll?: (arg0: boolean) => void; + isToggleOpen?: boolean; + index?: number; + onDelete?: () => void; } const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { - const searchClient = new MeiliSearch({ host: "http://127.0.0.1:7700" }); + const meilisearchUrl = useSelector( + (state: RootStore) => + state.serverState.meilisearch_url || "http://127.0.0.1:7700" + ); + + const [searchClient, setSearchClient] = useState( + undefined + ); + + useEffect(() => { + const client = new MeiliSearch({ + host: meilisearchUrl, + }); + setSearchClient(client); + }, [meilisearchUrl]); + const client = useContext(GUIClientContext); const dispatch = useDispatch(); const workspacePaths = useSelector( @@ -197,6 +282,14 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { const inputRef = React.useRef(null); + useEffect(() => { + if (!inputRef.current) return; + if (inputRef.current.scrollHeight > inputRef.current.clientHeight) { + inputRef.current.style.height = "auto"; + inputRef.current.style.height = inputRef.current.scrollHeight + "px"; + } + }, [inputRef.current, props.value]); + // Whether the current input follows an '@' and should be treated as context query const [currentlyInContextQuery, setCurrentlyInContextQuery] = useState(false); const [nestedContextProvider, setNestedContextProvider] = useState< @@ -206,9 +299,6 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { any | undefined >(undefined); - const sessionId = useSelector( - (state: RootStore) => state.serverState.session_info?.session_id - ); const availableSlashCommands = useSelector( (state: RootStore) => state.serverState.slash_commands ).map((cmd) => { @@ -217,15 +307,16 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { description: cmd.description, }; }); - const selectedContextItems = useSelector( - (state: RootStore) => state.serverState.selected_context_items - ); - - useEffect(() => { - if (inputRef.current) { - inputRef.current.focus(); + const selectedContextItems = useSelector((state: RootStore) => { + if (props.index) { + return state.serverState.history.timeline[props.index].context_used || []; + } else { + return state.serverState.selected_context_items; } - }, [sessionId, inputRef.current]); + }); + const timeline = useSelector( + (state: RootStore) => state.serverState.history.timeline + ); useEffect(() => { if (!currentlyInContextQuery) { @@ -287,7 +378,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { setInQueryForContextProvider(undefined); } - props.onInputValueChange(inputValue); + props.onInputValueChange?.(inputValue); // Handle context selection if (inputValue.endsWith("@") || currentlyInContextQuery) { @@ -365,7 +456,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { .join(", ")} ] AND provider_name = '${provider}'` : undefined; try { - const res = await searchClient.index(SEARCH_INDEX_NAME).search(query, { + const res = await searchClient?.index(SEARCH_INDEX_NAME).search(query, { filter: workspaceFilter, }); return ( @@ -410,13 +501,15 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { useImperativeHandle(ref, () => downshiftProps, [downshiftProps]); const contextItemsDivRef = React.useRef(null); - const handleTabPressed = () => { + const handleTabPressed = useCallback(() => { + setShowContextItemsIfNotMain(true); // Set the focus to the next item in the context items div if (!contextItemsDivRef.current) { return; } - const focusableItems = - contextItemsDivRef.current.querySelectorAll(".pill-button"); + const focusableItems = contextItemsDivRef.current.querySelectorAll( + `.pill-button-${props.index || "main"}` + ); const focusableItemsArray = Array.from(focusableItems); const focusedItemIndex = focusableItemsArray.findIndex( (item) => item === document.activeElement @@ -433,22 +526,30 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { const firstItem = focusableItemsArray[0]; (firstItem as any)?.focus(); } - }; + }, [props.index]); useEffect(() => { - if (typeof window !== "undefined") { + if (inputRef.current) { const listener = (e: any) => { if (e.key === "Tab") { e.preventDefault(); handleTabPressed(); } }; - window.addEventListener("keydown", listener); + inputRef.current.addEventListener("keydown", listener); return () => { - window.removeEventListener("keydown", listener); + inputRef.current?.removeEventListener("keydown", listener); }; } - }, []); + }, [inputRef.current]); + + useEffect(() => { + if (props.value) { + downshiftProps.setInputValue(props.value); + } + }, [props.value, downshiftProps.setInputValue]); + + const [isHovered, setIsHovered] = useState(false); useLayoutEffect(() => { if (!ulRef.current) { @@ -458,7 +559,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { }, [items, downshiftProps.setHighlightedIndex, ulRef.current]); const [metaKeyPressed, setMetaKeyPressed] = useState(false); - const [focused, setFocused] = useState(false); + const [inputFocused, setInputFocused] = useState(false); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Meta") { @@ -479,10 +580,12 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { }, []); useEffect(() => { - if (!inputRef.current) { + if (!inputRef.current || !props.isMainInput) { return; } - inputRef.current.focus(); + if (props.isMainInput) { + inputRef.current.focus(); + } const handler = (event: any) => { if (event.data.type === "focusContinueInput") { inputRef.current!.focus(); @@ -498,7 +601,20 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { return () => { window.removeEventListener("message", handler); }; - }, [inputRef.current]); + }, [inputRef.current, props.isMainInput]); + + const deleteButtonDivRef = React.useRef(null); + + const selectContextItem = useCallback( + (id: string, query: string) => { + if (props.isMainInput) { + client?.selectContextItem(id, query); + } else if (props.index) { + client?.selectContextItemAtIndex(id, query, props.index); + } + }, + [client, props.index] + ); const selectContextItemFromDropdown = useCallback( (event: any) => { @@ -511,7 +627,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { if (!newProvider) { if (nestedContextProvider && newItem.id) { // Tell server the context item was selected - client?.selectContextItem(newItem.id, ""); + selectContextItem(newItem.id, ""); // Clear the input downshiftProps.setInputValue(""); @@ -542,7 +658,7 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { const query = segs[segs.length - 1]; // Tell server the context item was selected - client?.selectContextItem(newItem.id, query); + selectContextItem(newItem.id, query); if (downshiftProps.inputValue.includes("@")) { const selectedNestedContextProvider = contextProviders.find( (provider) => provider.title === newItem.id @@ -582,221 +698,428 @@ const ComboBox = React.forwardRef((props: ComboBoxProps, ref) => { contextProviders, nestedContextProvider, downshiftProps.inputValue, + selectContextItem, ] ); const [isComposing, setIsComposing] = useState(false); + const [previewingContextItem, setPreviewingContextItem] = useState< + ContextItem | undefined + >(undefined); + + const [focusedContextItem, setFocusedContextItem] = useState< + ContextItem | undefined + >(undefined); + + const topRef = React.useRef(null); + + const [showContextItemsIfNotMain, setShowContextItemsIfNotMain] = + useState(false); + + useEffect(() => { + if (!inputFocused) { + setShowContextItemsIfNotMain(false); + } + }, [inputFocused]); + return ( - <> -
- 0 ? "pill-button" : ""} - onClick={() => { - client?.deleteContextWithIds( - selectedContextItems.map((item) => item.description.id) - ); - inputRef.current?.focus(); - }} - onKeyDown={(e: any) => { - if (e.key === "Backspace") { +
+ {props.isMainInput || + (selectedContextItems.length > 0 && showContextItemsIfNotMain) ? ( +
+ 0 + ? `pill-button-${props.index || "main"}` + : "" + } + onClick={() => { client?.deleteContextWithIds( - selectedContextItems.map((item) => item.description.id) + selectedContextItems.map((item) => item.description.id), + props.index ); inputRef.current?.focus(); - } - }} - > - - - {selectedContextItems.map((item, idx) => { - return ( - 1} - key={`${item.description.id.item_id}${idx}`} - item={item} - editing={ - item.editing && - (inputRef.current as any)?.value?.startsWith("/edit") - } - editingAny={(inputRef.current as any)?.value?.startsWith("/edit")} - index={idx} - onDelete={() => { - client?.deleteContextWithIds([item.description.id]); + }} + onKeyDown={(e: any) => { + if (e.key === "Backspace") { + client?.deleteContextWithIds( + selectedContextItems.map((item) => item.description.id), + props.index + ); inputRef.current?.focus(); - }} - /> - ); - })} + setPreviewingContextItem(undefined); + setFocusedContextItem(undefined); + } + }} + > + + + {(props.isMainInput + ? selectedContextItems + : timeline[props.index!].context_used || [] + ).map((item, idx) => { + return ( + 1} + key={`${item.description.id.item_id}${idx}`} + item={item} + editing={ + item.editing && + (inputRef.current as any)?.value?.startsWith("/edit") + } + editingAny={(inputRef.current as any)?.value?.startsWith( + "/edit" + )} + stepIndex={props.index} + index={idx} + onDelete={() => { + client?.deleteContextWithIds( + [item.description.id], + props.index + ); + inputRef.current?.focus(); + if ( + (item.description.id.item_id === + focusedContextItem?.description.id.item_id && + focusedContextItem?.description.id.provider_name === + item.description.id.provider_name) || + (item.description.id.item_id === + previewingContextItem?.description.id.item_id && + previewingContextItem?.description.id.provider_name === + item.description.id.provider_name) + ) { + setPreviewingContextItem(undefined); + setFocusedContextItem(undefined); + } + }} + onClick={(e) => { + if ( + item.description.id.item_id === + focusedContextItem?.description.id.item_id && + focusedContextItem?.description.id.provider_name === + item.description.id.provider_name + ) { + setFocusedContextItem(undefined); + } else { + setFocusedContextItem(item); + } + }} + onBlur={() => { + setFocusedContextItem(undefined); + }} + toggleViewContent={() => { + setPreviewingContextItem((prev) => { + if (!prev) return item; + if ( + prev.description.id.item_id === + item.description.id.item_id && + prev.description.id.provider_name === + item.description.id.provider_name + ) { + return undefined; + } else { + return item; + } + }); + }} + previewing={ + item.description.id.item_id === + previewingContextItem?.description.id.item_id && + previewingContextItem?.description.id.provider_name === + item.description.id.provider_name + } + focusing={ + item.description.id.item_id === + focusedContextItem?.description.id.item_id && + focusedContextItem?.description.id.provider_name === + item.description.id.provider_name + } + /> + ); + })} - {selectedContextItems.length > 0 && ( + {/* {selectedContextItems.length > 0 && ( { - client?.showContextVirtualFile(); + client?.showContextVirtualFile(props.index); }} text="View Current Context" > - )} -
+ )} */} +
+ ) : ( + selectedContextItems.length > 0 && ( +
{ + inputRef.current?.focus(); + setShowContextItemsIfNotMain(true); + }} + style={{ + color: lightGray, + fontSize: "10px", + backgroundColor: vscBackground, + paddingLeft: "12px", + cursor: "default", + paddingTop: getFontSize(), + }} + > + {props.active ? "Using" : "Used"} {selectedContextItems.length}{" "} + context item + {selectedContextItems.length === 1 ? "" : "s"} +
+ ) + )} + {previewingContextItem && ( +
+          
+        
+ )} {selectedContextItems.length === 0 && (downshiftProps.inputValue?.startsWith("/edit") || - (focused && + (inputFocused && metaKeyPressed && downshiftProps.inputValue?.length > 0)) && ( -
+
Inserting at cursor
)} - props.onEnter(undefined)} - /> - + {props.isMainInput && ( + props.onEnter?.(undefined)} + /> + )} +
); }); diff --git a/extension/react-app/src/components/ErrorStepContainer.tsx b/extension/react-app/src/components/ErrorStepContainer.tsx index e8ab7950..666780c5 100644 --- a/extension/react-app/src/components/ErrorStepContainer.tsx +++ b/extension/react-app/src/components/ErrorStepContainer.tsx @@ -14,6 +14,7 @@ const Div = styled.div` background-color: #ff000011; border-radius: ${defaultBorderRadius}; border: 1px solid #cc0000; + margin: 8px; `; interface ErrorStepContainerProps { @@ -28,8 +29,8 @@ function ErrorStepContainer(props: ErrorStepContainerProps) {
diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx index 84e6118c..431d0455 100644 --- a/extension/react-app/src/components/HeaderButtonWithText.tsx +++ b/extension/react-app/src/components/HeaderButtonWithText.tsx @@ -11,6 +11,7 @@ interface HeaderButtonWithTextProps { active?: boolean; className?: string; onKeyDown?: (e: any) => void; + tabIndex?: number; } const HeaderButtonWithText = React.forwardRef< @@ -39,6 +40,7 @@ const HeaderButtonWithText = React.forwardRef< onKeyDown={props.onKeyDown} className={props.className} ref={ref} + tabIndex={props.tabIndex} > {props.children} diff --git a/extension/react-app/src/components/PillButton.tsx b/extension/react-app/src/components/PillButton.tsx index fb685a82..063572b5 100644 --- a/extension/react-app/src/components/PillButton.tsx +++ b/extension/react-app/src/components/PillButton.tsx @@ -1,23 +1,23 @@ -import { useContext, useEffect, useState } from "react"; +import { useContext, useEffect, useRef, useState } from "react"; import styled from "styled-components"; import { StyledTooltip, defaultBorderRadius, lightGray, secondaryDark, - vscBackground, vscForeground, } from "."; import { TrashIcon, PaintBrushIcon, ExclamationTriangleIcon, + EyeIcon, } from "@heroicons/react/24/outline"; import { GUIClientContext } from "../App"; import { useDispatch } from "react-redux"; -import { setBottomMessage } from "../redux/slices/uiStateSlice"; import { ContextItem } from "../../../schema/FullState"; import { getFontSize } from "../util"; +import HeaderButtonWithText from "./HeaderButtonWithText"; const Button = styled.button<{ fontSize?: number }>` border: none; @@ -80,7 +80,13 @@ interface PillButtonProps { editingAny: boolean; index: number; areMultipleItems?: boolean; - onDelete?: () => void; + onDelete?: (index?: number) => void; + onClick?: (e: React.MouseEvent) => void; + stepIndex?: number; + previewing?: boolean; + toggleViewContent?: () => void; + onBlur?: () => void; + focusing?: boolean; } interface StyledButtonProps { @@ -88,6 +94,14 @@ interface StyledButtonProps { editing?: boolean; } +const Container = styled.div<{ previewing?: boolean }>` + border-radius: ${defaultBorderRadius}; + background-color: ${secondaryDark}; + display: flex; + align-items: center; + justify-content: center; +`; + const StyledButton = styled(Button)` position: relative; border-color: ${(props) => props.borderColor || "transparent"}; @@ -96,12 +110,34 @@ const StyledButton = styled(Button)` &:focus { outline: none; - border-color: ${lightGray}; - border-width: 1px; - border-style: solid; + /* border-color: ${lightGray}; */ + text-decoration: underline; + } +`; + +const HoverableInsidePillButton = styled(HeaderButtonWithText)<{ + color: string; +}>` + &:hover { + background-color: ${(props) => props.color}; } `; +const ClickableInsidePillButton = styled(HeaderButtonWithText)<{ + color: string; + selected: boolean; +}>` + ${(props) => + props.selected && + ` + background-color: ${props.color}; + + &:hover { + background-color: ${props.color}; + } + `} +`; + const PillButton = (props: PillButtonProps) => { const [isHovered, setIsHovered] = useState(false); const client = useContext(GUIClientContext); @@ -116,122 +152,125 @@ const PillButton = (props: PillButtonProps) => { } }, [props.editing, props.item]); - const dispatch = useDispatch(); + const pillContainerRef = useRef(null); + const buttonRef = useRef(null); return (
- { - setIsHovered(true); - if (props.onHover) { - props.onHover(true); + + { - setIsHovered(false); - if (props.onHover) { - props.onHover(false); - } - }} - className="pill-button" - onKeyDown={(e) => { - if (e.key === "Backspace") { - props.onDelete?.(); - } - }} - > - {isHovered && ( - - {props.editingAny && - props.item.editable && - props.areMultipleItems && ( - { - client?.setEditingAtIds([ - props.item.description.id.item_id, - ]); - }} - > - - - )} - - - Edit this range - - { + setIsHovered(true); + if (props.onHover) { + props.onHover(true); + } + }} + onMouseLeave={() => { + setIsHovered(false); + if (props.onHover) { + props.onHover(false); + } + }} + className={`pill-button-${props.stepIndex || "main"}`} + onKeyDown={(e) => { + if (e.key === "Backspace") { + props.onDelete?.(props.stepIndex); + } else if (e.key === "v") { + props.toggleViewContent?.(); + } else if (e.key === "e") { + client?.setEditingAtIds([props.item.description.id.item_id]); + } + }} + onClick={(e) => { + props.onClick?.(e); + }} + onBlur={(e) => { + if (!pillContainerRef.current?.contains(e.relatedTarget as any)) { + props.onBlur?.(); + } else { + e.preventDefault(); + buttonRef.current?.focus(); + } + }} + > + + {props.item.description.name} + + + {((props.focusing && props.item.editable && props.editingAny) || + props.editing) && ( + <> + { - client?.deleteContextWithIds([props.item.description.id]); - dispatch(setBottomMessage(undefined)); + if (!props.editing) { + client?.setEditingAtIds([props.item.description.id.item_id]); + } }} + tabIndex={-1} + color="#f0f4" + selected={props.editing} > - - - + + + + Editing this range + + + )} + {(props.focusing || props.previewing) && ( + props.toggleViewContent?.()} + tabIndex={-1} + color="#ff04" + selected={props.previewing || false} + > + + + )} + {props.focusing && ( + props.onDelete?.(props.stepIndex)} + tabIndex={-1} + color="#f004" + > + + )} - {props.item.description.name} - + {props.item.editing ? "Editing this section (with entire file as context)" : "Edit this section"} Delete - {props.editing && - (warning ? ( - <> - - - - - {warning} - - - ) : ( - <> - - - - - Editing this range - - - ))} + {props.editing && warning && ( + <> + + + + + {warning} + + + )}
); }; diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index e7264c5d..11e80fb2 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -35,10 +35,10 @@ const ButtonsDiv = styled.div` background-color: ${vscBackground}; box-shadow: 1px 1px 10px ${vscBackground}; border-radius: ${defaultBorderRadius}; - + z-index: 100; position: absolute; - right: 0; - top: 0; + right: 8px; + top: 16px; height: 0; `; diff --git a/extension/react-app/src/components/StyledMarkdownPreview.tsx b/extension/react-app/src/components/StyledMarkdownPreview.tsx index 78d4234c..f53e5289 100644 --- a/extension/react-app/src/components/StyledMarkdownPreview.tsx +++ b/extension/react-app/src/components/StyledMarkdownPreview.tsx @@ -12,12 +12,13 @@ import { getFontSize } from "../util"; const StyledMarkdownPreview = styled(MarkdownPreview)<{ light?: boolean; fontSize?: number; + maxHeight?: number; }>` pre { background-color: ${(props) => props.light ? vscBackground : secondaryDark}; border-radius: ${defaultBorderRadius}; - border: 0.5px solid ${lightGray}; + /* border: 0.5px solid ${lightGray}; */ max-width: calc(100vw - 24px); } @@ -34,6 +35,15 @@ const StyledMarkdownPreview = styled(MarkdownPreview)<{ props.light ? vscBackground : secondaryDark}; color: ${vscForeground}; padding: 12px; + + ${(props) => { + if (props.maxHeight) { + return ` + max-height: ${props.maxHeight}px; + overflow-y: auto; + `; + } + }} } background-color: ${(props) => (props.light ? "transparent" : vscBackground)}; diff --git a/extension/react-app/src/components/Suggestions.tsx b/extension/react-app/src/components/Suggestions.tsx index ed2eb558..bdda7579 100644 --- a/extension/react-app/src/components/Suggestions.tsx +++ b/extension/react-app/src/components/Suggestions.tsx @@ -150,6 +150,8 @@ const NUM_STAGES = suggestionsStages.length; const TutorialDiv = styled.div` margin: 4px; + margin-left: 8px; + margin-right: 8px; position: relative; background-color: #ff02; border-radius: ${defaultBorderRadius}; diff --git a/extension/react-app/src/components/TimelineItem.tsx b/extension/react-app/src/components/TimelineItem.tsx index f54788eb..b51dd307 100644 --- a/extension/react-app/src/components/TimelineItem.tsx +++ b/extension/react-app/src/components/TimelineItem.tsx @@ -11,7 +11,7 @@ const CollapseButton = styled.div` align-items: center; flex-shrink: 0; flex-grow: 0; - margin-left: 5px; + margin-left: 13px; cursor: pointer; `; diff --git a/extension/react-app/src/components/UserInputContainer.tsx b/extension/react-app/src/components/UserInputContainer.tsx index 11671526..99b4bbc4 100644 --- a/extension/react-app/src/components/UserInputContainer.tsx +++ b/extension/react-app/src/components/UserInputContainer.tsx @@ -35,7 +35,6 @@ import { useSelector } from "react-redux"; interface UserInputContainerProps { onDelete: () => void; children: string; - historyNode: HistoryNode; index: number; onToggle: (arg0: boolean) => void; onToggleAll: (arg0: boolean) => void; diff --git a/extension/react-app/src/components/index.ts b/extension/react-app/src/components/index.ts index 1c27527c..9d9b7c40 100644 --- a/extension/react-app/src/components/index.ts +++ b/extension/react-app/src/components/index.ts @@ -39,7 +39,7 @@ export const StyledTooltip = styled(Tooltip)` padding: 6px; padding-left: 12px; padding-right: 12px; - z-index: 100; + z-index: 1000; max-width: 80vw; `; @@ -196,6 +196,11 @@ export const HeaderButton = styled.button<{ inverted: boolean | undefined }>` border-radius: ${defaultBorderRadius}; cursor: ${({ disabled }) => (disabled ? "default" : "pointer")}; + &:focus { + outline: none; + border: none; + } + &:hover { background-color: ${({ inverted }) => typeof inverted === "undefined" || inverted -- cgit v1.2.3-70-g09d2