From 207465955cbf7a584fbe592aa21c8d141c23dd66 Mon Sep 17 00:00:00 2001 From: BetaHuhn Date: Thu, 31 Aug 2023 18:12:26 +0200 Subject: [PATCH] feat: incognito mode --- src/components/App.tsx | 4 +- src/components/ChatItem.tsx | 9 + src/components/EditChatModal.tsx | 26 ++- src/components/Layout.tsx | 364 +++++++++++++++++-------------- src/components/SettingsModal.tsx | 60 +++-- src/hooks/contexts.ts | 9 + 6 files changed, 283 insertions(+), 189 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index a9bceff..da31ff0 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -6,7 +6,7 @@ import { import { useHotkeys, useLocalStorage } from "@mantine/hooks"; import { Notifications } from "@mantine/notifications"; import { - createHashHistory, + createBrowserHistory, ReactLocation, Router, } from "@tanstack/react-location"; @@ -14,7 +14,7 @@ import { ChatRoute } from "../routes/ChatRoute"; import { IndexRoute } from "../routes/IndexRoute"; import { Layout } from "./Layout"; -const history = createHashHistory(); +const history = createBrowserHistory(); const location = new ReactLocation({ history }); export function App() { diff --git a/src/components/ChatItem.tsx b/src/components/ChatItem.tsx index 4dc2fb1..52c769f 100644 --- a/src/components/ChatItem.tsx +++ b/src/components/ChatItem.tsx @@ -6,10 +6,12 @@ import { EditChatModal } from "./EditChatModal"; import { MainLink } from "./MainLink"; import { useHover } from "@mantine/hooks"; import { Chat } from "../db"; +import { useIncognitoMode } from "../hooks/contexts"; export function ChatItem({ chat, active = false }: { chat: Chat, active?: boolean }) { const { hovered, ref } = useHover(); const theme = useMantineTheme(); + const { incognitoMode } = useIncognitoMode() return ( diff --git a/src/components/EditChatModal.tsx b/src/components/EditChatModal.tsx index 0fb020b..2304319 100644 --- a/src/components/EditChatModal.tsx +++ b/src/components/EditChatModal.tsx @@ -27,25 +27,24 @@ export function EditChatModal({ const [writingTone, setWritingTone] = useState(null); const [writingStyle, setWritingStyle] = useState(null); const [writingFormat, setWritingFormat] = useState(null); - const [model, setModel] = useState('default'); const [value, setValue] = useState(""); useEffect(() => { setValue(chat?.description ?? ""); + setModel(chat.model ?? 'default') + setWritingInstructions(chat.writingInstructions ?? null) + setWritingCharacter(chat.writingCharacter ?? null) + setWritingTone(chat.writingTone ?? null) + setWritingStyle(chat.writingStyle ?? null) + setWritingFormat(chat.writingFormat ?? null) - if (chat.model) setModel(chat.model) if (chat.prompt) { setPromptKey(chat.prompt) } else { setPromptKey(null) - if (chat.writingInstructions) setWritingInstructions(chat.writingInstructions) - if (chat.writingCharacter) setWritingCharacter(chat.writingCharacter) - if (chat.writingTone) setWritingTone(chat.writingTone) - if (chat.writingStyle) setWritingStyle(chat.writingStyle) - if (chat.writingFormat) setWritingFormat(chat.writingFormat) } - }, [chat]); + }, [chat, opened]); useEffect(() => { const prompt = prompts.find(prompt => prompt.key === promptKey) @@ -73,6 +72,17 @@ export function EditChatModal({ } }, [writingInstructions, writingCharacter, writingFormat, writingStyle, writingTone]); + // const handleClose = () => { + // close() + // setPromptKey(null) + // setWritingInstructions(null) + // setWritingCharacter(null) + // setWritingTone(null) + // setWritingStyle(null) + // setWritingFormat(null) + // setModel('default') + // } + return ( <> {cloneElement(children, { onClick: open })} diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 32b970e..109f66e 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -18,6 +18,8 @@ import { IconPlus, IconSearch, IconSettings, + IconSpy, + IconSpyOff, IconX, } from "@tabler/icons-react"; import { Link, Outlet, useNavigate, useRouter } from "@tanstack/react-location"; @@ -30,9 +32,10 @@ import { LogoText } from "./Logo"; import { Prompts } from "./Prompts"; import { SettingsModal } from "./SettingsModal"; import { config } from "../utils/config"; -import { ChatContext, ChatsContext, PromptsContext, SettingsContext } from "../hooks/contexts"; +import { ChatContext, ChatsContext, IncognitoModeContext, PromptsContext, SettingsContext } from "../hooks/contexts"; import { ChatHeader } from "./ChatHeader"; import { notifications } from "@mantine/notifications"; +import { useLocalStorage } from "@mantine/hooks"; declare global { interface Window { @@ -44,13 +47,17 @@ export function Layout() { const theme = useMantineTheme(); const [opened, setOpened] = useState(false); const [tab, setTab] = useState<"Chats" | "Prompts">("Chats"); - const { colorScheme } = useMantineColorScheme(); + const { colorScheme, toggleColorScheme } = useMantineColorScheme(); const navigate = useNavigate(); const router = useRouter(); const [search, setSearch] = useState(""); const chatId = useChatId(); + const [incognitoMode, setIncognitoMode] = useLocalStorage({ + key: 'incognito-mode', defaultValue: false + }); + const [settings, setSettings] = useState(null); useEffect(() => { const dataFetch = async () => { @@ -119,172 +126,209 @@ export function Layout() { setOpened(false); }, [router.state.location]); + const handleIncognito = () => { + if (incognitoMode) { + setIncognitoMode(false) + if (colorScheme === 'dark') { + toggleColorScheme() + } + } else { + setIncognitoMode(true) + if (colorScheme !== 'dark') { + toggleColorScheme() + } + } + } + return ( - + + + + {tab === "Chats" && ( + + )} + {tab === "Prompts" && } + + + + } + header={ + chat ? ( + + ) : undefined + } + layout="alt" + padding={0} + > + + setOpened((o) => !o)} + size="sm" + color={theme.colors.gray[6]} + className="app-region-no-drag" + sx={{ position: "fixed", top: 16, right: 16, zIndex: 100 }} + /> + + + + diff --git a/src/components/SettingsModal.tsx b/src/components/SettingsModal.tsx index 91dc3be..6ebc894 100644 --- a/src/components/SettingsModal.tsx +++ b/src/components/SettingsModal.tsx @@ -3,13 +3,16 @@ import { Anchor, Button, Flex, - List, Modal, PasswordInput, TextInput, Select, Stack, Text, + useMantineColorScheme, + Box, + SegmentedControl, + Center, } from "@mantine/core"; import { useDisclosure } from "@mantine/hooks"; import { notifications } from "@mantine/notifications"; @@ -18,6 +21,7 @@ import { Settings, detaDB } from "../db"; import { config } from "../utils/config"; import { checkOpenAIKey } from "../utils/openai"; import { useSettings } from "../hooks/contexts"; +import { IconMoonStars, IconSunHigh } from "@tabler/icons-react"; export function SettingsModal({ children }: { children: ReactElement }) { const [opened, { open, close }] = useDisclosure(false); @@ -31,6 +35,7 @@ export function SettingsModal({ children }: { children: ReactElement }) { const [version, setVersion] = useState(""); const { settings, setSettings } = useSettings() + const { colorScheme, toggleColorScheme } = useMantineColorScheme(); useEffect(() => { if (settings?.openAiApiKey) { @@ -58,6 +63,33 @@ export function SettingsModal({ children }: { children: ReactElement }) { {cloneElement(children, { onClick: open })} + + Theme + toggleColorScheme()} + data={[ + { + value: 'light', + label: ( +
+ + Light +
+ ), + }, + { + value: 'dark', + label: ( +
+ + Dark +
+ ), + }, + ]} + /> +
{ try { @@ -127,24 +159,14 @@ export function SettingsModal({ children }: { children: ReactElement }) {
- - - - - Get your OpenAI API key - - - - - - The API Key is stored locally on your browser and never sent - anywhere else. - - - + + + Get your OpenAI API key + +