mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-09-07 08:37:05 +08:00
refactor: init switching to nextjs router
This commit is contained in:
@@ -53,6 +53,8 @@ export interface TriggerProps
|
||||
|
||||
const baseZIndex = 150;
|
||||
|
||||
let div: HTMLDivElement | null = null;
|
||||
|
||||
const Modal = (props: ModalProps) => {
|
||||
const {
|
||||
onOk,
|
||||
@@ -78,6 +80,16 @@ const Modal = (props: ModalProps) => {
|
||||
|
||||
const mergeOpen = visible ?? open;
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const div: HTMLDivElement = document.createElement("div");
|
||||
div.id = "confirm-root";
|
||||
div.style.height = "0px";
|
||||
document.body.appendChild(div);
|
||||
}, []);
|
||||
const root = createRoot(div);
|
||||
const closeModal = () => {
|
||||
root.unmount();
|
||||
};
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
onCancel?.();
|
||||
@@ -121,7 +133,7 @@ const Modal = (props: ModalProps) => {
|
||||
<AlertDialog.Root open={mergeOpen} onOpenChange={setOpen}>
|
||||
<AlertDialog.Portal>
|
||||
<AlertDialog.Overlay
|
||||
className="bg-modal-mask fixed inset-0 animate-mask "
|
||||
className="fixed inset-0 bg-modal-mask animate-mask "
|
||||
style={{ zIndex: baseZIndex - 1 }}
|
||||
onClick={() => {
|
||||
if (maskCloseble) {
|
||||
@@ -165,7 +177,7 @@ const Modal = (props: ModalProps) => {
|
||||
${titleClassName}
|
||||
`}
|
||||
>
|
||||
<div className="flex gap-3 justify-start flex-1 items-center text-text-modal-title text-chat-header-title">
|
||||
<div className="flex items-center justify-start flex-1 gap-3 text-text-modal-title text-chat-header-title">
|
||||
{title}
|
||||
</div>
|
||||
{closeble && (
|
||||
@@ -283,11 +295,6 @@ export const Warn = ({
|
||||
);
|
||||
};
|
||||
|
||||
const div = document.createElement("div");
|
||||
div.id = "confirm-root";
|
||||
div.style.height = "0px";
|
||||
document.body.appendChild(div);
|
||||
|
||||
Modal.warn = (props: Omit<WarnProps, "visible" | "onCancel" | "onOk">) => {
|
||||
const root = createRoot(div);
|
||||
const closeModal = () => {
|
||||
|
@@ -1,3 +1,4 @@
|
||||
"use client";
|
||||
import useRelativePosition from "@/app/hooks/useRelativePosition";
|
||||
import {
|
||||
RefObject,
|
||||
@@ -36,19 +37,6 @@ const ArrowIcon = ({ sibling }: { sibling: RefObject<HTMLDivElement> }) => {
|
||||
|
||||
const baseZIndex = 100;
|
||||
const popoverRootName = "popoverRoot";
|
||||
let popoverRoot = document.querySelector(
|
||||
`#${popoverRootName}`,
|
||||
) as HTMLDivElement;
|
||||
if (!popoverRoot) {
|
||||
popoverRoot = document.createElement("div");
|
||||
document.body.appendChild(popoverRoot);
|
||||
popoverRoot.style.height = "0px";
|
||||
popoverRoot.style.width = "100%";
|
||||
popoverRoot.style.position = "fixed";
|
||||
popoverRoot.style.bottom = "0";
|
||||
popoverRoot.style.zIndex = "10000";
|
||||
popoverRoot.id = "popover-root";
|
||||
}
|
||||
|
||||
export interface PopoverProps {
|
||||
content?: JSX.Element | string;
|
||||
@@ -65,6 +53,8 @@ export interface PopoverProps {
|
||||
getPopoverPanelRef?: (ref: RefObject<HTMLDivElement>) => void;
|
||||
}
|
||||
|
||||
let popoverRoot: HTMLDivElement;
|
||||
|
||||
export default function Popover(props: PopoverProps) {
|
||||
const {
|
||||
content,
|
||||
@@ -184,6 +174,26 @@ export default function Popover(props: PopoverProps) {
|
||||
const popoverRef = useRef<HTMLDivElement>(null);
|
||||
const closeTimer = useRef<number>(0);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (popoverRoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
popoverRoot = document.querySelector(
|
||||
`#${popoverRootName}`,
|
||||
) as HTMLDivElement;
|
||||
if (!popoverRoot) {
|
||||
popoverRoot = document.createElement("div");
|
||||
document.body.appendChild(popoverRoot);
|
||||
popoverRoot.style.height = "0px";
|
||||
popoverRoot.style.width = "100%";
|
||||
popoverRoot.style.position = "fixed";
|
||||
popoverRoot.style.bottom = "0";
|
||||
popoverRoot.style.zIndex = "10000";
|
||||
popoverRoot.id = "popover-root";
|
||||
}
|
||||
}, []);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
getPopoverPanelRef?.(popoverRef);
|
||||
onShow?.(internalShow);
|
||||
@@ -207,6 +217,10 @@ export default function Popover(props: PopoverProps) {
|
||||
window.document.documentElement.style.overflow = "auto";
|
||||
};
|
||||
|
||||
if (mergedShow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative ${className}`}
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useMemo, ReactNode } from "react";
|
||||
import { Path, SIDEBAR_ID, SlotID } from "@/app/constant";
|
||||
import { getLang } from "@/app/locales";
|
||||
|
||||
import useMobileScreen from "@/app/hooks/useMobileScreen";
|
||||
import { isIOS } from "@/app/utils";
|
||||
|
||||
import useListenWinResize from "@/app/hooks/useListenWinResize";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useDeviceInfo } from "@/app/hooks/useDeviceInfo";
|
||||
|
||||
interface ScreenProps {
|
||||
children: ReactNode;
|
||||
@@ -14,15 +15,11 @@ interface ScreenProps {
|
||||
}
|
||||
|
||||
export default function Screen(props: ScreenProps) {
|
||||
const location = useLocation();
|
||||
const isAuth = location.pathname === Path.Auth;
|
||||
const pathname = usePathname();
|
||||
const isAuth = pathname === Path.Auth;
|
||||
|
||||
const isMobileScreen = useMobileScreen();
|
||||
const isIOSMobile = useMemo(
|
||||
() => isIOS() && isMobileScreen,
|
||||
[isMobileScreen],
|
||||
);
|
||||
|
||||
const { deviceType, systemInfo } = useDeviceInfo();
|
||||
useListenWinResize();
|
||||
|
||||
return (
|
||||
@@ -59,7 +56,10 @@ export default function Screen(props: ScreenProps) {
|
||||
id={SlotID.AppBody}
|
||||
style={{
|
||||
// #3016 disable transition on ios mobile screen
|
||||
transition: isIOSMobile ? "none" : undefined,
|
||||
transition:
|
||||
systemInfo === "iOS" && deviceType === "mobile"
|
||||
? "none"
|
||||
: undefined,
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
|
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
import styles from "./auth.module.scss";
|
||||
import { IconButton } from "./button";
|
||||
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Path } from "../constant";
|
||||
import { useAccessStore } from "../store";
|
||||
import Locale from "../locales";
|
||||
@@ -11,11 +12,11 @@ import { useEffect } from "react";
|
||||
import { getClientConfig } from "../config/client";
|
||||
|
||||
export function AuthPage() {
|
||||
const navigate = useNavigate();
|
||||
const router = useRouter();
|
||||
const accessStore = useAccessStore();
|
||||
|
||||
const goHome = () => navigate(Path.Home);
|
||||
const goChat = () => navigate(Path.Chat);
|
||||
const goHome = () => router.push(Path.Home);
|
||||
const goChat = () => router.push(Path.Chat);
|
||||
const resetAccessCode = () => {
|
||||
accessStore.update((access) => {
|
||||
access.openaiApiKey = "";
|
||||
|
@@ -12,13 +12,14 @@ import {
|
||||
import { useChatStore } from "../store";
|
||||
|
||||
import Locale from "../locales";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
// import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import { Path } from "../constant";
|
||||
import { MaskAvatar } from "./mask";
|
||||
import { Mask } from "../store/mask";
|
||||
import { useRef, useEffect } from "react";
|
||||
import { showConfirm } from "./ui-lib";
|
||||
import { useMobileScreen } from "../utils";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
|
||||
export function ChatItem(props: {
|
||||
onClick?: () => void;
|
||||
@@ -41,14 +42,14 @@ export function ChatItem(props: {
|
||||
}
|
||||
}, [props.selected]);
|
||||
|
||||
const { pathname: currentPath } = useLocation();
|
||||
const pathname = usePathname();
|
||||
return (
|
||||
<Draggable draggableId={`${props.id}`} index={props.index}>
|
||||
{(provided) => (
|
||||
<div
|
||||
className={`${styles["chat-item"]} ${
|
||||
props.selected &&
|
||||
(currentPath === Path.Chat || currentPath === Path.Home) &&
|
||||
(pathname === Path.Chat || pathname === Path.Home) &&
|
||||
styles["chat-item-selected"]
|
||||
}`}
|
||||
onClick={props.onClick}
|
||||
@@ -112,8 +113,8 @@ export function ChatList(props: { narrow?: boolean }) {
|
||||
],
|
||||
);
|
||||
const chatStore = useChatStore();
|
||||
const navigate = useNavigate();
|
||||
const isMobileScreen = useMobileScreen();
|
||||
const router = useRouter();
|
||||
|
||||
const onDragEnd: OnDragEndResponder = (result) => {
|
||||
const { destination, source } = result;
|
||||
@@ -150,7 +151,8 @@ export function ChatList(props: { narrow?: boolean }) {
|
||||
index={i}
|
||||
selected={i === selectedIndex}
|
||||
onClick={() => {
|
||||
navigate(Path.Chat);
|
||||
// navigate(Path.Chat);
|
||||
router.push(Path.Chat);
|
||||
selectSession(i);
|
||||
}}
|
||||
onDelete={async () => {
|
||||
|
@@ -97,6 +97,7 @@ import { ExportMessageModal } from "./exporter";
|
||||
import { getClientConfig } from "../config/client";
|
||||
import { useAllModels } from "../utils/hooks";
|
||||
import { MultimodalContent } from "../client/api";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
|
||||
loading: () => <LoadingIcon />,
|
||||
@@ -428,7 +429,7 @@ export function ChatActions(props: {
|
||||
uploading: boolean;
|
||||
}) {
|
||||
const config = useAppConfig();
|
||||
const navigate = useNavigate();
|
||||
const router = useRouter();
|
||||
const chatStore = useChatStore();
|
||||
|
||||
// switch themes
|
||||
@@ -543,7 +544,8 @@ export function ChatActions(props: {
|
||||
|
||||
<ChatAction
|
||||
onClick={() => {
|
||||
navigate(Path.Masks);
|
||||
// navigate(Path.Masks);
|
||||
router.push(Path.Masks);
|
||||
}}
|
||||
text={Locale.Chat.InputActions.Masks}
|
||||
icon={<MaskIcon />}
|
||||
|
@@ -27,9 +27,9 @@ import {
|
||||
} from "../constant";
|
||||
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { isIOS, useMobileScreen } from "../utils";
|
||||
import dynamic from "next/dynamic";
|
||||
import { showConfirm, showToast } from "./ui-lib";
|
||||
import { useDeviceInfo } from "../hooks/useDeviceInfo";
|
||||
|
||||
const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
|
||||
loading: () => null,
|
||||
@@ -130,16 +130,11 @@ function useDragSideBar() {
|
||||
|
||||
export function SideBar(props: { className?: string }) {
|
||||
const chatStore = useChatStore();
|
||||
|
||||
const { deviceType, systemInfo } = useDeviceInfo();
|
||||
// drag side bar
|
||||
const { onDragStart, shouldNarrow } = useDragSideBar();
|
||||
const navigate = useNavigate();
|
||||
const config = useAppConfig();
|
||||
const isMobileScreen = useMobileScreen();
|
||||
const isIOSMobile = useMemo(
|
||||
() => isIOS() && isMobileScreen,
|
||||
[isMobileScreen],
|
||||
);
|
||||
|
||||
useHotKey();
|
||||
|
||||
@@ -150,7 +145,8 @@ export function SideBar(props: { className?: string }) {
|
||||
}`}
|
||||
style={{
|
||||
// #3016 disable transition on ios mobile screen
|
||||
transition: isMobileScreen && isIOSMobile ? "none" : undefined,
|
||||
transition:
|
||||
deviceType === "mobile" && systemInfo === "iOS" ? "none" : undefined,
|
||||
}}
|
||||
>
|
||||
<div className={styles["sidebar-header"]} data-tauri-drag-region>
|
||||
|
Reference in New Issue
Block a user