feat: add settings ui

This commit is contained in:
Yidadaa 2023-03-12 01:14:07 +08:00
parent 1161adaa9f
commit a9940cb05e
9 changed files with 326 additions and 218 deletions

View File

@ -14,7 +14,7 @@
}
.sidebar {
max-width: 300px;
width: 300px;
padding: 20px;
background-color: var(--second);
display: flex;
@ -141,14 +141,19 @@
margin-left: 15px;
}
.window-content {
width: 100%;
height: 100%;
}
.chat {
display: flex;
flex-direction: column;
width: 100%;
position: relative;
height: 100%;
}
.chat-header {
.window-header {
padding: 14px 20px;
border-bottom: rgba(0, 0, 0, 0.1) 1px solid;
@ -157,7 +162,7 @@
align-items: center;
}
.chat-header-title {
.window-header-title {
font-size: 20px;
font-weight: bolder;
overflow: hidden;
@ -167,7 +172,7 @@
-webkit-box-orient: vertical;
}
.chat-header-sub-title {
.window-header-sub-title {
font-size: 14px;
margin-top: 5px;
}
@ -303,3 +308,16 @@
right: 30px;
bottom: 10px;
}
.settings {
padding: 20px;
}
.settings-title {
font-size: 14px;
font-weight: bolder;
}
.avatar {
cursor: pointer;
}

View File

@ -6,6 +6,8 @@ import "katex/dist/katex.min.css";
import RemarkMath from "remark-math";
import RehypeKatex from "rehype-katex";
import EmojiPicker, { Emoji, EmojiClickData } from "emoji-picker-react";
import { IconButton } from "./button";
import styles from "./home.module.css";
@ -20,7 +22,8 @@ import AddIcon from "../icons/add.svg";
import DeleteIcon from "../icons/delete.svg";
import LoadingIcon from "../icons/three-dots.svg";
import { Message, useChatStore } from "../store";
import { Message, SubmitKey, useChatStore } from "../store";
import { Card, List, ListItem, Popover } from "./ui-lib";
export function Markdown(props: { content: string }) {
return (
@ -31,11 +34,17 @@ export function Markdown(props: { content: string }) {
}
export function Avatar(props: { role: Message["role"] }) {
const config = useChatStore((state) => state.config);
if (props.role === "assistant") {
return <BotIcon className={styles["user-avtar"]} />;
}
return <div className={styles["user-avtar"]}>🤣</div>;
return (
<div className={styles["user-avtar"]}>
<Emoji unified={config.avatar} size={18} />
</div>
);
}
export function ChatItem(props: {
@ -148,11 +157,11 @@ export function Chat() {
});
return (
<div className={styles.chat} key={session.topic}>
<div className={styles["chat-header"]}>
<div className={styles.chat} key={session.id}>
<div className={styles["window-header"]}>
<div>
<div className={styles["chat-header-title"]}>{session.topic}</div>
<div className={styles["chat-header-sub-title"]}>
<div className={styles["window-header-title"]}>{session.topic}</div>
<div className={styles["window-header-sub-title"]}>
ChatGPT {session.messages.length}
</div>
</div>
@ -181,7 +190,7 @@ export function Chat() {
<div className={styles["chat-message-avatar"]}>
<Avatar role={message.role} />
</div>
{message.preview && (
{(message.preview || message.streaming) && (
<div className={styles["chat-message-status"]}></div>
)}
<div className={styles["chat-message-item"]}>
@ -235,6 +244,9 @@ export function Chat() {
export function Home() {
const [createNewSession] = useChatStore((state) => [state.newSession]);
// settings
const [openSettings, setOpenSettings] = useState(false);
return (
<div className={styles.container}>
<div className={styles.sidebar}>
@ -255,7 +267,10 @@ export function Home() {
<div className={styles["sidebar-tail"]}>
<div className={styles["sidebar-actions"]}>
<div className={styles["sidebar-action"]}>
<IconButton icon={<SettingsIcon />} />
<IconButton
icon={<SettingsIcon />}
onClick={() => setOpenSettings(!openSettings)}
/>
</div>
<div className={styles["sidebar-action"]}>
<a href="https://github.com/Yidadaa" target="_blank">
@ -273,7 +288,94 @@ export function Home() {
</div>
</div>
<Chat key="chat" />
<div className={styles["window-content"]}>
{openSettings ? <Settings /> : <Chat key="chat" />}
</div>
</div>
);
}
export function EmojiPickerModal(props: {
show: boolean;
onClose: (_: boolean) => void;
}) {
return <div className=""></div>;
}
export function Settings() {
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
const [config, updateConfig] = useChatStore((state) => [
state.config,
state.updateConfig,
]);
return (
<>
<div className={styles["window-header"]}>
<div>
<div className={styles["window-header-title"]}></div>
<div className={styles["window-header-sub-title"]}></div>
</div>
</div>
<div className={styles["settings"]}>
<List>
<ListItem>
<div className={styles["settings-title"]}></div>
<Popover
onClose={() => setShowEmojiPicker(false)}
content={
<EmojiPicker
lazyLoadEmojis
onEmojiClick={(e) => {
updateConfig((config) => (config.avatar = e.unified));
setShowEmojiPicker(false);
}}
/>
}
open={showEmojiPicker}
>
<div
className={styles.avatar}
onClick={() => setShowEmojiPicker(true)}
>
<Avatar role="user" />
</div>
</Popover>
</ListItem>
<ListItem>
<div className={styles["settings-title"]}></div>
<div className="">
<select
value={config.submitKey}
onChange={(e) => {
updateConfig(
(config) =>
(config.submitKey = e.target.value as any as SubmitKey)
);
}}
>
{Object.entries(SubmitKey).map(([k, v]) => (
<option value={k} key={v}>
{v}
</option>
))}
</select>
</div>
</ListItem>
</List>
<List>
<ListItem>
<div className={styles["settings-title"]}></div>
<div className="">{config.historyMessageCount}</div>
</ListItem>
<ListItem>
<div className={styles["settings-title"]}></div>
<div className="">{config.sendBotMessages ? "是" : "否"}</div>
</ListItem>
</List>
</div>
</>
);
}

View File

@ -0,0 +1,56 @@
.card {
background-color: var(--white);
border-radius: 10px;
box-shadow: var(--card-shadow);
padding: 10px;
}
.popover {
position: relative;
}
.popover-content {
position: absolute;
animation: slide-in 0.3s ease;
right: 0;
top: calc(100% + 10px);
}
.popover-mask {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
@keyframes slide-in {
from {
transform: translateY(10px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.list-item {
display: flex;
justify-content: space-between;
align-items: center;
min-height: 40px;
border-bottom: var(--border-in-light);
padding: 10px 20px;
}
.list {
border: var(--border-in-light);
border-radius: 10px;
box-shadow: var(--card-shadow);
margin-bottom: 20px;
}
.list .list-item:last-child {
border: 0;
}

38
app/components/ui-lib.tsx Normal file
View File

@ -0,0 +1,38 @@
import styles from "./ui-lib.module.css";
export function Popover(props: {
children: JSX.Element;
content: JSX.Element;
open?: boolean;
onClose?: () => void;
}) {
return (
<div className={styles.popover}>
{props.children}
{props.open && (
<div className={styles["popover-content"]}>
<div className={styles["popover-mask"]} onClick={props.onClose}></div>
{props.content}
</div>
)}
</div>
);
}
export function Card(props: { children: JSX.Element[]; className?: string }) {
return (
<div className={styles.card + " " + props.className}>{props.children}</div>
);
}
export function ListItem(props: { children: JSX.Element[] }) {
if (props.children.length > 2) {
throw Error("Only Support Two Children");
}
return <div className={styles["list-item"]}>{props.children}</div>;
}
export function List(props: { children: JSX.Element[] }) {
return <div className={styles.list}>{props.children}</div>;
}

View File

@ -1,6 +1,7 @@
:root {
/* color */
--white: white;
--black: --black;
--gray: rgb(250, 250, 250);
--primary: rgb(29, 147, 171);
--second: rgb(231, 248, 255);
@ -40,3 +41,9 @@ body {
border: 6px solid transparent;
background-clip: content-box;
}
select {
border: var(--border-in-light);
padding: 10px;
border-radius: 10px;
}

View File

@ -1,21 +1,31 @@
import type { ChatRequest, ChatReponse } from "./api/chat/typing";
import { Message } from "./store";
const makeRequestParam = (messages: Message[], stream = false): ChatRequest => {
const makeRequestParam = (
messages: Message[],
options?: {
filterBot?: boolean;
stream?: boolean;
}
): ChatRequest => {
let sendMessages = messages.map((v) => ({
role: v.role,
content: v.content,
}));
if (options?.filterBot) {
sendMessages = sendMessages.filter((m) => m.role !== "assistant");
}
return {
model: "gpt-3.5-turbo",
messages: messages
.map((v) => ({
role: v.role,
content: v.content,
}))
.filter((m) => m.role !== "assistant"),
stream,
messages: sendMessages,
stream: options?.stream,
};
};
export async function requestChat(messages: Message[]) {
const req: ChatRequest = makeRequestParam(messages);
const req: ChatRequest = makeRequestParam(messages, { filterBot: true });
const res = await fetch("/api/chat", {
method: "POST",
@ -31,10 +41,15 @@ export async function requestChat(messages: Message[]) {
export async function requestChatStream(
messages: Message[],
options?: {
filterBot?: boolean;
onMessage: (message: string, done: boolean) => void;
onError: (error: Error) => void;
}
) {
const req = makeRequestParam(messages, true);
const req = makeRequestParam(messages, {
stream: true,
filterBot: options?.filterBot,
});
const res = await fetch("/api/chat-stream", {
method: "POST",
@ -64,6 +79,8 @@ export async function requestChatStream(
}
options?.onMessage(responseText, true);
} else {
options?.onError(new Error("NetWork Error"));
}
}

View File

@ -10,8 +10,19 @@ export type Message = ChatCompletionResponseMessage & {
streaming?: boolean;
};
export enum SubmitKey {
Enter = "Enter",
CtrlEnter = "Ctrl + Enter",
ShiftEnter = "Shift + Enter",
AltEnter = "Alt + Enter",
}
interface ChatConfig {
maxToken: number;
maxToken?: number;
historyMessageCount: number; // -1 means all
sendBotMessages: boolean; // send bot's message or not
submitKey: SubmitKey;
avatar: string;
}
interface ChatStat {
@ -21,6 +32,7 @@ interface ChatStat {
}
interface ChatSession {
id: number;
topic: string;
memoryPrompt: string;
messages: Message[];
@ -35,6 +47,7 @@ function createEmptySession(): ChatSession {
const createDate = new Date().toLocaleString();
return {
id: Date.now(),
topic: DEFAULT_TOPIC,
memoryPrompt: "",
messages: [
@ -54,6 +67,7 @@ function createEmptySession(): ChatSession {
}
interface ChatStore {
config: ChatConfig;
sessions: ChatSession[];
currentSessionIndex: number;
removeSession: (index: number) => void;
@ -71,6 +85,9 @@ interface ChatStore {
messageIndex: number,
updater: (message?: Message) => void
) => void;
getConfig: () => ChatConfig;
updateConfig: (updater: (config: ChatConfig) => void) => void;
}
export const useChatStore = create<ChatStore>()(
@ -78,6 +95,22 @@ export const useChatStore = create<ChatStore>()(
(set, get) => ({
sessions: [createEmptySession()],
currentSessionIndex: 0,
config: {
historyMessageCount: 5,
sendBotMessages: false as boolean,
submitKey: SubmitKey.CtrlEnter,
avatar: "1fae0",
},
getConfig() {
return get().config;
},
updateConfig(updater) {
const config = get().config;
updater(config);
set(() => ({ config }));
},
selectSession(index: number) {
set({
@ -126,7 +159,9 @@ export const useChatStore = create<ChatStore>()(
set(() => ({ currentSessionIndex: index }));
}
return sessions[index];
const session = sessions[index];
return session;
},
onNewMessage(message) {
@ -144,6 +179,7 @@ export const useChatStore = create<ChatStore>()(
date: new Date().toLocaleString(),
};
// get last five messges
const messages = get().currentSession().messages.concat(message);
get().onNewMessage(message);
@ -158,17 +194,25 @@ export const useChatStore = create<ChatStore>()(
session.messages.push(botMessage);
});
requestChatStream(messages, {
const fiveMessages = messages.slice(-5);
requestChatStream(fiveMessages, {
onMessage(content, done) {
if (done) {
get().updateStat(message);
botMessage.streaming = false;
get().updateStat(botMessage);
get().summarizeSession();
} else {
botMessage.content = content;
botMessage.streaming = false;
set(() => ({}));
}
},
onError(error) {
botMessage.content = "出错了,稍后重试吧";
botMessage.streaming = false;
set(() => ({}));
},
filterBot: !get().config.sendBotMessages,
});
},

View File

@ -14,6 +14,7 @@
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/react-katex": "^3.0.0",
"emoji-picker-react": "^4.4.7",
"eslint": "8.35.0",
"eslint-config-next": "13.2.3",
"eventsource-parser": "^0.1.0",

203
yarn.lock
View File

@ -1313,11 +1313,6 @@
dependencies:
"@types/ms" "*"
"@types/global-tunnel-ng@^2.1.1":
version "2.1.1"
resolved "https://registry.npmmirror.com/@types/global-tunnel-ng/-/global-tunnel-ng-2.1.1.tgz#4f01cf93f7e51a6f97bdea5a11f49c742993f865"
integrity sha512-TikApqV8CkUsI1GGUgVydkJFrq9sYCBWv4fc/r3zvl6Oqe2YU1ASeWBrG5bw1D2XvS07YS3s05hCor/lEtIoYw==
"@types/hast@^2.0.0":
version "2.3.4"
resolved "https://registry.npmmirror.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc"
@ -1610,11 +1605,6 @@ boolbase@^1.0.0:
resolved "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
boolean@^3.0.1:
version "3.2.0"
resolved "https://registry.npmmirror.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b"
integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -1695,6 +1685,11 @@ client-only@0.0.1:
resolved "https://registry.npmmirror.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
clsx@^1.2.1:
version "1.2.1"
resolved "https://registry.npmmirror.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@ -1746,14 +1741,6 @@ concat-map@0.0.1:
resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
config-chain@^1.1.11:
version "1.1.13"
resolved "https://registry.npmmirror.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==
dependencies:
ini "^1.3.4"
proto-list "~1.2.1"
convert-source-map@^1.7.0:
version "1.9.0"
resolved "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
@ -1766,11 +1753,6 @@ core-js-compat@^3.25.1:
dependencies:
browserslist "^4.21.5"
core-js@^3.6.5:
version "3.29.0"
resolved "https://registry.npmmirror.com/core-js/-/core-js-3.29.0.tgz#0273e142b67761058bcde5615c503c7406b572d6"
integrity sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg==
cosmiconfig@^7.0.1:
version "7.1.0"
resolved "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
@ -1909,11 +1891,6 @@ dequal@^2.0.0:
resolved "https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be"
integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==
detect-node@^2.0.4:
version "2.1.0"
resolved "https://registry.npmmirror.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
diff@^5.0.0:
version "5.1.0"
resolved "https://registry.npmmirror.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40"
@ -1975,16 +1952,18 @@ electron-to-chromium@^1.4.284:
resolved "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.325.tgz#7b97238a61192d85d055d97f3149832b3617d37b"
integrity sha512-K1C03NT4I7BuzsRdCU5RWkgZxtswnKDYM6/eMhkEXqKu4e5T+ck610x3FPzu1y7HVFSiQKZqP16gnJzPpji1TQ==
emoji-picker-react@^4.4.7:
version "4.4.7"
resolved "https://registry.npmmirror.com/emoji-picker-react/-/emoji-picker-react-4.4.7.tgz#faff798cf7acad41c5eb6b103c93480e777f2222"
integrity sha512-HcB1Fr57W6M+gLLm/W4YhbAnUQqYBUAhZBOHmPlSQODLtsDI8vecyqNIF9RrStZHfZwzUSLlpZMfY07AA6gxmA==
dependencies:
clsx "^1.2.1"
emoji-regex@^9.2.2:
version "9.2.2"
resolved "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
encodeurl@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
enhanced-resolve@^5.10.0:
version "5.12.0"
resolved "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634"
@ -2089,11 +2068,6 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
es6-error@^4.1.1:
version "4.1.1"
resolved "https://registry.npmmirror.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@ -2515,29 +2489,6 @@ glob@^7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
global-agent@^2.1.12:
version "2.2.0"
resolved "https://registry.npmmirror.com/global-agent/-/global-agent-2.2.0.tgz#566331b0646e6bf79429a16877685c4a1fbf76dc"
integrity sha512-+20KpaW6DDLqhG7JDiJpD1JvNvb8ts+TNl7BPOYcURqCrXqnN1Vf+XVOrkKJAFPqfX+oEhsdzOj1hLWkBTdNJg==
dependencies:
boolean "^3.0.1"
core-js "^3.6.5"
es6-error "^4.1.1"
matcher "^3.0.0"
roarr "^2.15.3"
semver "^7.3.2"
serialize-error "^7.0.1"
global-tunnel-ng@^2.7.1:
version "2.7.1"
resolved "https://registry.npmmirror.com/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz#d03b5102dfde3a69914f5ee7d86761ca35d57d8f"
integrity sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==
dependencies:
encodeurl "^1.0.2"
lodash "^4.17.10"
npm-conf "^1.1.3"
tunnel "^0.0.6"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
@ -2550,7 +2501,7 @@ globals@^13.19.0:
dependencies:
type-fest "^0.20.2"
globalthis@^1.0.1, globalthis@^1.0.3:
globalthis@^1.0.3:
version "1.0.3"
resolved "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf"
integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==
@ -2738,16 +2689,6 @@ inherits@2:
resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
inherits@2.0.3:
version "2.0.3"
resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
ini@^1.3.4:
version "1.3.8"
resolved "https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
inline-style-parser@0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
@ -2996,11 +2937,6 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
json-stringify-safe@^5.0.1:
version "5.0.1"
resolved "https://registry.npmmirror.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
json5@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
@ -3035,13 +2971,6 @@ katex@^0.15.0:
dependencies:
commander "^8.0.0"
katex@^0.16.0:
version "0.16.4"
resolved "https://registry.npmmirror.com/katex/-/katex-0.16.4.tgz#87021bc3bbd80586ef715aeb476794cba6a49ad4"
integrity sha512-WudRKUj8yyBeVDI4aYMNxhx5Vhh2PjpzQw1GRu/LVGqL4m1AxwD1GcUp0IMbdJaf5zsjtj8ghP0DOQRYhroNkw==
dependencies:
commander "^8.0.0"
kleur@^4.0.3:
version "4.1.5"
resolved "https://registry.npmmirror.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
@ -3089,11 +3018,6 @@ lodash.merge@^4.6.2:
resolved "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash@^4.17.10:
version "4.17.21"
resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
longest-streak@^3.0.0:
version "3.1.0"
resolved "https://registry.npmmirror.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4"
@ -3120,13 +3044,6 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
matcher@^3.0.0:
version "3.0.0"
resolved "https://registry.npmmirror.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca"
integrity sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==
dependencies:
escape-string-regexp "^4.0.0"
mdast-util-definitions@^5.0.0:
version "5.1.2"
resolved "https://registry.npmmirror.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7"
@ -3506,27 +3423,11 @@ next@^13.2.3:
"@next/swc-win32-ia32-msvc" "13.2.4"
"@next/swc-win32-x64-msvc" "13.2.4"
node-global-proxy@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/node-global-proxy/-/node-global-proxy-1.0.1.tgz#6d1f66ed60427cb3f70066f7da0b70c78a1547a4"
integrity sha512-pKGD42p81TFbrUudDBtApwri2Ho1xjm3ozmXhHLIRpwgXk18KvPMv0ubDZLD8gNI6q/Jzc2zK6jNbga8j+FRSw==
dependencies:
global-agent "^2.1.12"
global-tunnel-ng "^2.7.1"
node-releases@^2.0.8:
version "2.0.10"
resolved "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f"
integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
npm-conf@^1.1.3:
version "1.1.3"
resolved "https://registry.npmmirror.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9"
integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==
dependencies:
config-chain "^1.1.11"
pify "^3.0.0"
nth-check@^2.0.1:
version "2.1.1"
resolved "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
@ -3699,14 +3600,6 @@ path-type@^4.0.0:
resolved "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
path@^0.12.7:
version "0.12.7"
resolved "https://registry.npmmirror.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==
dependencies:
process "^0.11.1"
util "^0.10.3"
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
@ -3717,11 +3610,6 @@ picomatch@^2.3.1:
resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.npmmirror.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==
postcss@8.4.14:
version "8.4.14"
resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
@ -3736,11 +3624,6 @@ prelude-ls@^1.2.1:
resolved "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
process@^0.11.1:
version "0.11.10"
resolved "https://registry.npmmirror.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
prop-types@^15.0.0, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
@ -3755,11 +3638,6 @@ property-information@^6.0.0:
resolved "https://registry.npmmirror.com/property-information/-/property-information-6.2.0.tgz#b74f522c31c097b5149e3c3cb8d7f3defd986a1d"
integrity sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==
proto-list@~1.2.1:
version "1.2.4"
resolved "https://registry.npmmirror.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==
punycode@^2.1.0:
version "2.3.0"
resolved "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
@ -3788,13 +3666,6 @@ react-is@^18.0.0:
resolved "https://registry.npmmirror.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
react-katex@^3.0.1:
version "3.0.1"
resolved "https://registry.npmmirror.com/react-katex/-/react-katex-3.0.1.tgz#262b44f49c5fa727f1d13cbab595f791318e5083"
integrity sha512-wIUW1fU5dHlkKvq4POfDkHruQsYp3fM8xNb/jnc8dnQ+nNCnaj0sx5pw7E6UyuEdLRyFKK0HZjmXBo+AtXXy0A==
dependencies:
katex "^0.16.0"
react-markdown@^8.0.5:
version "8.0.5"
resolved "https://registry.npmmirror.com/react-markdown/-/react-markdown-8.0.5.tgz#c9a70a33ca9aeeafb769c6582e7e38843b9d70ad"
@ -3968,18 +3839,6 @@ rimraf@^3.0.2:
dependencies:
glob "^7.1.3"
roarr@^2.15.3:
version "2.15.4"
resolved "https://registry.npmmirror.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd"
integrity sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==
dependencies:
boolean "^3.0.1"
detect-node "^2.0.4"
globalthis "^1.0.1"
json-stringify-safe "^5.0.1"
semver-compare "^1.0.0"
sprintf-js "^1.1.2"
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
@ -4010,30 +3869,18 @@ scheduler@^0.23.0:
dependencies:
loose-envify "^1.1.0"
semver-compare@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==
semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.npmmirror.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.2, semver@^7.3.7:
semver@^7.3.7:
version "7.3.8"
resolved "https://registry.npmmirror.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
dependencies:
lru-cache "^6.0.0"
serialize-error@^7.0.1:
version "7.0.1"
resolved "https://registry.npmmirror.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18"
integrity sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==
dependencies:
type-fest "^0.13.1"
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@ -4080,11 +3927,6 @@ space-separated-tokens@^2.0.0:
resolved "https://registry.npmmirror.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f"
integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==
sprintf-js@^1.1.2:
version "1.1.2"
resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"
integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==
stable@^0.1.8:
version "0.1.8"
resolved "https://registry.npmmirror.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
@ -4272,11 +4114,6 @@ tsutils@^3.21.0:
dependencies:
tslib "^1.8.1"
tunnel@^0.0.6:
version "0.0.6"
resolved "https://registry.npmmirror.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@ -4284,11 +4121,6 @@ type-check@^0.4.0, type-check@~0.4.0:
dependencies:
prelude-ls "^1.2.1"
type-fest@^0.13.1:
version "0.13.1"
resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934"
integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==
type-fest@^0.20.2:
version "0.20.2"
resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
@ -4433,13 +4265,6 @@ use-sync-external-store@1.2.0:
resolved "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
util@^0.10.3:
version "0.10.4"
resolved "https://registry.npmmirror.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
dependencies:
inherits "2.0.3"
uvu@^0.5.0:
version "0.5.6"
resolved "https://registry.npmmirror.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df"