summaryrefslogtreecommitdiff
path: root/extension/react-app/src/components/Layout.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'extension/react-app/src/components/Layout.tsx')
-rw-r--r--extension/react-app/src/components/Layout.tsx183
1 files changed, 182 insertions, 1 deletions
diff --git a/extension/react-app/src/components/Layout.tsx b/extension/react-app/src/components/Layout.tsx
index 47ed9cc3..30cb5df2 100644
--- a/extension/react-app/src/components/Layout.tsx
+++ b/extension/react-app/src/components/Layout.tsx
@@ -1,6 +1,29 @@
import styled from "styled-components";
-import { defaultBorderRadius } from ".";
+import { defaultBorderRadius, secondaryDark, vscForeground } from ".";
import { Outlet } from "react-router-dom";
+import Onboarding from "./Onboarding";
+import TextDialog from "./TextDialog";
+import { useContext } from "react";
+import { GUIClientContext } from "../App";
+import { useDispatch, useSelector } from "react-redux";
+import { RootStore } from "../redux/store";
+import {
+ setBottomMessage,
+ setBottomMessageCloseTimeout,
+ setDialogEntryOn,
+ setDialogMessage,
+ setShowDialog,
+} from "../redux/slices/uiStateSlice";
+import {
+ PlusIcon,
+ FolderIcon,
+ BookOpenIcon,
+ ChatBubbleOvalLeftEllipsisIcon,
+} from "@heroicons/react/24/outline";
+import HeaderButtonWithText from "./HeaderButtonWithText";
+import { useNavigate } from "react-router-dom";
+
+// #region Styled Components
const LayoutTopDiv = styled.div`
height: 100%;
@@ -9,7 +32,56 @@ const LayoutTopDiv = styled.div`
scrollbar-width: thin;
`;
+const BottomMessageDiv = styled.div<{ displayOnBottom: boolean }>`
+ position: fixed;
+ bottom: ${(props) => (props.displayOnBottom ? "50px" : undefined)};
+ top: ${(props) => (props.displayOnBottom ? undefined : "50px")};
+ left: 0;
+ right: 0;
+ margin: 8px;
+ margin-top: 0;
+ background-color: ${secondaryDark};
+ color: ${vscForeground};
+ border-radius: ${defaultBorderRadius};
+ padding: 12px;
+ z-index: 100;
+ box-shadow: 0px 0px 2px 0px ${vscForeground};
+ max-height: 50vh;
+ overflow: scroll;
+`;
+
+const Footer = styled.footer`
+ display: flex;
+ flex-direction: row;
+ gap: 8px;
+ justify-content: right;
+ padding: 8px;
+ align-items: center;
+ margin-top: 8px;
+ border-top: 0.1px solid gray;
+`;
+
+// #endregion
+
const Layout = () => {
+ const navigate = useNavigate();
+ const client = useContext(GUIClientContext);
+ const dispatch = useDispatch();
+ const { showDialog, dialogEntryOn, dialogMessage } = useSelector(
+ (state: RootStore) => state.uiState
+ );
+
+ // #region Selectors
+ const vscMediaUrl = useSelector(
+ (state: RootStore) => state.config.vscMediaUrl
+ );
+
+ const { bottomMessage, displayBottomMessageOnBottom } = useSelector(
+ (state: RootStore) => state.uiState
+ );
+
+ // #endregion
+
return (
<LayoutTopDiv>
<div
@@ -20,7 +92,116 @@ const Layout = () => {
gridTemplateRows: "1fr auto",
}}
>
+ <Onboarding />
+ <TextDialog
+ showDialog={showDialog}
+ onEnter={(text) => {
+ client?.sendMainInput(`/feedback ${text}`);
+ dispatch(setShowDialog(false));
+ }}
+ onClose={() => {
+ dispatch(setShowDialog(false));
+ }}
+ message={dialogMessage}
+ entryOn={dialogEntryOn}
+ />
<Outlet />
+
+ <BottomMessageDiv
+ displayOnBottom={displayBottomMessageOnBottom}
+ onMouseEnter={() => {
+ dispatch(setBottomMessageCloseTimeout(undefined));
+ }}
+ onMouseLeave={(e) => {
+ if (!e.buttons) {
+ dispatch(setBottomMessage(undefined));
+ }
+ }}
+ hidden={!bottomMessage}
+ >
+ {bottomMessage}
+ </BottomMessageDiv>
+ <Footer>
+ {vscMediaUrl && (
+ <a
+ href="https://github.com/continuedev/continue"
+ style={{ marginRight: "auto" }}
+ >
+ <img
+ src={`${vscMediaUrl}/continue-dev-square.png`}
+ width="22px"
+ style={{ backgroundColor: "black", color: "red" }}
+ />
+ </a>
+ )}
+ <HeaderButtonWithText
+ onClick={() => {
+ // Show the dialog
+ dispatch(
+ setDialogMessage(`Continue uses GPT-4 by default, but works with any model. If you'd like to keep your code completely private, there are few options:
+
+ Run a local model with ggml: [5 minute quickstart](https://github.com/continuedev/ggml-server-example)
+
+ Use Azure OpenAI service, which is GDPR and HIPAA compliant: [Tutorial](https://continue.dev/docs/customization#azure-openai-service)
+
+ If you already have an LLM deployed on your own infrastructure, or would like to do so, please contact us at hi@continue.dev.
+ `)
+ );
+ dispatch(setDialogEntryOn(false));
+ dispatch(setShowDialog(true));
+ }}
+ text={"Use Private Model"}
+ >
+ <div
+ style={{
+ fontSize: "18px",
+ marginLeft: "2px",
+ marginRight: "2px",
+ }}
+ >
+ 🔒
+ </div>
+ </HeaderButtonWithText>
+ <HeaderButtonWithText
+ onClick={() => {
+ client?.loadSession(undefined);
+ }}
+ text="New Session"
+ >
+ <PlusIcon width="1.4em" height="1.4em" />
+ </HeaderButtonWithText>
+ <HeaderButtonWithText
+ onClick={() => {
+ navigate("/history");
+ }}
+ text="History"
+ >
+ <FolderIcon width="1.4em" height="1.4em" />
+ </HeaderButtonWithText>
+ <a
+ href="https://continue.dev/docs/how-to-use-continue"
+ className="no-underline"
+ >
+ <HeaderButtonWithText text="Docs">
+ <BookOpenIcon width="1.4em" height="1.4em" />
+ </HeaderButtonWithText>
+ </a>
+ <HeaderButtonWithText
+ onClick={() => {
+ // Set dialog open
+ dispatch(
+ setDialogMessage(
+ "Having trouble using Continue? Want a new feature? Let us know! This box is anonymous, but we will promptly address your feedback."
+ )
+ );
+ dispatch(setDialogEntryOn(true));
+ dispatch(setShowDialog(true));
+ }}
+ text="Feedback"
+ >
+ <ChatBubbleOvalLeftEllipsisIcon width="1.4em" height="1.4em" />
+ </HeaderButtonWithText>
+ </Footer>
</div>
</LayoutTopDiv>
);