feat:全屏功能
This commit is contained in:
parent
a8d1c8367f
commit
32f581cf50
|
|
@ -24,6 +24,7 @@ import { MessageList } from "@/components/workspace/messages";
|
||||||
import { ThreadContext } from "@/components/workspace/messages/context";
|
import { ThreadContext } from "@/components/workspace/messages/context";
|
||||||
import { ThreadTitle } from "@/components/workspace/thread-title";
|
import { ThreadTitle } from "@/components/workspace/thread-title";
|
||||||
import { Welcome } from "@/components/workspace/welcome";
|
import { Welcome } from "@/components/workspace/welcome";
|
||||||
|
import { useArtifacts } from "@/components/workspace/artifacts";
|
||||||
import { useI18n } from "@/core/i18n/hooks";
|
import { useI18n } from "@/core/i18n/hooks";
|
||||||
import { useNotification } from "@/core/notification/hooks";
|
import { useNotification } from "@/core/notification/hooks";
|
||||||
import { useLocalSettings } from "@/core/settings";
|
import { useLocalSettings } from "@/core/settings";
|
||||||
|
|
@ -36,6 +37,7 @@ export default function ChatPage() {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const [settings, setSettings] = useLocalSettings();
|
const [settings, setSettings] = useLocalSettings();
|
||||||
const [showExitDialog, setShowExitDialog] = useState(false);
|
const [showExitDialog, setShowExitDialog] = useState(false);
|
||||||
|
const { fullscreen } = useArtifacts();
|
||||||
|
|
||||||
const { threadId, isNewThread, setIsNewThread, isMock } = useThreadChat();
|
const { threadId, isNewThread, setIsNewThread, isMock } = useThreadChat();
|
||||||
useSpecificChatMode();
|
useSpecificChatMode();
|
||||||
|
|
@ -85,7 +87,7 @@ export default function ChatPage() {
|
||||||
<div className="bg-background relative flex size-full min-h-0 justify-between">
|
<div className="bg-background relative flex size-full min-h-0 justify-between">
|
||||||
<header
|
<header
|
||||||
className={cn(
|
className={cn(
|
||||||
"absolute top-0 right-0 left-0 z-30 grid h-[58px] shrink-0 grid-cols-3 items-center rounded-t-[20px] px-[20px] py-[15px]",
|
"absolute top-0 right-0 left-0 z-30 mx-[20px] grid h-[58px] shrink-0 grid-cols-3 items-center rounded-t-[20px] border-b py-[15px]",
|
||||||
isNewThread
|
isNewThread
|
||||||
? "bg-background/0 backdrop-blur-none"
|
? "bg-background/0 backdrop-blur-none"
|
||||||
: "bg-background/80 shadow-xs backdrop-blur",
|
: "bg-background/80 shadow-xs backdrop-blur",
|
||||||
|
|
@ -130,7 +132,7 @@ export default function ChatPage() {
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="h-full px-[10px] py-[5px] text-sm font-medium"
|
className="h-full px-[10px] py-[5px] text-sm font-medium"
|
||||||
>
|
>
|
||||||
<ListTodoIcon className="size-4" /> Todo
|
<ListTodoIcon className="size-4" /> To-dos
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
@ -147,14 +149,19 @@ export default function ChatPage() {
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<div className="pointer-events-none fixed right-0 bottom-3 left-0 z-30 flex justify-center px-4">
|
<div
|
||||||
|
className={cn(
|
||||||
|
"pointer-events-none fixed right-0 bottom-3 left-0 z-30 flex justify-center px-4",
|
||||||
|
"transition-all duration-300 ease-in-out",
|
||||||
|
fullscreen
|
||||||
|
? "pointer-events-none translate-y-4 opacity-0"
|
||||||
|
: "translate-y-0 opacity-100",
|
||||||
|
)}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"pointer-events-auto relative w-full max-w-[720px]",
|
"pointer-events-auto relative w-full max-w-[720px]",
|
||||||
isNewThread && "top-[-65px] -translate-y-[calc(50vh-96px)]",
|
isNewThread && "top-[-65px] -translate-y-[calc(50vh-96px)]",
|
||||||
// isNewThread
|
|
||||||
// ? "max-w-(--container-width-sm)"
|
|
||||||
// : "max-w-(--container-width-md)",
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<InputBox
|
<InputBox
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ export type ArtifactProps = HTMLAttributes<HTMLDivElement>;
|
||||||
export const Artifact = ({ className, ...props }: ArtifactProps) => (
|
export const Artifact = ({ className, ...props }: ArtifactProps) => (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-background flex flex-col overflow-hidden rounded-[20px] px-[20px] pt-[15px]",
|
"bg-background flex min-w-(--container-width-sm) flex-col overflow-hidden rounded-[20px] px-[20px] pt-[15px]",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
type HTMLAttributes,
|
type HTMLAttributes,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
@ -57,7 +58,8 @@ export function ArtifactFileDetail({
|
||||||
threadId: string;
|
threadId: string;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { artifacts, setOpen, select } = useArtifacts();
|
const { artifacts, setOpen, select, fullscreen, setFullscreen } =
|
||||||
|
useArtifacts();
|
||||||
const isWriteFile = useMemo(() => {
|
const isWriteFile = useMemo(() => {
|
||||||
return filepathFromProps.startsWith("write-file:");
|
return filepathFromProps.startsWith("write-file:");
|
||||||
}, [filepathFromProps]);
|
}, [filepathFromProps]);
|
||||||
|
|
@ -105,6 +107,33 @@ export function ArtifactFileDetail({
|
||||||
const [isInstalling, setIsInstalling] = useState(false);
|
const [isInstalling, setIsInstalling] = useState(false);
|
||||||
const [zoom, setZoom] = useState(100);
|
const [zoom, setZoom] = useState(100);
|
||||||
const { isMock } = useThread();
|
const { isMock } = useThread();
|
||||||
|
|
||||||
|
// 全屏切换处理
|
||||||
|
const handleFullscreenToggle = useCallback(() => {
|
||||||
|
if (!document.fullscreenElement) {
|
||||||
|
document.documentElement.requestFullscreen().catch((err) => {
|
||||||
|
console.error("无法进入全屏模式:", err);
|
||||||
|
});
|
||||||
|
setFullscreen(true);
|
||||||
|
} else {
|
||||||
|
document.exitFullscreen().catch((err) => {
|
||||||
|
console.error("无法退出全屏模式:", err);
|
||||||
|
});
|
||||||
|
setFullscreen(false);
|
||||||
|
}
|
||||||
|
}, [setFullscreen]);
|
||||||
|
|
||||||
|
// 监听全屏变化
|
||||||
|
useEffect(() => {
|
||||||
|
const handleFullscreenChange = () => {
|
||||||
|
setFullscreen(!!document.fullscreenElement);
|
||||||
|
};
|
||||||
|
document.addEventListener("fullscreenchange", handleFullscreenChange);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("fullscreenchange", handleFullscreenChange);
|
||||||
|
};
|
||||||
|
}, [setFullscreen]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isSupportPreview) {
|
if (isSupportPreview) {
|
||||||
setViewMode("preview");
|
setViewMode("preview");
|
||||||
|
|
@ -172,11 +201,10 @@ export function ArtifactFileDetail({
|
||||||
)}
|
)}
|
||||||
</ArtifactTitle>
|
</ArtifactTitle>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-end gap-2">
|
<div className="flex items-center justify-end overflow-hidden">
|
||||||
{/* 放大缩小选择器 */}
|
{/* 放大缩小选择器 */}
|
||||||
<ArtifactZoomSelector value={zoom} onChange={setZoom} />
|
<ArtifactZoomSelector value={zoom} onChange={setZoom} />
|
||||||
<ArtifactActions>
|
<ArtifactActions>
|
||||||
{/* 新界面打开的按钮 */}
|
|
||||||
{/* {!isWriteFile && filepath.endsWith(".skill") && (
|
{/* {!isWriteFile && filepath.endsWith(".skill") && (
|
||||||
<Tooltip content={t.toolCalls.skillInstallTooltip}>
|
<Tooltip content={t.toolCalls.skillInstallTooltip}>
|
||||||
<ArtifactAction
|
<ArtifactAction
|
||||||
|
|
@ -191,7 +219,8 @@ export function ArtifactFileDetail({
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)} */}
|
)} */}
|
||||||
{!isWriteFile && (
|
{/* 新界面打开的按钮 */}
|
||||||
|
{/* {!isWriteFile && (
|
||||||
<a href={urlOfArtifact({ filepath, threadId })} target="_blank">
|
<a href={urlOfArtifact({ filepath, threadId })} target="_blank">
|
||||||
<ArtifactAction
|
<ArtifactAction
|
||||||
icon={SquareArrowOutUpRightIcon}
|
icon={SquareArrowOutUpRightIcon}
|
||||||
|
|
@ -199,10 +228,10 @@ export function ArtifactFileDetail({
|
||||||
tooltip={t.common.openInNewWindow}
|
tooltip={t.common.openInNewWindow}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)} */}
|
||||||
|
{/* 复制按钮 */}
|
||||||
{isCodeFile && (
|
{isCodeFile && (
|
||||||
<ArtifactAction
|
<ArtifactAction
|
||||||
icon={CopyIcon}
|
|
||||||
label={t.clipboard.copyToClipboard}
|
label={t.clipboard.copyToClipboard}
|
||||||
disabled={!content}
|
disabled={!content}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
|
@ -215,26 +244,143 @@ export function ArtifactFileDetail({
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
tooltip={t.clipboard.copyToClipboard}
|
tooltip={t.clipboard.copyToClipboard}
|
||||||
/>
|
>
|
||||||
|
<svg
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 18 18"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6 2H13C14.1046 2 15 2.89543 15 4V13"
|
||||||
|
stroke="#666666"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
x="2.5"
|
||||||
|
y="4.5"
|
||||||
|
width="10"
|
||||||
|
height="11"
|
||||||
|
rx="1.5"
|
||||||
|
stroke="#666666"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</ArtifactAction>
|
||||||
)}
|
)}
|
||||||
|
{/* 下载按钮 */}
|
||||||
{!isWriteFile && (
|
{!isWriteFile && (
|
||||||
<a
|
<a
|
||||||
href={urlOfArtifact({ filepath, threadId, download: true })}
|
href={urlOfArtifact({ filepath, threadId, download: true })}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<ArtifactAction
|
<ArtifactAction
|
||||||
icon={DownloadIcon}
|
|
||||||
label={t.common.download}
|
label={t.common.download}
|
||||||
tooltip={t.common.download}
|
tooltip={t.common.download}
|
||||||
/>
|
>
|
||||||
|
<svg
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 18 18"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16 9V14C16 15.1046 15.1046 16 14 16H4C2.89543 16 2 15.1046 2 14V9"
|
||||||
|
stroke="#666666"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9 2V13M9 13L5 9M9 13L13 9"
|
||||||
|
stroke="#666666"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</ArtifactAction>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
{/* 全屏按钮 */}
|
||||||
|
<ArtifactAction
|
||||||
|
label={
|
||||||
|
fullscreen ? t.common.closeFullScreen : t.common.fullScreen
|
||||||
|
}
|
||||||
|
onClick={handleFullscreenToggle}
|
||||||
|
tooltip={
|
||||||
|
fullscreen ? t.common.closeFullScreen : t.common.fullScreen
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{fullscreen ? (
|
||||||
|
<svg
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 18 18"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6 2V4C6 5.10457 5.10457 6 4 6H2"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6 16V14C6 12.8954 5.10457 12 4 12H2"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M12 2V4C12 5.10457 12.8954 6 14 6H16"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M12 16V14C12 12.8954 12.8954 12 14 12H16"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<svg
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 18 18"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M5.75 15.5H4.5C3.39543 15.5 2.5 14.6046 2.5 13.5V12.25M2.5 5.75V4.5C2.5 3.39543 3.39543 2.5 4.5 2.5H5.75M12.25 2.5H13.5C14.6046 2.5 15.5 3.39543 15.5 4.5V5.75M15.5 12.25V13.5C15.5 14.6046 14.6046 15.5 13.5 15.5H12.25"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</ArtifactAction>
|
||||||
|
{/* 关闭按钮 */}
|
||||||
<ArtifactAction
|
<ArtifactAction
|
||||||
icon={XIcon}
|
|
||||||
label={t.common.close}
|
label={t.common.close}
|
||||||
onClick={() => setOpen(false)}
|
onClick={() => setOpen(false)}
|
||||||
tooltip={t.common.close}
|
tooltip={t.common.close}
|
||||||
/>
|
>
|
||||||
|
<svg
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 18 18"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M4 14L14 4M4 4L14 14"
|
||||||
|
stroke="#666666"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</ArtifactAction>
|
||||||
</ArtifactActions>
|
</ArtifactActions>
|
||||||
</div>
|
</div>
|
||||||
</ArtifactHeader>
|
</ArtifactHeader>
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@ export interface ArtifactsContextType {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
autoOpen: boolean;
|
autoOpen: boolean;
|
||||||
setOpen: (open: boolean) => void;
|
setOpen: (open: boolean) => void;
|
||||||
|
|
||||||
|
fullscreen: boolean;
|
||||||
|
setFullscreen: (fullscreen: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ArtifactsContext = createContext<ArtifactsContextType | undefined>(
|
const ArtifactsContext = createContext<ArtifactsContextType | undefined>(
|
||||||
|
|
@ -39,6 +42,7 @@ export function ArtifactsProvider({ children }: ArtifactsProviderProps) {
|
||||||
env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true",
|
env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true",
|
||||||
);
|
);
|
||||||
const [autoOpen, setAutoOpen] = useState(true);
|
const [autoOpen, setAutoOpen] = useState(true);
|
||||||
|
const [fullscreen, setFullscreen] = useState(false);
|
||||||
const { setOpen: setSidebarOpen } = useSidebar();
|
const { setOpen: setSidebarOpen } = useSidebar();
|
||||||
|
|
||||||
const select = useCallback(
|
const select = useCallback(
|
||||||
|
|
@ -78,6 +82,9 @@ export function ArtifactsProvider({ children }: ArtifactsProviderProps) {
|
||||||
selectedArtifact,
|
selectedArtifact,
|
||||||
select,
|
select,
|
||||||
deselect,
|
deselect,
|
||||||
|
|
||||||
|
fullscreen,
|
||||||
|
setFullscreen,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import {
|
||||||
} from "../artifacts";
|
} from "../artifacts";
|
||||||
import { useThread } from "../messages/context";
|
import { useThread } from "../messages/context";
|
||||||
|
|
||||||
|
const FULLSCREEN_MODE = { chat: 0, artifacts: 100 };
|
||||||
const CLOSE_MODE = { chat: 100, artifacts: 0 };
|
const CLOSE_MODE = { chat: 100, artifacts: 0 };
|
||||||
const OPEN_MODE = { chat: 50, artifacts: 50 };
|
const OPEN_MODE = { chat: 50, artifacts: 50 };
|
||||||
|
|
||||||
|
|
@ -40,6 +41,7 @@ const ChatBox: React.FC<{ children: React.ReactNode; threadId: string }> = ({
|
||||||
select: selectArtifact,
|
select: selectArtifact,
|
||||||
deselect,
|
deselect,
|
||||||
selectedArtifact,
|
selectedArtifact,
|
||||||
|
fullscreen,
|
||||||
} = useArtifacts();
|
} = useArtifacts();
|
||||||
|
|
||||||
const [autoSelectFirstArtifact, setAutoSelectFirstArtifact] = useState(true);
|
const [autoSelectFirstArtifact, setAutoSelectFirstArtifact] = useState(true);
|
||||||
|
|
@ -88,13 +90,15 @@ const ChatBox: React.FC<{ children: React.ReactNode; threadId: string }> = ({
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (layoutRef.current) {
|
if (layoutRef.current) {
|
||||||
if (artifactPanelOpen) {
|
if (fullscreen) {
|
||||||
|
layoutRef.current.setLayout(FULLSCREEN_MODE);
|
||||||
|
} else if (artifactPanelOpen) {
|
||||||
layoutRef.current.setLayout(OPEN_MODE);
|
layoutRef.current.setLayout(OPEN_MODE);
|
||||||
} else {
|
} else {
|
||||||
layoutRef.current.setLayout(CLOSE_MODE);
|
layoutRef.current.setLayout(CLOSE_MODE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [artifactPanelOpen]);
|
}, [artifactPanelOpen, fullscreen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResizablePanelGroup
|
<ResizablePanelGroup
|
||||||
|
|
@ -103,7 +107,10 @@ const ChatBox: React.FC<{ children: React.ReactNode; threadId: string }> = ({
|
||||||
groupRef={layoutRef}
|
groupRef={layoutRef}
|
||||||
>
|
>
|
||||||
<ResizablePanel
|
<ResizablePanel
|
||||||
className="relative overflow-hidden rounded-t-[20px]"
|
className={cn(
|
||||||
|
"relative overflow-hidden rounded-t-[20px] transition-opacity duration-300 ease-in-out",
|
||||||
|
fullscreen && "pointer-events-none opacity-0",
|
||||||
|
)}
|
||||||
defaultSize={100}
|
defaultSize={100}
|
||||||
id="chat"
|
id="chat"
|
||||||
>
|
>
|
||||||
|
|
@ -111,8 +118,9 @@ const ChatBox: React.FC<{ children: React.ReactNode; threadId: string }> = ({
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
<ResizableHandle
|
<ResizableHandle
|
||||||
className={cn(
|
className={cn(
|
||||||
"opacity-33 hover:opacity-100",
|
"opacity-33 transition-opacity duration-300 hover:opacity-100",
|
||||||
!artifactPanelOpen && "pointer-events-none opacity-0",
|
!artifactPanelOpen && "pointer-events-none opacity-0",
|
||||||
|
fullscreen && "pointer-events-none opacity-0",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<ResizablePanel
|
<ResizablePanel
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ export interface Translations {
|
||||||
share: string;
|
share: string;
|
||||||
openInNewWindow: string;
|
openInNewWindow: string;
|
||||||
close: string;
|
close: string;
|
||||||
|
fullScreen: string;
|
||||||
|
closeFullScreen: string;
|
||||||
more: string;
|
more: string;
|
||||||
search: string;
|
search: string;
|
||||||
download: string;
|
download: string;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ export const zhCN: Translations = {
|
||||||
share: "分享",
|
share: "分享",
|
||||||
openInNewWindow: "在新窗口打开",
|
openInNewWindow: "在新窗口打开",
|
||||||
close: "关闭",
|
close: "关闭",
|
||||||
|
fullScreen: "全屏",
|
||||||
|
closeFullScreen: "关闭全屏",
|
||||||
more: "更多",
|
more: "更多",
|
||||||
search: "搜索",
|
search: "搜索",
|
||||||
download: "下载",
|
download: "下载",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue