diff --git a/app/command.ts b/app/command.ts index ba3bb653..9330d4ff 100644 --- a/app/command.ts +++ b/app/command.ts @@ -1,3 +1,4 @@ +import { useEffect } from "react"; import { useSearchParams } from "react-router-dom"; import Locale from "./locales"; @@ -11,21 +12,22 @@ interface Commands { export function useCommand(commands: Commands = {}) { const [searchParams, setSearchParams] = useSearchParams(); - if (commands === undefined) return; + useEffect(() => { + let shouldUpdate = false; + searchParams.forEach((param, name) => { + const commandName = name as keyof Commands; + if (typeof commands[commandName] === "function") { + commands[commandName]!(param); + searchParams.delete(name); + shouldUpdate = true; + } + }); - let shouldUpdate = false; - searchParams.forEach((param, name) => { - const commandName = name as keyof Commands; - if (typeof commands[commandName] === "function") { - commands[commandName]!(param); - searchParams.delete(name); - shouldUpdate = true; + if (shouldUpdate) { + setSearchParams(searchParams); } - }); - - if (shouldUpdate) { - setSearchParams(searchParams); - } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [searchParams, commands]); } interface ChatCommands { diff --git a/app/components/mask.tsx b/app/components/mask.tsx index ea7cf3a5..be68c00e 100644 --- a/app/components/mask.tsx +++ b/app/components/mask.tsx @@ -30,7 +30,7 @@ import { useNavigate } from "react-router-dom"; import chatStyle from "./chat.module.scss"; import { useEffect, useState } from "react"; -import { downloadAs, readFromFile } from "../utils"; +import { copyToClipboard, downloadAs, readFromFile } from "../utils"; import { Updater } from "../typing"; import { ModelConfigList } from "./model-config"; import { FileName, Path } from "../constant"; @@ -65,6 +65,11 @@ export function MaskConfig(props: { }); }; + const copyMaskLink = () => { + const maskLink = `${location.protocol}//${location.host}/#${Path.NewChat}?mask=${props.mask.id}`; + copyToClipboard(maskLink); + }; + const globalConfig = useAppConfig(); return ( @@ -125,6 +130,20 @@ export function MaskConfig(props: { }} > + + {!props.shouldSyncFromGlobal ? ( + + } + text={Locale.Mask.Config.Share.Action} + onClick={copyMaskLink} + /> + + ) : null} + {props.shouldSyncFromGlobal ? ( { - chatStore.newSession(mask); - setTimeout(() => navigate(Path.Chat), 1); + setTimeout(() => { + chatStore.newSession(mask); + navigate(Path.Chat); + }, 10); }; useCommand({ mask: (id) => { try { - const mask = maskStore.get(parseInt(id)); + const intId = parseInt(id); + const mask = maskStore.get(intId) ?? BUILTIN_MASK_STORE.get(intId); startChat(mask ?? undefined); } catch { console.error("[New Chat] failed to create chat from mask id=", id); diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 6c8b6c0a..cb0cbbb1 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -297,6 +297,11 @@ const cn = { Title: "隐藏预设对话", SubTitle: "隐藏后预设对话不会出现在聊天界面", }, + Share: { + Title: "分享此面具", + SubTitle: "生成此面具的直达链接", + Action: "复制链接", + }, }, }, NewChat: { diff --git a/app/locales/en.ts b/app/locales/en.ts index ab489c25..11b8b157 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -301,6 +301,11 @@ const en: LocaleType = { Title: "Hide Context Prompts", SubTitle: "Do not show in-context prompts in chat", }, + Share: { + Title: "Share This Mask", + SubTitle: "Generate a link to this mask", + Action: "Copy Link", + }, }, }, NewChat: {