From 05cfd7f34f5deffa6e8a8a1f987cd30467c57099 Mon Sep 17 00:00:00 2001 From: Jing Hua Date: Sat, 4 Mar 2023 06:17:11 +0800 Subject: [PATCH] First Commit --- index.html | 2 +- package.json | 9 +- src/App.tsx | 49 +- src/api/customApi.ts | 72 ++ src/api/freeApi.ts | 44 + src/api/helper.ts | 19 + src/assets/icons/ChatIcon.tsx | 22 + src/assets/icons/CopyIcon.tsx | 23 + src/assets/icons/CrossIcon.tsx | 23 + src/assets/icons/CrossIcon2.tsx | 21 + src/assets/icons/DeleteIcon.tsx | 25 + src/assets/icons/DownArrow.tsx | 23 + src/assets/icons/DownChevronArrow.tsx | 23 + src/assets/icons/EditIcon.tsx | 23 + src/assets/icons/EditIcon2.tsx | 23 + src/assets/icons/HeartIcon.tsx | 16 + src/assets/icons/LinkIcon.tsx | 24 + src/assets/icons/LogoutIcon.tsx | 24 + src/assets/icons/MoonIcon.tsx | 22 + src/assets/icons/PersonIcon.tsx | 23 + src/assets/icons/PlusIcon.tsx | 23 + src/assets/icons/RefreshIcon.tsx | 24 + src/assets/icons/SendIcon.tsx | 23 + src/assets/icons/SettingIcon.tsx | 11 + src/assets/icons/SunIcon.tsx | 30 + src/assets/icons/TickIcon.tsx | 22 + src/components/Chat/Chat.tsx | 19 + .../Chat/ChatContent/ChatContent.tsx | 116 +++ src/components/Chat/ChatContent/ChatTitle.tsx | 11 + .../Chat/ChatContent/Message/Avatar.tsx | 62 ++ .../Chat/ChatContent/Message/Message.tsx | 50 + .../ChatContent/Message/MessageContent.tsx | 289 ++++++ .../ChatContent/Message/NewMessageButton.tsx | 66 ++ .../Chat/ChatContent/Message/RoleSelector.tsx | 70 ++ .../Chat/ChatContent/Message/index.ts | 1 + .../Chat/ChatContent/ScrollToBottomButton.tsx | 18 + src/components/Chat/ChatContent/index.ts | 1 + src/components/Chat/ChatInput.tsx | 34 + src/components/Chat/index.ts | 1 + src/components/ConfigMenu/ConfigMenu.tsx | 141 +++ src/components/ConfigMenu/index.ts | 1 + src/components/Menu/ChatHistoryList.tsx | 164 +++ src/components/Menu/Menu.tsx | 39 + src/components/Menu/MenuOptions/Account.tsx | 13 + .../Menu/MenuOptions/ClearConversation.tsx | 14 + src/components/Menu/MenuOptions/Config.tsx | 23 + src/components/Menu/MenuOptions/Logout.tsx | 13 + src/components/Menu/MenuOptions/Me.tsx | 18 + .../Menu/MenuOptions/MenuOptions.tsx | 25 + .../Menu/MenuOptions/ThemeSwitcher.tsx | 38 + src/components/Menu/MenuOptions/Updates.tsx | 17 + src/components/Menu/MenuOptions/index.ts | 1 + src/components/Menu/NewChat.tsx | 43 + src/components/Menu/index.ts | 1 + src/components/MobileBar/MobileBar.tsx | 53 + src/components/MobileBar/index.ts | 1 + src/constants/chat.ts | 12 + src/hooks/useSaveToLocalStorage.ts | 12 + src/hooks/useUpdateChats.ts | 25 + src/index.css | 3 - src/main.css | 207 ++++ src/main.tsx | 2 +- src/store/auth-slice.ts | 24 + src/store/chat-slice.ts | 34 + src/store/config-slice.ts | 16 + src/store/input-slice.ts | 17 + src/store/store.ts | 21 + src/types/api.ts | 18 + src/types/chat.ts | 12 + tailwind.config.cjs | 37 +- tsconfig.json | 11 +- vite.config.ts | 16 +- yarn.lock | 946 +++++++++++++++++- 73 files changed, 3380 insertions(+), 19 deletions(-) create mode 100644 src/api/customApi.ts create mode 100644 src/api/freeApi.ts create mode 100644 src/api/helper.ts create mode 100644 src/assets/icons/ChatIcon.tsx create mode 100644 src/assets/icons/CopyIcon.tsx create mode 100644 src/assets/icons/CrossIcon.tsx create mode 100644 src/assets/icons/CrossIcon2.tsx create mode 100644 src/assets/icons/DeleteIcon.tsx create mode 100644 src/assets/icons/DownArrow.tsx create mode 100644 src/assets/icons/DownChevronArrow.tsx create mode 100644 src/assets/icons/EditIcon.tsx create mode 100644 src/assets/icons/EditIcon2.tsx create mode 100644 src/assets/icons/HeartIcon.tsx create mode 100644 src/assets/icons/LinkIcon.tsx create mode 100644 src/assets/icons/LogoutIcon.tsx create mode 100644 src/assets/icons/MoonIcon.tsx create mode 100644 src/assets/icons/PersonIcon.tsx create mode 100644 src/assets/icons/PlusIcon.tsx create mode 100644 src/assets/icons/RefreshIcon.tsx create mode 100644 src/assets/icons/SendIcon.tsx create mode 100644 src/assets/icons/SettingIcon.tsx create mode 100644 src/assets/icons/SunIcon.tsx create mode 100644 src/assets/icons/TickIcon.tsx create mode 100644 src/components/Chat/Chat.tsx create mode 100644 src/components/Chat/ChatContent/ChatContent.tsx create mode 100644 src/components/Chat/ChatContent/ChatTitle.tsx create mode 100644 src/components/Chat/ChatContent/Message/Avatar.tsx create mode 100644 src/components/Chat/ChatContent/Message/Message.tsx create mode 100644 src/components/Chat/ChatContent/Message/MessageContent.tsx create mode 100644 src/components/Chat/ChatContent/Message/NewMessageButton.tsx create mode 100644 src/components/Chat/ChatContent/Message/RoleSelector.tsx create mode 100644 src/components/Chat/ChatContent/Message/index.ts create mode 100644 src/components/Chat/ChatContent/ScrollToBottomButton.tsx create mode 100644 src/components/Chat/ChatContent/index.ts create mode 100644 src/components/Chat/ChatInput.tsx create mode 100644 src/components/Chat/index.ts create mode 100644 src/components/ConfigMenu/ConfigMenu.tsx create mode 100644 src/components/ConfigMenu/index.ts create mode 100644 src/components/Menu/ChatHistoryList.tsx create mode 100644 src/components/Menu/Menu.tsx create mode 100644 src/components/Menu/MenuOptions/Account.tsx create mode 100644 src/components/Menu/MenuOptions/ClearConversation.tsx create mode 100644 src/components/Menu/MenuOptions/Config.tsx create mode 100644 src/components/Menu/MenuOptions/Logout.tsx create mode 100644 src/components/Menu/MenuOptions/Me.tsx create mode 100644 src/components/Menu/MenuOptions/MenuOptions.tsx create mode 100644 src/components/Menu/MenuOptions/ThemeSwitcher.tsx create mode 100644 src/components/Menu/MenuOptions/Updates.tsx create mode 100644 src/components/Menu/MenuOptions/index.ts create mode 100644 src/components/Menu/NewChat.tsx create mode 100644 src/components/Menu/index.ts create mode 100644 src/components/MobileBar/MobileBar.tsx create mode 100644 src/components/MobileBar/index.ts create mode 100644 src/constants/chat.ts create mode 100644 src/hooks/useSaveToLocalStorage.ts create mode 100644 src/hooks/useUpdateChats.ts delete mode 100644 src/index.css create mode 100644 src/main.css create mode 100644 src/store/auth-slice.ts create mode 100644 src/store/chat-slice.ts create mode 100644 src/store/config-slice.ts create mode 100644 src/store/input-slice.ts create mode 100644 src/store/store.ts create mode 100644 src/types/api.ts create mode 100644 src/types/chat.ts diff --git a/index.html b/index.html index e0d1c84..8a75dc1 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - Vite + React + TS + ChatGPT Free
diff --git a/package.json b/package.json index f829b88..6aea76c 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "chatgpt", + "name": "chatgpt-free-app", "private": true, "version": "0.0.0", "type": "module", @@ -9,11 +9,16 @@ "preview": "vite preview" }, "dependencies": { + "dompurify": "^3.0.1", "highlight.js": "^11.7.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-markdown": "^8.0.5", + "react-scroll-to-bottom": "^4.2.0", + "zustand": "^4.3.5" }, "devDependencies": { + "@tailwindcss/typography": "^0.5.9", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "@vitejs/plugin-react-swc": "^3.0.0", diff --git a/src/App.tsx b/src/App.tsx index 544badc..aad4b81 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,52 @@ +import React, { useEffect } from 'react'; +import useStore from '@store/store'; + +import Chat from './components/Chat'; +import Menu from './components/Menu'; +import ConfigMenu from './components/ConfigMenu'; + +import useSaveToLocalStorage from '@hooks/useSaveToLocalStorage'; +import useUpdateCharts from '@hooks/useUpdateChats'; + +import { ChatInterface } from '@type/chat'; + function App() { - return
App
; + useSaveToLocalStorage(); + useUpdateCharts(); + + const [setChats, setMessages, setCurrentChatIndex] = useStore((state) => [ + state.setChats, + state.setMessages, + state.setCurrentChatIndex, + ]); + + useEffect(() => { + // localStorage.removeItem('chats'); + const storedChats = localStorage.getItem('chats'); + if (storedChats) { + try { + const chats: ChatInterface[] = JSON.parse(storedChats); + setChats(chats); + setMessages(chats[0].messages); + setCurrentChatIndex(0); + } catch (e: unknown) { + setChats([]); + setMessages([]); + setCurrentChatIndex(-1); + console.log(e); + } + } else { + setChats([]); + } + }, []); + + return ( +
+ + + +
+ ); } export default App; diff --git a/src/api/customApi.ts b/src/api/customApi.ts new file mode 100644 index 0000000..a8aa777 --- /dev/null +++ b/src/api/customApi.ts @@ -0,0 +1,72 @@ +import { MessageInterface } from '@type/chat'; + +export const endpoint = 'https://api.openai.com/v1/chat/completions'; + +export const validateApiKey = async (apiKey: string) => { + try { + const response = await fetch(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + }, + }); + const data = await response.json(); + console.log(data); + + if (response.status === 401) return false; + else if (response.status === 400) return true; + } catch (error) { + console.error('Error:', error); + return false; + } +}; + +export const getChatCompletion = async ( + apiKey: string, + messages: MessageInterface[] +) => { + try { + const response = await fetch(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + }, + body: JSON.stringify({ + model: 'gpt-3.5-turbo', + messages, + }), + }); + const data = await response.json(); + console.log(data); + return data; + } catch (error) { + console.error('Error:', error); + } +}; + +export const getChatCompletionStream = async ( + apiKey: string, + messages: MessageInterface[] +) => { + try { + const response = await fetch(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + }, + body: JSON.stringify({ + model: 'gpt-3.5-turbo', + messages, + stream: true, + }), + }); + console.log(response); + const stream = response.body; + return stream; + } catch (error) { + console.error('Error:', error); + } +}; diff --git a/src/api/freeApi.ts b/src/api/freeApi.ts new file mode 100644 index 0000000..5378154 --- /dev/null +++ b/src/api/freeApi.ts @@ -0,0 +1,44 @@ +import { MessageInterface } from '@type/chat'; + +export const endpoint = 'https://chatgpt-api.shn.hk/v1/'; + +export const getChatCompletion = async (messages: MessageInterface[]) => { + try { + const response = await fetch(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + model: 'gpt-3.5-turbo', + messages, + }), + }); + const data = await response.json(); + console.log(data); + return data; + } catch (error) { + console.error('Error:', error); + } +}; + +export const getChatCompletionStream = async (messages: MessageInterface[]) => { + try { + const response = await fetch(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + model: 'gpt-3.5-turbo', + messages, + stream: true, + }), + }); + console.log(response); + const stream = response.body; + return stream; + } catch (error) { + console.error('Error:', error); + } +}; diff --git a/src/api/helper.ts b/src/api/helper.ts new file mode 100644 index 0000000..298748f --- /dev/null +++ b/src/api/helper.ts @@ -0,0 +1,19 @@ +import { EventSourceData } from '@type/api'; + +export const parseEventSource = ( + data: string +): '[DONE]' | EventSourceData[] => { + const result = data + .split('\n\n') + .filter(Boolean) + .map((chunk) => { + const jsonString = chunk + .split('\n') + .map((line) => line.replace(/^data: /, '')) + .join(''); + console.log(jsonString); + if (jsonString === '[DONE]') return jsonString; + else return JSON.parse(jsonString); + }); + return result; +}; diff --git a/src/assets/icons/ChatIcon.tsx b/src/assets/icons/ChatIcon.tsx new file mode 100644 index 0000000..00a2d81 --- /dev/null +++ b/src/assets/icons/ChatIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +const ChatIcon = () => { + return ( + + + + ); +}; + +export default ChatIcon; diff --git a/src/assets/icons/CopyIcon.tsx b/src/assets/icons/CopyIcon.tsx new file mode 100644 index 0000000..a10dad8 --- /dev/null +++ b/src/assets/icons/CopyIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +const CopyIcon = () => { + return ( + + + + + ); +}; + +export default CopyIcon; diff --git a/src/assets/icons/CrossIcon.tsx b/src/assets/icons/CrossIcon.tsx new file mode 100644 index 0000000..25f1171 --- /dev/null +++ b/src/assets/icons/CrossIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +const CrossIcon = () => { + return ( + + + + + ); +}; + +export default CrossIcon; diff --git a/src/assets/icons/CrossIcon2.tsx b/src/assets/icons/CrossIcon2.tsx new file mode 100644 index 0000000..e35dd85 --- /dev/null +++ b/src/assets/icons/CrossIcon2.tsx @@ -0,0 +1,21 @@ +import React from 'react'; + +const CrossIcon2 = () => { + return ( + + ); +}; + +export default CrossIcon2; diff --git a/src/assets/icons/DeleteIcon.tsx b/src/assets/icons/DeleteIcon.tsx new file mode 100644 index 0000000..835fdba --- /dev/null +++ b/src/assets/icons/DeleteIcon.tsx @@ -0,0 +1,25 @@ +import React from 'react'; + +const DeleteIcon = () => { + return ( + + + + + + + ); +}; + +export default DeleteIcon; diff --git a/src/assets/icons/DownArrow.tsx b/src/assets/icons/DownArrow.tsx new file mode 100644 index 0000000..9603b08 --- /dev/null +++ b/src/assets/icons/DownArrow.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +const DownArrow = () => { + return ( + + + + + ); +}; + +export default DownArrow; diff --git a/src/assets/icons/DownChevronArrow.tsx b/src/assets/icons/DownChevronArrow.tsx new file mode 100644 index 0000000..931a043 --- /dev/null +++ b/src/assets/icons/DownChevronArrow.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +const DownChevronArrow = ({ className }: { className?: string }) => { + return ( + + ); +}; + +export default DownChevronArrow; diff --git a/src/assets/icons/EditIcon.tsx b/src/assets/icons/EditIcon.tsx new file mode 100644 index 0000000..4b96673 --- /dev/null +++ b/src/assets/icons/EditIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +const EditIcon = () => { + return ( + + + + + ); +}; + +export default EditIcon; diff --git a/src/assets/icons/EditIcon2.tsx b/src/assets/icons/EditIcon2.tsx new file mode 100644 index 0000000..f383812 --- /dev/null +++ b/src/assets/icons/EditIcon2.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +const EditIcon2 = () => { + return ( + + + + + ); +}; + +export default EditIcon2; diff --git a/src/assets/icons/HeartIcon.tsx b/src/assets/icons/HeartIcon.tsx new file mode 100644 index 0000000..08969d3 --- /dev/null +++ b/src/assets/icons/HeartIcon.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +const HeartIcon = () => { + return ( + + + + ); +}; + +export default HeartIcon; diff --git a/src/assets/icons/LinkIcon.tsx b/src/assets/icons/LinkIcon.tsx new file mode 100644 index 0000000..4039744 --- /dev/null +++ b/src/assets/icons/LinkIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; + +const LinkIcon = () => { + return ( + + + + + + ); +}; + +export default LinkIcon; diff --git a/src/assets/icons/LogoutIcon.tsx b/src/assets/icons/LogoutIcon.tsx new file mode 100644 index 0000000..91c4938 --- /dev/null +++ b/src/assets/icons/LogoutIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; + +const LogoutIcon = () => { + return ( + + + + + + ); +}; + +export default LogoutIcon; diff --git a/src/assets/icons/MoonIcon.tsx b/src/assets/icons/MoonIcon.tsx new file mode 100644 index 0000000..840921c --- /dev/null +++ b/src/assets/icons/MoonIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +const MoonIcon = () => { + return ( + + + + ); +}; + +export default MoonIcon; diff --git a/src/assets/icons/PersonIcon.tsx b/src/assets/icons/PersonIcon.tsx new file mode 100644 index 0000000..e913c91 --- /dev/null +++ b/src/assets/icons/PersonIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +const PersonIcon = () => { + return ( + + + + + ); +}; + +export default PersonIcon; diff --git a/src/assets/icons/PlusIcon.tsx b/src/assets/icons/PlusIcon.tsx new file mode 100644 index 0000000..2b2c838 --- /dev/null +++ b/src/assets/icons/PlusIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +const PlusIcon = () => { + return ( + + + + + ); +}; + +export default PlusIcon; diff --git a/src/assets/icons/RefreshIcon.tsx b/src/assets/icons/RefreshIcon.tsx new file mode 100644 index 0000000..de44047 --- /dev/null +++ b/src/assets/icons/RefreshIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; + +const RefreshIcon = () => { + return ( + + + + + + ); +}; + +export default RefreshIcon; diff --git a/src/assets/icons/SendIcon.tsx b/src/assets/icons/SendIcon.tsx new file mode 100644 index 0000000..2574da2 --- /dev/null +++ b/src/assets/icons/SendIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +const SendIcon = () => { + return ( + + + + + ); +}; + +export default SendIcon; diff --git a/src/assets/icons/SettingIcon.tsx b/src/assets/icons/SettingIcon.tsx new file mode 100644 index 0000000..cfbf610 --- /dev/null +++ b/src/assets/icons/SettingIcon.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const SettingIcon = () => { + return ( + + + + ); +}; + +export default SettingIcon; diff --git a/src/assets/icons/SunIcon.tsx b/src/assets/icons/SunIcon.tsx new file mode 100644 index 0000000..72c6de5 --- /dev/null +++ b/src/assets/icons/SunIcon.tsx @@ -0,0 +1,30 @@ +import React from 'react'; + +const SunIcon = () => { + return ( + + + + + + + + + + + + ); +}; + +export default SunIcon; diff --git a/src/assets/icons/TickIcon.tsx b/src/assets/icons/TickIcon.tsx new file mode 100644 index 0000000..6d5d58d --- /dev/null +++ b/src/assets/icons/TickIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +const TickIcon = () => { + return ( + + + + ); +}; + +export default TickIcon; diff --git a/src/components/Chat/Chat.tsx b/src/components/Chat/Chat.tsx new file mode 100644 index 0000000..f239a31 --- /dev/null +++ b/src/components/Chat/Chat.tsx @@ -0,0 +1,19 @@ +import React from 'react'; + +import ChatContent from './ChatContent'; +import ChatInput from './ChatInput'; +import MobileBar from '../MobileBar'; + +const Chat = () => { + return ( +
+ +
+ + {/* */} +
+
+ ); +}; + +export default Chat; diff --git a/src/components/Chat/ChatContent/ChatContent.tsx b/src/components/Chat/ChatContent/ChatContent.tsx new file mode 100644 index 0000000..0436cf4 --- /dev/null +++ b/src/components/Chat/ChatContent/ChatContent.tsx @@ -0,0 +1,116 @@ +import React from 'react'; +import ScrollToBottom from 'react-scroll-to-bottom'; +import useStore from '@store/store'; + +import ScrollToBottomButton from './ScrollToBottomButton'; +import ChatTitle from './ChatTitle'; +import Message from './Message'; +import NewMessageButton from './Message/NewMessageButton'; + +import { getChatCompletionStream as getChatCompletionStreamFree } from '@api/freeApi'; +import { getChatCompletionStream as getChatCompletionStreamCustom } from '@api/customApi'; +import { parseEventSource } from '@api/helper'; + +import RefreshIcon from '@icon/RefreshIcon'; +import { MessageInterface } from '@type/chat'; + +const ChatContent = () => { + const [messages, inputRole, apiFree, apiKey, setMessages] = useStore( + (state) => [ + state.messages, + state.inputRole, + state.apiFree, + state.apiKey, + state.setMessages, + ] + ); + + const handleSubmit = async () => { + const updatedMessages: MessageInterface[] = JSON.parse( + JSON.stringify(messages) + ); + updatedMessages.push({ role: 'assistant', content: '' }); + setMessages(updatedMessages); + let stream; + + if (apiFree) { + stream = await getChatCompletionStreamFree(messages); + } else if (apiKey) { + stream = await getChatCompletionStreamCustom(apiKey, messages); + } + + if (stream) { + const reader = stream.getReader(); + let reading = true; + while (reading) { + const { done, value } = await reader.read(); + + const result = parseEventSource(new TextDecoder().decode(value)); + + if (result === '[DONE]' || done) { + reading = false; + } else { + const resultString = result.reduce((output: string, curr) => { + if (curr === '[DONE]') return output; + else { + const content = curr.choices[0].delta.content; + if (content) output += content; + return output; + } + }, ''); + console.log(resultString); + + const updatedMessages: MessageInterface[] = JSON.parse( + JSON.stringify(useStore.getState().messages) + ); + updatedMessages[updatedMessages.length - 1].content += resultString; + setMessages(updatedMessages); + } + } + } + }; + + return ( +
+ + +
+ + {messages?.length === 0 && } + {messages?.map((message, index) => ( + <> + + + + ))} + + +
+ + +
+
+
+
+
+ ); +}; + +export default ChatContent; diff --git a/src/components/Chat/ChatContent/ChatTitle.tsx b/src/components/Chat/ChatContent/ChatTitle.tsx new file mode 100644 index 0000000..7acab42 --- /dev/null +++ b/src/components/Chat/ChatContent/ChatTitle.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const ChatTitle = () => { + return ( +
+ Model: Default +
+ ); +}; + +export default ChatTitle; diff --git a/src/components/Chat/ChatContent/Message/Avatar.tsx b/src/components/Chat/ChatContent/Message/Avatar.tsx new file mode 100644 index 0000000..bf95c9f --- /dev/null +++ b/src/components/Chat/ChatContent/Message/Avatar.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { Role } from '@type/chat'; +import SettingIcon from '@icon/SettingIcon'; +import PersonIcon from '@icon/PersonIcon'; + +const Avatar = ({ role }: { role: Role }) => { + return ( +
+ {role === 'user' && } + {role === 'assistant' && } + {role === 'system' && } +
+ ); +}; + +const UserAvatar = () => { + return ( +
+ +
+ ); +}; + +const AssistantAvatar = () => { + return ( +
+ + + +
+ ); +}; + +const SystemAvatar = () => { + return ( +
+ +
+ ); +}; + +export default Avatar; diff --git a/src/components/Chat/ChatContent/Message/Message.tsx b/src/components/Chat/ChatContent/Message/Message.tsx new file mode 100644 index 0000000..a7937d9 --- /dev/null +++ b/src/components/Chat/ChatContent/Message/Message.tsx @@ -0,0 +1,50 @@ +import React from 'react'; + +import Avatar from './Avatar'; +import MessageContent from './MessageContent'; + +import { Role } from '@type/chat'; +import RoleSelector from './RoleSelector'; + +const backgroundStyle: { [role in Role]: string } = { + user: 'dark:bg-gray-800', + assistant: 'bg-gray-50 dark:bg-[#444654]', + system: 'bg-gray-50 dark:bg-[#444654]', +}; + +const Message = ({ + role, + content, + messageIndex, + sticky = false, +}: { + role: Role; + content: string; + messageIndex: number; + sticky?: boolean; +}) => { + return ( +
+
+ +
+ + +
+
+
+ ); +}; + +export default Message; diff --git a/src/components/Chat/ChatContent/Message/MessageContent.tsx b/src/components/Chat/ChatContent/Message/MessageContent.tsx new file mode 100644 index 0000000..3a2f1b5 --- /dev/null +++ b/src/components/Chat/ChatContent/Message/MessageContent.tsx @@ -0,0 +1,289 @@ +import React, { useState } from 'react'; +import ReactMarkdown from 'react-markdown'; +import hljs from 'highlight.js'; +import DOMPurify from 'dompurify'; +import useStore from '@store/store'; + +import CopyIcon from '@icon/CopyIcon'; +import EditIcon2 from '@icon/EditIcon2'; +import DeleteIcon from '@icon/DeleteIcon'; +import TickIcon from '@icon/TickIcon'; +import CrossIcon from '@icon/CrossIcon'; +import DownChevronArrow from '@icon/DownChevronArrow'; + +import { MessageInterface } from '@type/chat'; + +const MessageContent = ({ + content, + messageIndex, + sticky = false, +}: { + content: string; + messageIndex: number; + sticky?: boolean; +}) => { + const [isEdit, setIsEdit] = useState(sticky); + + return ( +
+
+ {isEdit ? ( + + ) : ( + + )} +
+ ); +}; + +const ContentView = ({ + content, + setIsEdit, + messageIndex, +}: { + content: string; + setIsEdit: React.Dispatch>; + messageIndex: number; +}) => { + const [isDelete, setIsDelete] = useState(false); + const [copied, setCopied] = useState(false); + + const [messages, setMessages] = useStore((state) => [ + state.messages, + state.setMessages, + ]); + + const handleDelete = () => { + const updatedMessages = JSON.parse(JSON.stringify(messages)); + updatedMessages.splice(messageIndex, 1); + setMessages(updatedMessages); + }; + + const handleMove = (direction: 'up' | 'down') => { + const updatedMessages = JSON.parse(JSON.stringify(messages)); + const temp = updatedMessages[messageIndex]; + if (direction === 'up') { + updatedMessages[messageIndex] = updatedMessages[messageIndex - 1]; + updatedMessages[messageIndex - 1] = temp; + } else { + updatedMessages[messageIndex] = updatedMessages[messageIndex + 1]; + updatedMessages[messageIndex + 1] = temp; + } + setMessages(updatedMessages); + }; + + return ( + <> +
+ +
+ {highlight.language} + +
+
+ +
+ +
+
+ ); + }, + }} + > + {content} +
+
+
+ {isDelete || ( + <> + {messageIndex !== 0 && ( + handleMove('up')} /> + )} + {messageIndex !== messages?.length - 1 && ( + handleMove('down')} /> + )} + + + + )} + {isDelete && ( + <> + + + + )} +
+ + ); +}; + +const MessageButton = ({ + onClick, + icon, +}: { + onClick: React.MouseEventHandler; + icon: React.ReactElement; +}) => { + return ( +
+ +
+ ); +}; + +const EditButton = ({ + setIsEdit, +}: { + setIsEdit: React.Dispatch>; +}) => { + return } onClick={() => setIsEdit(true)} />; +}; + +const DeleteButton = ({ + setIsDelete, +}: { + setIsDelete: React.Dispatch>; +}) => { + return ( + } onClick={() => setIsDelete(true)} /> + ); +}; + +const DownButton = ({ + onClick, +}: { + onClick: React.MouseEventHandler; +}) => { + return } onClick={onClick} />; +}; + +const UpButton = ({ + onClick, +}: { + onClick: React.MouseEventHandler; +}) => { + return ( + } + onClick={onClick} + /> + ); +}; + +const EditView = ({ + content, + setIsEdit, + messageIndex, + sticky, +}: { + content: string; + setIsEdit: React.Dispatch>; + messageIndex: number; + sticky?: boolean; +}) => { + const [messages, setMessages, inputRole] = useStore((state) => [ + state.messages, + state.setMessages, + state.inputRole, + ]); + + const [_content, _setContent] = useState(content); + + return ( + <> + +
+ + {sticky || ( + + )} +
+ + ); +}; + +export default MessageContent; diff --git a/src/components/Chat/ChatContent/Message/NewMessageButton.tsx b/src/components/Chat/ChatContent/Message/NewMessageButton.tsx new file mode 100644 index 0000000..a6fa240 --- /dev/null +++ b/src/components/Chat/ChatContent/Message/NewMessageButton.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import useStore from '@store/store'; + +import PlusIcon from '@icon/PlusIcon'; + +import { ChatInterface, MessageInterface } from '@type/chat'; +import { defaultSystemMessage } from '@constants/chat'; + +const NewMessageButton = ({ messageIndex }: { messageIndex: number }) => { + const [ + messages, + chats, + setMessages, + currentChatIndex, + setChats, + setCurrentChatIndex, + ] = useStore((state) => [ + state.messages, + state.chats, + state.setMessages, + state.currentChatIndex, + state.setChats, + state.setCurrentChatIndex, + ]); + + const addChat = () => { + if (chats) { + const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats)); + updatedChats.unshift({ + title: `Chat ${Math.random()}`, + messages: [{ role: 'system', content: defaultSystemMessage }], + }); + setChats(updatedChats); + setMessages(updatedChats[0].messages); + setCurrentChatIndex(0); + } + }; + + const addMessage = () => { + if (currentChatIndex === -1) { + addChat(); + } else { + const updatedMessages: MessageInterface[] = JSON.parse( + JSON.stringify(messages) + ); + updatedMessages.splice(messageIndex + 1, 0, { + content: '', + role: 'user', + }); + setMessages(updatedMessages); + } + }; + + return ( +
+
+ +
+
+ ); +}; + +export default NewMessageButton; diff --git a/src/components/Chat/ChatContent/Message/RoleSelector.tsx b/src/components/Chat/ChatContent/Message/RoleSelector.tsx new file mode 100644 index 0000000..ad445cd --- /dev/null +++ b/src/components/Chat/ChatContent/Message/RoleSelector.tsx @@ -0,0 +1,70 @@ +import React, { useState } from 'react'; +import useStore from '@store/store'; + +import DownChevronArrow from '@icon/DownChevronArrow'; +import { MessageInterface, Role, roles } from '@type/chat'; + +const RoleSelector = ({ + role, + messageIndex, + sticky, +}: { + role: Role; + messageIndex: number; + sticky?: boolean; +}) => { + const [messages, setMessages, setInputRole] = useStore((state) => [ + state.messages, + state.setMessages, + state.setInputRole, + ]); + + const [dropDown, setDropDown] = useState(false); + + return ( +
+ + +
+ ); +}; + +export default RoleSelector; diff --git a/src/components/Chat/ChatContent/Message/index.ts b/src/components/Chat/ChatContent/Message/index.ts new file mode 100644 index 0000000..a8132ba --- /dev/null +++ b/src/components/Chat/ChatContent/Message/index.ts @@ -0,0 +1 @@ +export { default } from './Message'; diff --git a/src/components/Chat/ChatContent/ScrollToBottomButton.tsx b/src/components/Chat/ChatContent/ScrollToBottomButton.tsx new file mode 100644 index 0000000..0318c03 --- /dev/null +++ b/src/components/Chat/ChatContent/ScrollToBottomButton.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { useScrollToBottom } from 'react-scroll-to-bottom'; + +import DownArrow from '@icon/DownArrow'; + +const ScrollToBottomButton = () => { + const scrollToBottom = useScrollToBottom(); + return ( + + ); +}; + +export default ScrollToBottomButton; diff --git a/src/components/Chat/ChatContent/index.ts b/src/components/Chat/ChatContent/index.ts new file mode 100644 index 0000000..7e8f774 --- /dev/null +++ b/src/components/Chat/ChatContent/index.ts @@ -0,0 +1 @@ +export { default } from './ChatContent'; diff --git a/src/components/Chat/ChatInput.tsx b/src/components/Chat/ChatInput.tsx new file mode 100644 index 0000000..9edc276 --- /dev/null +++ b/src/components/Chat/ChatInput.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import RefreshIcon from '@icon/RefreshIcon'; +import SendIcon from '@icon/SendIcon'; + +const ChatInput = () => { + return ( +
+
+
+ +
+
+
+ ); +}; + +const TextField = () => { + return ( +
+ + +
+ ); +}; + +export default ChatInput; diff --git a/src/components/Chat/index.ts b/src/components/Chat/index.ts new file mode 100644 index 0000000..654497b --- /dev/null +++ b/src/components/Chat/index.ts @@ -0,0 +1 @@ +export { default } from './Chat'; diff --git a/src/components/ConfigMenu/ConfigMenu.tsx b/src/components/ConfigMenu/ConfigMenu.tsx new file mode 100644 index 0000000..9bd0d2f --- /dev/null +++ b/src/components/ConfigMenu/ConfigMenu.tsx @@ -0,0 +1,141 @@ +import React, { useState } from 'react'; +import useStore from '@store/store'; + +import CrossIcon2 from '@icon/CrossIcon2'; +import { validateApiKey } from '@api/customApi'; + +const ConfigMenu = () => { + const [apiKey, setApiKey, apiFree, setApiFree, openConfig, setOpenConfig] = + useStore((state) => [ + state.apiKey, + state.setApiKey, + state.apiFree, + state.setApiFree, + state.openConfig, + state.setOpenConfig, + ]); + + const [_apiKey, _setApiKey] = useState(apiKey || ''); + const [error, setError] = useState(false); + + const handleSave = async () => { + if (apiFree === true) { + setOpenConfig(false); + } else { + const valid = await validateApiKey(_apiKey); + + if (valid) { + setApiKey(_apiKey); + localStorage.setItem('apiKey', _apiKey); + setError(false); + setOpenConfig(false); + } else { + setError(true); + setTimeout(() => { + setError(false); + }, 3000); + } + } + }; + + const handleClose = () => { + setOpenConfig(false); + }; + + return openConfig ? ( +
+
+
+
+

+ Config +

+ +
+
+
+ setApiFree(true)} + /> + +
+ +
+ setApiFree(false)} + /> + +
+ + {apiFree === false && ( + <> +
+
+ API Key +
+ { + _setApiKey(e.target.value); + }} + /> +
+ {error && ( +
+ Invalid API key! +
+ )} + + )} +
+ +
+ + +
+
+
+
+ ) : ( + <> + ); +}; + +export default ConfigMenu; diff --git a/src/components/ConfigMenu/index.ts b/src/components/ConfigMenu/index.ts new file mode 100644 index 0000000..6497639 --- /dev/null +++ b/src/components/ConfigMenu/index.ts @@ -0,0 +1 @@ +export { default } from './ConfigMenu'; diff --git a/src/components/Menu/ChatHistoryList.tsx b/src/components/Menu/ChatHistoryList.tsx new file mode 100644 index 0000000..1202fe5 --- /dev/null +++ b/src/components/Menu/ChatHistoryList.tsx @@ -0,0 +1,164 @@ +import React, { MouseEventHandler, useEffect, useState } from 'react'; +import useStore from '@store/store'; + +import ChatIcon from '@icon/ChatIcon'; +import EditIcon from '@icon/EditIcon'; +import DeleteIcon from '@icon/DeleteIcon'; +import TickIcon from '@icon/TickIcon'; +import CrossIcon from '@icon/CrossIcon'; + +const ChatHistoryList = () => { + const [chats, setCurrentChatIndex, setMessages] = useStore((state) => [ + state.chats, + state.setCurrentChatIndex, + state.setMessages, + ]); + + return ( +
+
+ {chats && + chats.map((chat, index) => ( + { + setCurrentChatIndex(index); + setMessages(chats[index].messages); + }} + /> + ))} + {/* */} +
+
+ ); +}; + +const ShowMoreButton = () => { + return ( + + ); +}; + +const ChatHistoryClass = { + normal: + 'flex py-3 px-3 items-center gap-3 relative rounded-md hover:bg-[#2A2B32] cursor-pointer break-all hover:pr-4 group', + active: + 'flex py-3 px-3 items-center gap-3 relative rounded-md cursor-pointer break-all pr-14 bg-gray-800 hover:bg-gray-800 group', + normalGradient: + 'absolute inset-y-0 right-0 w-8 z-10 bg-gradient-to-l from-gray-900 group-hover:from-[#2A2B32]', + activeGradient: + 'absolute inset-y-0 right-0 w-8 z-10 bg-gradient-to-l from-gray-800', +}; + +const ChatHistory = ({ + title, + chatIndex, + onClick, +}: { + title: string; + chatIndex: number; + onClick?: React.MouseEventHandler; +}) => { + const [chats, setChats, currentChatIndex, setMessages, setCurrentChatIndex] = + useStore((state) => [ + state.chats, + state.setChats, + state.currentChatIndex, + state.setMessages, + state.setCurrentChatIndex, + ]); + + const [isDelete, setIsDelete] = useState(false); + const [isEdit, setIsEdit] = useState(false); + const [_title, _setTitle] = useState(title); + + const active = currentChatIndex === chatIndex; + + const handleTick = (e: React.MouseEvent) => { + e.stopPropagation(); + const updatedChats = JSON.parse(JSON.stringify(chats)); + if (isEdit) { + updatedChats[chatIndex].title = _title; + setIsEdit(false); + } else if (isDelete) { + updatedChats.splice(chatIndex, 1); + setCurrentChatIndex(-1); + setMessages([]); + setIsDelete(false); + } + setTimeout(() => { + setChats(updatedChats); + }, 0); + }; + + const handleCross = () => { + setIsDelete(false); + setIsEdit(false); + }; + + return ( + onClick && onClick(e)} + > + +
+ {isEdit ? ( + { + _setTitle(e.target.value); + }} + /> + ) : ( + _title + )} + +
+
+ {active && ( +
+ {isDelete || isEdit ? ( + <> + + + + ) : ( + <> + + + + )} +
+ )} +
+ ); +}; + +export default ChatHistoryList; diff --git a/src/components/Menu/Menu.tsx b/src/components/Menu/Menu.tsx new file mode 100644 index 0000000..301cdd8 --- /dev/null +++ b/src/components/Menu/Menu.tsx @@ -0,0 +1,39 @@ +import React from 'react'; + +import NewChat from './NewChat'; +import ChatHistoryList from './ChatHistoryList'; +import MenuOptions from './MenuOptions'; +import CrossIcon2 from '@icon/CrossIcon2'; + +const Menu = () => { + return ( + + ); +}; + +export default Menu; diff --git a/src/components/Menu/MenuOptions/Account.tsx b/src/components/Menu/MenuOptions/Account.tsx new file mode 100644 index 0000000..481eee4 --- /dev/null +++ b/src/components/Menu/MenuOptions/Account.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import PersonIcon from '@icon/PersonIcon'; + +const Account = () => { + return ( + + + My account + + ); +}; + +export default Account; diff --git a/src/components/Menu/MenuOptions/ClearConversation.tsx b/src/components/Menu/MenuOptions/ClearConversation.tsx new file mode 100644 index 0000000..9c054e1 --- /dev/null +++ b/src/components/Menu/MenuOptions/ClearConversation.tsx @@ -0,0 +1,14 @@ +import React from 'react'; + +import DeleteIcon from '@icon/DeleteIcon'; + +const ClearConversation = () => { + return ( + + + Clear conversations + + ); +}; + +export default ClearConversation; diff --git a/src/components/Menu/MenuOptions/Config.tsx b/src/components/Menu/MenuOptions/Config.tsx new file mode 100644 index 0000000..4dd7d3e --- /dev/null +++ b/src/components/Menu/MenuOptions/Config.tsx @@ -0,0 +1,23 @@ +import React, { useState } from 'react'; +import useStore from '@store/store'; + +import PersonIcon from '@icon/PersonIcon'; + +const Config = () => { + const [apiFree, setOpenConfig] = useStore((state) => [ + state.apiFree, + state.setOpenConfig, + ]); + + return ( + setOpenConfig(true)} + > + + API: {apiFree ? 'Free' : 'Personal'} + + ); +}; + +export default Config; diff --git a/src/components/Menu/MenuOptions/Logout.tsx b/src/components/Menu/MenuOptions/Logout.tsx new file mode 100644 index 0000000..6d68408 --- /dev/null +++ b/src/components/Menu/MenuOptions/Logout.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import LogoutIcon from '@icon/LogoutIcon'; + +const Logout = () => { + return ( + + + Log out + + ); +}; + +export default Logout; diff --git a/src/components/Menu/MenuOptions/Me.tsx b/src/components/Menu/MenuOptions/Me.tsx new file mode 100644 index 0000000..e3796d5 --- /dev/null +++ b/src/components/Menu/MenuOptions/Me.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +import HeartIcon from '@icon/HeartIcon'; + +const Me = () => { + return ( + + + Made by Jing Hua + + ); +}; + +export default Me; diff --git a/src/components/Menu/MenuOptions/MenuOptions.tsx b/src/components/Menu/MenuOptions/MenuOptions.tsx new file mode 100644 index 0000000..72d83e4 --- /dev/null +++ b/src/components/Menu/MenuOptions/MenuOptions.tsx @@ -0,0 +1,25 @@ +import React from 'react'; + +import Account from './Account'; +import ClearConversation from './ClearConversation'; +import Config from './Config'; +import Logout from './Logout'; +import Me from './Me'; +import ThemeSwitcher from './ThemeSwitcher'; +import Updates from './Updates'; + +const MenuOptions = () => { + return ( + <> + {/* */} + + + {/* */} + + + {/* */} + + ); +}; + +export default MenuOptions; diff --git a/src/components/Menu/MenuOptions/ThemeSwitcher.tsx b/src/components/Menu/MenuOptions/ThemeSwitcher.tsx new file mode 100644 index 0000000..67372d1 --- /dev/null +++ b/src/components/Menu/MenuOptions/ThemeSwitcher.tsx @@ -0,0 +1,38 @@ +import React, { useEffect, useState } from 'react'; +import SunIcon from '@icon/SunIcon'; +import MoonIcon from '@icon/MoonIcon'; + +type Theme = 'light' | 'dark'; + +const getOppositeTheme = (theme: Theme): Theme => { + if (theme === 'dark') { + return 'light'; + } else { + return 'dark'; + } +}; +const ThemeSwitcher = () => { + const [theme, setTheme] = useState('dark'); + + const switchTheme = () => { + setTheme(getOppositeTheme(theme)); + }; + + useEffect(() => { + document.documentElement.className = theme; + }, [theme]); + + return ( + + {theme === 'dark' ? : } + {getOppositeTheme(theme).charAt(0).toUpperCase() + + getOppositeTheme(theme).slice(1)}{' '} + mode + + ); +}; + +export default ThemeSwitcher; diff --git a/src/components/Menu/MenuOptions/Updates.tsx b/src/components/Menu/MenuOptions/Updates.tsx new file mode 100644 index 0000000..c4e1bb6 --- /dev/null +++ b/src/components/Menu/MenuOptions/Updates.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import LinkIcon from '@icon/LinkIcon'; + +const Updates = () => { + return ( + + + Source Code + + ); +}; + +export default Updates; diff --git a/src/components/Menu/MenuOptions/index.ts b/src/components/Menu/MenuOptions/index.ts new file mode 100644 index 0000000..99449e8 --- /dev/null +++ b/src/components/Menu/MenuOptions/index.ts @@ -0,0 +1 @@ +export { default } from './MenuOptions'; diff --git a/src/components/Menu/NewChat.tsx b/src/components/Menu/NewChat.tsx new file mode 100644 index 0000000..40774b8 --- /dev/null +++ b/src/components/Menu/NewChat.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import useStore from '@store/store'; + +import PlusIcon from '@icon/PlusIcon'; + +import { ChatInterface } from '@type/chat'; +import { defaultSystemMessage } from '@constants/chat'; + +const NewChat = () => { + const [chats, setChats, setCurrentChatIndex, setMessages] = useStore( + (state) => [ + state.chats, + state.setChats, + state.setCurrentChatIndex, + state.setMessages, + ] + ); + + const addChat = () => { + if (chats) { + const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats)); + updatedChats.unshift({ + title: `Chat ${Math.random()}`, + messages: [{ role: 'system', content: defaultSystemMessage }], + }); + setChats(updatedChats); + setMessages(updatedChats[0].messages); + setCurrentChatIndex(0); + } + }; + + return ( + + {' '} + New chat + + ); +}; + +export default NewChat; diff --git a/src/components/Menu/index.ts b/src/components/Menu/index.ts new file mode 100644 index 0000000..a6de24c --- /dev/null +++ b/src/components/Menu/index.ts @@ -0,0 +1 @@ +export { default } from './Menu'; diff --git a/src/components/MobileBar/MobileBar.tsx b/src/components/MobileBar/MobileBar.tsx new file mode 100644 index 0000000..d524ee1 --- /dev/null +++ b/src/components/MobileBar/MobileBar.tsx @@ -0,0 +1,53 @@ +import React from 'react'; + +import useStore from '@store/store'; + +import NewChat from '../Menu/NewChat'; + +const MobileBar = () => { + const [chats, currentChatIndex] = useStore((state) => [ + state.chats, + state.currentChatIndex, + ]); + + return ( +
+ +

+ {chats && chats.length > 0 + ? chats[currentChatIndex]?.title + : 'New Chat'} +

+ +
+ ); +}; + +export default MobileBar; diff --git a/src/components/MobileBar/index.ts b/src/components/MobileBar/index.ts new file mode 100644 index 0000000..73bbfef --- /dev/null +++ b/src/components/MobileBar/index.ts @@ -0,0 +1 @@ +export { default } from './MobileBar'; diff --git a/src/constants/chat.ts b/src/constants/chat.ts new file mode 100644 index 0000000..82f6570 --- /dev/null +++ b/src/constants/chat.ts @@ -0,0 +1,12 @@ +const date = new Date(); +const dateString = + date.getFullYear() + + '-' + + ('0' + (date.getMonth() + 1)).slice(-2) + + '-' + + ('0' + date.getDate()).slice(-2); + +// default system message obtained using the following method: https://twitter.com/DeminDimin/status/1619935545144279040 +export const defaultSystemMessage = `You are ChatGPT, a large language model trained by OpenAI. +Knowledge cutoff: 2021-09 +Current date: ${dateString}`; diff --git a/src/hooks/useSaveToLocalStorage.ts b/src/hooks/useSaveToLocalStorage.ts new file mode 100644 index 0000000..ee98b41 --- /dev/null +++ b/src/hooks/useSaveToLocalStorage.ts @@ -0,0 +1,12 @@ +import React, { useEffect } from 'react'; +import useStore from '@store/store'; + +const useSaveToLocalStorage = () => { + const chats = useStore((state) => state.chats); + + useEffect(() => { + if (chats) localStorage.setItem('chats', JSON.stringify(chats)); + }, [chats]); +}; + +export default useSaveToLocalStorage; diff --git a/src/hooks/useUpdateChats.ts b/src/hooks/useUpdateChats.ts new file mode 100644 index 0000000..6b9023e --- /dev/null +++ b/src/hooks/useUpdateChats.ts @@ -0,0 +1,25 @@ +import React, { useEffect } from 'react'; +import useStore from '@store/store'; +import { ChatInterface, MessageInterface } from '@type/chat'; + +const useUpdateCharts = () => { + const [chats, messages, setChats, currentChatIndex] = useStore((state) => [ + state.chats, + state.messages, + state.setChats, + state.currentChatIndex, + ]); + + useEffect(() => { + if (currentChatIndex !== -1 && chats && chats.length > 0) { + const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats)); + const updatedMessages: MessageInterface[] = JSON.parse( + JSON.stringify(messages) + ); + updatedChats[currentChatIndex].messages = updatedMessages; + setChats(updatedChats); + } + }, [messages]); +}; + +export default useUpdateCharts; diff --git a/src/index.css b/src/index.css deleted file mode 100644 index b5c61c9..0000000 --- a/src/index.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/src/main.css b/src/main.css new file mode 100644 index 0000000..ed51e17 --- /dev/null +++ b/src/main.css @@ -0,0 +1,207 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + * { + box-sizing: border-box; + } + + body, + html { + height: 100%; + } + + body { + line-height: inherit; + margin: 0; + } + + .dark body, + .dark html { + --tw-bg-opacity: 1; + background-color: rgba(52, 53, 65, var(--tw-bg-opacity)); + } + + #root { + height: 100%; + } + + ::-webkit-scrollbar { + height: 1rem; + width: 0.5rem; + } + @media screen and (min-width: 768px) { + .scrollbar-trigger ::-webkit-scrollbar-thumb { + visibility: hidden; + } + } + + .dark::-webkit-scrollbar-thumb { + --tw-bg-opacity: 1; + background-color: rgba(86, 88, 105, var(--tw-bg-opacity)); + } + + ::-webkit-scrollbar-thumb { + --tw-border-opacity: 1; + background-color: rgba(217, 217, 227, 0.8); + border-color: rgba(255, 255, 255, var(--tw-border-opacity)); + border-radius: 9999px; + border-width: 1px; + } + + ::-webkit-scrollbar-track { + background-color: transparent; + border-radius: 9999px; + } + + textarea:focus { + outline: none; + } +} + +@layer components { + .btn { + align-items: center; + border-color: transparent; + border-radius: 0.25rem; + border-width: 1px; + display: inline-flex; + font-size: 0.875rem; + line-height: 1.25rem; + padding: 0.5rem 0.75rem; + pointer-events: auto; + } + + .btn-neutral { + --tw-bg-opacity: 1; + --tw-text-opacity: 1; + background-color: rgba(255, 255, 255, var(--tw-bg-opacity)); + border-color: rgba(0, 0, 0, 0.1); + border-width: 1px; + color: rgba(64, 65, 79, var(--tw-text-opacity)); + font-size: 0.875rem; + line-height: 1.25rem; + } + + .btn-neutral:hover { + --tw-bg-opacity: 1; + background-color: rgba(236, 236, 241, var(--tw-bg-opacity)); + } + + .dark .btn-neutral { + --tw-border-opacity: 1; + --tw-bg-opacity: 1; + --tw-text-opacity: 1; + background-color: rgba(52, 53, 65, var(--tw-bg-opacity)); + border-color: rgba(86, 88, 105, var(--tw-border-opacity)); + color: rgba(217, 217, 227, var(--tw-text-opacity)); + } + + .dark .btn-neutral:hover { + --tw-bg-opacity: 1; + background-color: rgba(64, 65, 79, var(--tw-bg-opacity)); + } + + .btn-dark { + --tw-border-opacity: 1; + --tw-bg-opacity: 1; + --tw-text-opacity: 1; + background-color: rgba(52, 53, 65, var(--tw-bg-opacity)); + border-color: rgba(86, 88, 105, var(--tw-border-opacity)); + border-width: 1px; + color: rgba(255, 255, 255, var(--tw-text-opacity)); + } + + .btn-primary { + --tw-bg-opacity: 1; + --tw-text-opacity: 1; + background-color: rgba(16, 163, 127, var(--tw-bg-opacity)); + color: rgba(255, 255, 255, var(--tw-text-opacity)); + } + + .btn-primary:hover { + --tw-bg-opacity: 1; + background-color: rgba(26, 127, 100, var(--tw-bg-opacity)); + } + + .btn-small { + padding: 0.25rem 0.5rem; + } + + button.scroll-convo { + display: none; + } + + .markdown ol, + .markdown ul { + display: flex; + flex-direction: column; + padding-left: 1rem; + } + + .markdown ol li, + .markdown ol li > p, + .markdown ol ol, + .markdown ol ul, + .markdown ul li, + .markdown ul li > p, + .markdown ul ol, + .markdown ul ul { + margin: 0; + } + + .markdown ul li:before { + content: '•'; + font-size: 0.875rem; + line-height: 1.25rem; + margin-left: -1rem; + position: absolute; + } +} + +:not(pre) > code.hljs, +:not(pre) > code[class*='language-'] { + border-radius: 0.3em; + white-space: normal; +} +.hljs-comment { + color: hsla(0, 0%, 100%, 0.5); +} +.hljs-meta { + color: hsla(0, 0%, 100%, 0.6); +} +.hljs-built_in, +.hljs-class .hljs-title { + color: #e9950c; +} +.hljs-doctag, +.hljs-formula, +.hljs-keyword, +.hljs-literal { + color: #2e95d3; +} +.hljs-addition, +.hljs-attribute, +.hljs-meta-string, +.hljs-regexp, +.hljs-string { + color: #00a67d; +} +.hljs-attr, +.hljs-number, +.hljs-selector-attr, +.hljs-selector-class, +.hljs-selector-pseudo, +.hljs-template-variable, +.hljs-type, +.hljs-variable { + color: #df3079; +} +.hljs-bullet, +.hljs-link, +.hljs-selector-id, +.hljs-symbol, +.hljs-title { + color: #f22c3d; +} diff --git a/src/main.tsx b/src/main.tsx index a2bf01b..f4721f7 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; -import './index.css'; +import './main.css'; ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( diff --git a/src/store/auth-slice.ts b/src/store/auth-slice.ts new file mode 100644 index 0000000..994cd59 --- /dev/null +++ b/src/store/auth-slice.ts @@ -0,0 +1,24 @@ +import { StoreSlice } from './store'; + +export interface AuthSlice { + apiKey?: string; + apiFree: boolean; + setApiKey: (apiKey: string) => void; + setApiFree: (apiFree: boolean) => void; +} + +export const createAuthSlice: StoreSlice = (set, get) => ({ + apiFree: true, + setApiKey: (apiKey: string) => { + set((prev: AuthSlice) => ({ + ...prev, + apiKey: apiKey, + })); + }, + setApiFree: (apiFree: boolean) => { + set((prev: AuthSlice) => ({ + ...prev, + apiFree: apiFree, + })); + }, +}); diff --git a/src/store/chat-slice.ts b/src/store/chat-slice.ts new file mode 100644 index 0000000..3610a4b --- /dev/null +++ b/src/store/chat-slice.ts @@ -0,0 +1,34 @@ +import { StoreSlice } from './store'; +import { ChatInterface, MessageInterface } from '@type/chat'; + +export interface ChatSlice { + messages: MessageInterface[]; + chats?: ChatInterface[]; + currentChatIndex: number; + setMessages: (messages: MessageInterface[]) => void; + setChats: (chats: ChatInterface[]) => void; + setCurrentChatIndex: (currentChatIndex: number) => void; +} + +export const createChatSlice: StoreSlice = (set, get) => ({ + messages: [], + currentChatIndex: -1, + setMessages: (messages: MessageInterface[]) => { + set((prev: ChatSlice) => ({ + ...prev, + messages: messages, + })); + }, + setChats: (chats: ChatInterface[]) => { + set((prev: ChatSlice) => ({ + ...prev, + chats: chats, + })); + }, + setCurrentChatIndex: (currentChatIndex: number) => { + set((prev: ChatSlice) => ({ + ...prev, + currentChatIndex: currentChatIndex, + })); + }, +}); diff --git a/src/store/config-slice.ts b/src/store/config-slice.ts new file mode 100644 index 0000000..4103f9e --- /dev/null +++ b/src/store/config-slice.ts @@ -0,0 +1,16 @@ +import { StoreSlice } from './store'; + +export interface ConfigSlice { + openConfig: boolean; + setOpenConfig: (openConfig: boolean) => void; +} + +export const createConfigSlice: StoreSlice = (set, get) => ({ + openConfig: false, + setOpenConfig: (openConfig: boolean) => { + set((prev: ConfigSlice) => ({ + ...prev, + openConfig: openConfig, + })); + }, +}); diff --git a/src/store/input-slice.ts b/src/store/input-slice.ts new file mode 100644 index 0000000..6741910 --- /dev/null +++ b/src/store/input-slice.ts @@ -0,0 +1,17 @@ +import { StoreSlice } from './store'; +import { Role } from '@type/chat'; + +export interface InputSlice { + inputRole: Role; + setInputRole: (inputRole: Role) => void; +} + +export const createInputSlice: StoreSlice = (set, get) => ({ + inputRole: 'user', + setInputRole: (inputRole: Role) => { + set((prev: InputSlice) => ({ + ...prev, + inputRole: inputRole, + })); + }, +}); diff --git a/src/store/store.ts b/src/store/store.ts new file mode 100644 index 0000000..b816643 --- /dev/null +++ b/src/store/store.ts @@ -0,0 +1,21 @@ +import create, { SetState, GetState } from 'zustand'; +import { ChatSlice, createChatSlice } from './chat-slice'; +import { InputSlice, createInputSlice } from './input-slice'; +import { AuthSlice, createAuthSlice } from './auth-slice'; +import { ConfigSlice, createConfigSlice } from './config-slice'; + +export type StoreState = ChatSlice & InputSlice & AuthSlice & ConfigSlice; + +export type StoreSlice = ( + set: SetState, + get: GetState +) => T; + +const useStore = create((set, get) => ({ + ...createChatSlice(set, get), + ...createInputSlice(set, get), + ...createAuthSlice(set, get), + ...createConfigSlice(set, get), +})); + +export default useStore; diff --git a/src/types/api.ts b/src/types/api.ts new file mode 100644 index 0000000..54fa696 --- /dev/null +++ b/src/types/api.ts @@ -0,0 +1,18 @@ +export interface EventSourceDataInterface { + choices: EventSourceDataChoices[]; + created: number; + id: string; + model: string; + object: string; +} + +export type EventSourceData = EventSourceDataInterface | '[DONE]'; + +export interface EventSourceDataChoices { + delta: { + content?: string; + role?: string; + }; + finish_reason?: string; + index: number; +} diff --git a/src/types/chat.ts b/src/types/chat.ts new file mode 100644 index 0000000..651020e --- /dev/null +++ b/src/types/chat.ts @@ -0,0 +1,12 @@ +export type Role = 'user' | 'assistant' | 'system'; +export const roles: Role[] = ['user', 'assistant', 'system']; + +export interface MessageInterface { + role: Role; + content: string; +} + +export interface ChatInterface { + title: string; + messages: MessageInterface[]; +} diff --git a/tailwind.config.cjs b/tailwind.config.cjs index 62c6d9c..54bacb7 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -2,7 +2,40 @@ module.exports = { content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], theme: { - extend: {}, + fontFamily: { + sans: [ + 'Söhne', + 'ui-sans-serif', + 'system-ui', + '-apple-system', + 'Segoe UI', + 'Roboto', + 'Ubuntu', + 'Cantarell', + 'Noto Sans', + 'sans-serif', + 'Helvetica Neue', + 'Arial', + 'Apple Color Emoji', + 'Segoe UI Emoji', + 'Segoe UI Symbol', + 'Noto Color Emoji', + ], + mono: ['Söhne Mono', 'Monaco', 'Andale Mono', 'Ubuntu Mono', 'monospace'], + }, + extend: { + typography: { + DEFAULT: { + css: { + pre: { padding: 0, margin: 0 }, + ul: { + 'list-style-type': 'none', + }, + }, + }, + }, + }, }, - plugins: [], + plugins: [require('@tailwindcss/typography')], + darkMode: 'class', }; diff --git a/tsconfig.json b/tsconfig.json index 3d0a51a..8e3a564 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,16 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx" + "jsx": "react-jsx", + "baseUrl": ".", + "paths": { + "@icon/*": ["./src/assets/icons/*"], + "@type/*": ["./src/types/*"], + "@store/*": ["./src/store/*"], + "@hooks/*": ["./src/hooks/*"], + "@constants/*": ["./src/constants/*"], + "@api/*": ["./src/api/*"] + } }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }] diff --git a/vite.config.ts b/vite.config.ts index 861b04b..6741cd2 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,17 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react-swc' +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react-swc'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], -}) + resolve: { + alias: { + '@icon/': new URL('./src/assets/icons/', import.meta.url).pathname, + '@type/': new URL('./src/types/', import.meta.url).pathname, + '@store/': new URL('./src/store/', import.meta.url).pathname, + '@hooks/': new URL('./src/hooks/', import.meta.url).pathname, + '@constants/': new URL('./src/constants/', import.meta.url).pathname, + '@api/': new URL('./src/api/', import.meta.url).pathname, + }, + }, +}); diff --git a/yarn.lock b/yarn.lock index 0133387..de2ec30 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,143 @@ # yarn lockfile v1 +"@babel/code-frame@^7.0.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/helper-module-imports@^7.16.7": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" + integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/runtime-corejs3@^7.15.4": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz#6e4939d9d9789ff63e2dc58e88f13a3913a24eba" + integrity sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw== + dependencies: + core-js-pure "^3.25.1" + regenerator-runtime "^0.13.11" + +"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" + integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/types@^7.18.6": + version "7.21.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" + integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw== + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + +"@emotion/babel-plugin@^11.0.0": + version "11.10.6" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz#a68ee4b019d661d6f37dec4b8903255766925ead" + integrity sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/serialize" "^1.1.1" + babel-plugin-macros "^3.1.0" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.1.3" + +"@emotion/cache@^11.1.3": + version "11.10.5" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12" + integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA== + dependencies: + "@emotion/memoize" "^0.8.0" + "@emotion/sheet" "^1.2.1" + "@emotion/utils" "^1.2.0" + "@emotion/weak-memoize" "^0.3.0" + stylis "4.1.3" + +"@emotion/css@11.1.3": + version "11.1.3" + resolved "https://registry.yarnpkg.com/@emotion/css/-/css-11.1.3.tgz#9ed44478b19e5d281ccbbd46d74d123d59be793f" + integrity sha512-RSQP59qtCNTf5NWD6xM08xsQdCZmVYnX/panPYvB6LQAPKQB6GL49Njf0EMbS3CyDtrlWsBcmqBtysFvfWT3rA== + dependencies: + "@emotion/babel-plugin" "^11.0.0" + "@emotion/cache" "^11.1.3" + "@emotion/serialize" "^1.0.0" + "@emotion/sheet" "^1.0.0" + "@emotion/utils" "^1.0.0" + +"@emotion/hash@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7" + integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ== + +"@emotion/memoize@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f" + integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== + +"@emotion/serialize@^1.0.0", "@emotion/serialize@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0" + integrity sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA== + dependencies: + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/unitless" "^0.8.0" + "@emotion/utils" "^1.2.0" + csstype "^3.0.2" + +"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c" + integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA== + +"@emotion/unitless@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db" + integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw== + +"@emotion/utils@^1.0.0", "@emotion/utils@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561" + integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw== + +"@emotion/weak-memoize@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" + integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== + "@esbuild/android-arm64@0.16.17": version "0.16.17" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23" @@ -199,7 +336,48 @@ "@swc/core-win32-ia32-msvc" "1.3.37" "@swc/core-win32-x64-msvc" "1.3.37" -"@types/prop-types@*": +"@tailwindcss/typography@^0.5.9": + version "0.5.9" + resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.9.tgz#027e4b0674929daaf7c921c900beee80dbad93e8" + integrity sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg== + dependencies: + lodash.castarray "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.merge "^4.6.2" + postcss-selector-parser "6.0.10" + +"@types/debug@^4.0.0": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" + integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== + dependencies: + "@types/ms" "*" + +"@types/hast@^2.0.0": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" + integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g== + dependencies: + "@types/unist" "*" + +"@types/mdast@^3.0.0": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" + integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== + dependencies: + "@types/unist" "*" + +"@types/ms@*": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/prop-types@*", "@types/prop-types@^15.0.0": version "15.7.5" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== @@ -225,6 +403,11 @@ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== +"@types/unist@*", "@types/unist@^2.0.0": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" + integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== + "@vitejs/plugin-react-swc@^3.0.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.2.0.tgz#7c4f6e116a296c27f680d05750f9dbf798cf7709" @@ -251,6 +434,13 @@ acorn@^7.0.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -276,6 +466,20 @@ autoprefixer@^10.4.13: picocolors "^1.0.0" postcss-value-parser "^4.2.0" +babel-plugin-macros@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" + integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== + dependencies: + "@babel/runtime" "^7.12.5" + cosmiconfig "^7.0.0" + resolve "^1.19.0" + +bail@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" + integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -298,6 +502,11 @@ browserslist@^4.21.4: node-releases "^2.0.8" update-browserslist-db "^1.0.10" +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camelcase-css@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" @@ -308,6 +517,20 @@ caniuse-lite@^1.0.30001426, caniuse-lite@^1.0.30001449: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001458.tgz#871e35866b4654a7d25eccca86864f411825540c" integrity sha512-lQ1VlUUq5q9ro9X+5gOEyH7i3vm+AYVT1WDCVB69XOZ17KZRhnZ9J0Sqz7wTHQaLBJccNCHq8/Ww5LlOIZbB0w== +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +character-entities@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" + integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== + chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -323,11 +546,59 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +classnames@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + color-name@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +comma-separated-tokens@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" + integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== + +convert-source-map@^1.5.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +core-js-pure@^3.25.1: + version "3.29.0" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.29.0.tgz#0e1ac889214398641ea4bb1c6cf25ff0959ec1d2" + integrity sha512-v94gUjN5UTe1n0yN/opTihJ8QBWD2O8i19RfTZR7foONPWArnjB96QA/wk5ozu1mm6ja3udQCzOzwQXTxi3xOQ== + +core-js@3.18.3: + version "3.18.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.3.tgz#86a0bba2d8ec3df860fefcc07a8d119779f01509" + integrity sha512-tReEhtMReZaPFVw7dajMx0vlsz3oOb8ajgPoHVYGxr8ErnZ6PcYEvvmjGmXlfpnxpkYSdOQttjB+MvVbCGfvLw== + +cosmiconfig@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -338,11 +609,30 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== +debug@^4.0.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decode-named-character-reference@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e" + integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg== + dependencies: + character-entities "^2.0.0" + defined@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== +dequal@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + detective@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034" @@ -357,16 +647,33 @@ didyoumean@^1.2.2: resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== +diff@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" + integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== + dlv@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== +dompurify@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.1.tgz#a0933f38931b3238934dd632043b727e53004289" + integrity sha512-60tsgvPKwItxZZdfLmamp0MTcecCta3avOhsLgPZ0qcWt96OasFfhkeIRbJ6br5i0fQawT1/RBGB5L58/Jpwuw== + electron-to-chromium@^1.4.284: version "1.4.317" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.317.tgz#9a3d38a1a37f26a417d3d95dafe198ff11ed072b" integrity sha512-JhCRm9v30FMNzQSsjl4kXaygU+qHBD0Yh7mKxyjmF0V8VwYVB6qpBRX28GyAucrM9wDCpSUctT6FpMUQxbyKuA== +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + esbuild@^0.16.14: version "0.16.17" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259" @@ -400,6 +707,21 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + fast-glob@^3.2.12: version "3.2.12" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" @@ -425,6 +747,11 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + fraction.js@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" @@ -454,6 +781,11 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -461,11 +793,34 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hast-util-whitespace@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557" + integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng== + highlight.js@^11.7.0: version "11.7.0" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.7.0.tgz#3ff0165bc843f8c9bce1fd89e2fda9143d24b11e" integrity sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ== +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +inline-style-parser@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" + integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -473,6 +828,11 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-buffer@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + is-core-module@^2.9.0: version "2.11.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" @@ -497,28 +857,311 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -"js-tokens@^3.0.0 || ^4.0.0": +is-plain-obj@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" + integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +kleur@^4.0.3: + version "4.1.5" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" + integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== + lilconfig@^2.0.5, lilconfig@^2.0.6: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== -loose-envify@^1.1.0: +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lodash.castarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + integrity sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" +math-random@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-2.0.1.tgz#5604b16c6a9a4aee63aff13937fb909b27e46b3a" + integrity sha512-oIEbWiVDxDpl5tIF4S6zYS9JExhh3bun3uLb3YAinHPTlRtW4g1S66LtJrJ4Npq8dgIa8CLK5iPVah5n4n0s2w== + +mdast-util-definitions@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7" + integrity sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + unist-util-visit "^4.0.0" + +mdast-util-from-markdown@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.0.tgz#0214124154f26154a2b3f9d401155509be45e894" + integrity sha512-HN3W1gRIuN/ZW295c7zi7g9lVBllMgZE40RxCX37wrTPWXCWtpvOZdfnuK+1WNpvZje6XuJeI3Wnb4TJEUem+g== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + decode-named-character-reference "^1.0.0" + mdast-util-to-string "^3.1.0" + micromark "^3.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-decode-string "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + unist-util-stringify-position "^3.0.0" + uvu "^0.5.0" + +mdast-util-to-hast@^12.1.0: + version "12.3.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz#045d2825fb04374e59970f5b3f279b5700f6fb49" + integrity sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-definitions "^5.0.0" + micromark-util-sanitize-uri "^1.1.0" + trim-lines "^3.0.0" + unist-util-generated "^2.0.0" + unist-util-position "^4.0.0" + unist-util-visit "^4.0.0" + +mdast-util-to-string@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.1.tgz#db859050d79d48cf9896d294de06f3ede7474d16" + integrity sha512-tGvhT94e+cVnQt8JWE9/b3cUQZWS732TJxXHktvP+BYo62PpYD53Ls/6cC60rW21dW+txxiM4zMdc6abASvZKA== + dependencies: + "@types/mdast" "^3.0.0" + merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +micromark-core-commonmark@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad" + integrity sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-factory-destination "^1.0.0" + micromark-factory-label "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-factory-title "^1.0.0" + micromark-factory-whitespace "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-classify-character "^1.0.0" + micromark-util-html-tag-name "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + +micromark-factory-destination@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e" + integrity sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-label@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz#6be2551fa8d13542fcbbac478258fb7a20047137" + integrity sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-factory-space@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz#cebff49968f2b9616c0fcb239e96685cb9497633" + integrity sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-title@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz#7e09287c3748ff1693930f176e1c4a328382494f" + integrity sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-factory-whitespace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz#e991e043ad376c1ba52f4e49858ce0794678621c" + integrity sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-character@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.1.0.tgz#d97c54d5742a0d9611a68ca0cd4124331f264d86" + integrity sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg== + dependencies: + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-chunked@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz#5b40d83f3d53b84c4c6bce30ed4257e9a4c79d06" + integrity sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-classify-character@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz#cbd7b447cb79ee6997dd274a46fc4eb806460a20" + integrity sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-combine-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5" + integrity sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-decode-numeric-character-reference@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz#dcc85f13b5bd93ff8d2868c3dba28039d490b946" + integrity sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-decode-string@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz#942252ab7a76dec2dbf089cc32505ee2bc3acf02" + integrity sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-encode@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz#2c1c22d3800870ad770ece5686ebca5920353383" + integrity sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA== + +micromark-util-html-tag-name@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz#eb227118befd51f48858e879b7a419fc0df20497" + integrity sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA== + +micromark-util-normalize-identifier@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz#4a3539cb8db954bbec5203952bfe8cedadae7828" + integrity sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-resolve-all@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz#a7c363f49a0162e931960c44f3127ab58f031d88" + integrity sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw== + dependencies: + micromark-util-types "^1.0.0" + +micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz#f12e07a85106b902645e0364feb07cf253a85aee" + integrity sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-subtokenize@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz#ff6f1af6ac836f8bfdbf9b02f40431760ad89105" + integrity sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-util-symbol@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz#b90344db62042ce454f351cf0bebcc0a6da4920e" + integrity sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ== + +micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.0.2.tgz#f4220fdb319205812f99c40f8c87a9be83eded20" + integrity sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w== + +micromark@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.1.0.tgz#eeba0fe0ac1c9aaef675157b52c166f125e89f62" + integrity sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA== + dependencies: + "@types/debug" "^4.0.0" + debug "^4.0.0" + decode-named-character-reference "^1.0.0" + micromark-core-commonmark "^1.0.1" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-combine-extensions "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -532,6 +1175,16 @@ minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + nanoid@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" @@ -552,16 +1205,43 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + object-hash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -608,6 +1288,14 @@ postcss-nested@6.0.0: dependencies: postcss-selector-parser "^6.0.10" +postcss-selector-parser@6.0.10: + version "6.0.10" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" + integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.11: version "6.0.11" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" @@ -630,6 +1318,29 @@ postcss@^8.0.9, postcss@^8.4.21: picocolors "^1.0.0" source-map-js "^1.0.2" +prop-types@15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +prop-types@^15.0.0: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +property-information@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.2.0.tgz#b74f522c31c097b5149e3c3cb8d7f3defd986a1d" + integrity sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -648,6 +1359,50 @@ react-dom@^18.2.0: loose-envify "^1.1.0" scheduler "^0.23.0" +react-is@^16.13.1, react-is@^16.8.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +react-markdown@^8.0.5: + version "8.0.5" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.5.tgz#c9a70a33ca9aeeafb769c6582e7e38843b9d70ad" + integrity sha512-jGJolWWmOWAvzf+xMdB9zwStViODyyFQhNB/bwCerbBKmrTmgmA599CGiOlP58OId1IMoIRsA8UdI1Lod4zb5A== + dependencies: + "@types/hast" "^2.0.0" + "@types/prop-types" "^15.0.0" + "@types/unist" "^2.0.0" + comma-separated-tokens "^2.0.0" + hast-util-whitespace "^2.0.0" + prop-types "^15.0.0" + property-information "^6.0.0" + react-is "^18.0.0" + remark-parse "^10.0.0" + remark-rehype "^10.0.0" + space-separated-tokens "^2.0.0" + style-to-object "^0.4.0" + unified "^10.0.0" + unist-util-visit "^4.0.0" + vfile "^5.0.0" + +react-scroll-to-bottom@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/react-scroll-to-bottom/-/react-scroll-to-bottom-4.2.0.tgz#208183547f85e2b640f467c185fdbc93de2fcc64" + integrity sha512-1WweuumQc5JLzeAR81ykRdK/cEv9NlCPEm4vSwOGN1qS2qlpGVTyMgdI8Y7ZmaqRmzYBGV5/xPuJQtekYzQFGg== + dependencies: + "@babel/runtime-corejs3" "^7.15.4" + "@emotion/css" "11.1.3" + classnames "2.3.1" + core-js "3.18.3" + math-random "2.0.1" + prop-types "15.7.2" + simple-update-in "2.2.0" + react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" @@ -669,7 +1424,36 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -resolve@^1.1.7, resolve@^1.22.1: +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +remark-parse@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.1.tgz#6f60ae53edbf0cf38ea223fe643db64d112e0775" + integrity sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^1.0.0" + unified "^10.0.0" + +remark-rehype@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" + integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-to-hast "^12.1.0" + unified "^10.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.1.7, resolve@^1.19.0, resolve@^1.22.1: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -697,6 +1481,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +sade@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" + integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== + dependencies: + mri "^1.1.0" + scheduler@^0.23.0: version "0.23.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" @@ -704,11 +1495,45 @@ scheduler@^0.23.0: dependencies: loose-envify "^1.1.0" +simple-update-in@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/simple-update-in/-/simple-update-in-2.2.0.tgz#86607662635ea12e59b5341044244902aa7db1c8" + integrity sha512-FrW41lLiOs82jKxwq39UrE1HDAHOvirKWk4Nv8tqnFFFknVbTxcHZzDS4vt02qqdU/5+KNsQHWzhKHznDBmrww== + source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +space-separated-tokens@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" + integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== + +style-to-object@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.1.tgz#53cf856f7cf7f172d72939d9679556469ba5de37" + integrity sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw== + dependencies: + inline-style-parser "0.1.1" + +stylis@4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" + integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -743,6 +1568,11 @@ tailwindcss@^3.2.7: quick-lru "^5.1.1" resolve "^1.22.1" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -750,11 +1580,77 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +trim-lines@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" + integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== + +trough@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" + integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== + typescript@^4.9.3: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +unified@^10.0.0: + version "10.1.2" + resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df" + integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q== + dependencies: + "@types/unist" "^2.0.0" + bail "^2.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^4.0.0" + trough "^2.0.0" + vfile "^5.0.0" + +unist-util-generated@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.1.tgz#e37c50af35d3ed185ac6ceacb6ca0afb28a85cae" + integrity sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A== + +unist-util-is@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.2.1.tgz#b74960e145c18dcb6226bc57933597f5486deae9" + integrity sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw== + dependencies: + "@types/unist" "^2.0.0" + +unist-util-position@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.4.tgz#93f6d8c7d6b373d9b825844645877c127455f037" + integrity sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg== + dependencies: + "@types/unist" "^2.0.0" + +unist-util-stringify-position@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz#03ad3348210c2d930772d64b489580c13a7db39d" + integrity sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg== + dependencies: + "@types/unist" "^2.0.0" + +unist-util-visit-parents@^5.1.1: + version "5.1.3" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz#b4520811b0ca34285633785045df7a8d6776cfeb" + integrity sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + +unist-util-visit@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.2.tgz#125a42d1eb876283715a3cb5cceaa531828c72e2" + integrity sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^5.1.1" + update-browserslist-db@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" @@ -763,11 +1659,44 @@ update-browserslist-db@^1.0.10: escalade "^3.1.1" picocolors "^1.0.0" +use-sync-external-store@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +uvu@^0.5.0: + version "0.5.6" + resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df" + integrity sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA== + dependencies: + dequal "^2.0.0" + diff "^5.0.0" + kleur "^4.0.3" + sade "^1.7.3" + +vfile-message@^3.0.0: + version "3.1.4" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.4.tgz#15a50816ae7d7c2d1fa87090a7f9f96612b59dea" + integrity sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^3.0.0" + +vfile@^5.0.0: + version "5.3.7" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.3.7.tgz#de0677e6683e3380fafc46544cfe603118826ab7" + integrity sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g== + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + unist-util-stringify-position "^3.0.0" + vfile-message "^3.0.0" + vite@^4.1.0: version "4.1.4" resolved "https://registry.yarnpkg.com/vite/-/vite-4.1.4.tgz#170d93bcff97e0ebc09764c053eebe130bfe6ca0" @@ -785,7 +1714,14 @@ xtend@^4.0.2: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -yaml@^1.10.2: +yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +zustand@^4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.3.5.tgz#011d2997534f8a187ea7b1d75db56df31f58453d" + integrity sha512-2iPUzfwx+g3f0PagOMz2vDO9mZzEp2puFpNe7vrAymVPOEIEUjCPkC4/zy84eAscxIWmTU4j9g6upXYkJdzEFQ== + dependencies: + use-sync-external-store "1.2.0"