mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-09-01 20:56:59 +08:00
feat: optiminize message&img display
This commit is contained in:
52
app/components/Imgs/index.tsx
Normal file
52
app/components/Imgs/index.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { CSSProperties } from "react";
|
||||
import { getMessageImages } from "@/app/utils";
|
||||
import { RequestMessage } from "@/app/client/api";
|
||||
|
||||
interface ImgsProps {
|
||||
message: RequestMessage;
|
||||
isMobileScreen?: boolean;
|
||||
}
|
||||
|
||||
export default function Imgs(props: ImgsProps) {
|
||||
const { message, isMobileScreen } = props;
|
||||
const imgSrcs = getMessageImages(message);
|
||||
|
||||
if (imgSrcs.length < 1) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
let imgVars = {
|
||||
"--imgs-width": `calc(var(--max-message-width) - ${
|
||||
imgSrcs.length - 1
|
||||
}*0.25rem)`,
|
||||
"--img-width": `calc(var(--imgs-width)/ ${imgSrcs.length})`,
|
||||
};
|
||||
|
||||
if (isMobileScreen) {
|
||||
imgVars = {
|
||||
"--imgs-width": `calc(var(--max-message-width) - ${
|
||||
imgSrcs.length - 1
|
||||
}*0.25rem)`,
|
||||
"--img-width": `calc(var(--imgs-width)/ ${imgSrcs.length})`,
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`w-[100%] mt-[0.625rem] flex gap-1`}
|
||||
style={imgVars as CSSProperties}
|
||||
>
|
||||
{imgSrcs.map((image, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="flex-1 min-w-[var(--img-width)] pb-[var(--img-width)] object-cover bg-cover bg-no-repeat bg-center box-border rounded-chat-img"
|
||||
style={{
|
||||
backgroundImage: `url(${image})`,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useMemo, ReactNode } from "react";
|
||||
import { Path, SlotID } from "@/app/constant";
|
||||
import { Path, SIDEBAR_ID, SlotID } from "@/app/constant";
|
||||
import { getLang } from "@/app/locales";
|
||||
|
||||
import useMobileScreen from "@/app/hooks/useMobileScreen";
|
||||
@@ -47,7 +47,9 @@ export default function Screen(props: ScreenProps) {
|
||||
props.noAuth
|
||||
) : (
|
||||
<>
|
||||
<div className={sidebarClassName}>{props.sidebar}</div>
|
||||
<div className={sidebarClassName} id={SIDEBAR_ID}>
|
||||
{props.sidebar}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={pageClassName}
|
||||
|
@@ -49,6 +49,8 @@ export enum StoreKey {
|
||||
Sync = "sync",
|
||||
}
|
||||
|
||||
export const NARROW_SIDEBAR_WIDTH = 100;
|
||||
|
||||
export const DEFAULT_SIDEBAR_WIDTH = 340;
|
||||
export const MAX_SIDEBAR_WIDTH = 440;
|
||||
export const MIN_SIDEBAR_WIDTH = 230;
|
||||
@@ -383,3 +385,5 @@ export const internalWhiteWebDavEndpoints = [
|
||||
"https://webdav.yandex.com",
|
||||
"https://app.koofr.net/dav/Koofr",
|
||||
];
|
||||
|
||||
export const SIDEBAR_ID = "sidebar";
|
||||
|
@@ -20,6 +20,7 @@ import useRelativePosition, {
|
||||
Orientation,
|
||||
} from "@/app/hooks/useRelativePosition";
|
||||
import MessageActions, { RenderMessage } from "./MessageActions";
|
||||
import Imgs from "@/app/components/Imgs";
|
||||
|
||||
export type { RenderMessage };
|
||||
|
||||
@@ -186,7 +187,11 @@ export default function ChatMessagePanel(props: ChatMessagePanelProps) {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className={`group relative max-w-message-width`}>
|
||||
<div
|
||||
className={`group relative flex-1 flex ${
|
||||
isUser ? "flex-row-reverse" : ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={` pointer-events-none text-gray-500 text-right text-time whitespace-nowrap transition-all duration-500 text-sm absolute z-1 ${
|
||||
isUser ? "right-0" : "left-0"
|
||||
@@ -198,10 +203,10 @@ export default function ChatMessagePanel(props: ChatMessagePanelProps) {
|
||||
</div>
|
||||
<div
|
||||
className={`transition-all duration-300 select-text break-words font-common text-sm-title ${
|
||||
isUser ? "rounded-user-message" : "rounded-bot-message"
|
||||
} box-border peer py-2 px-3 ${
|
||||
isUser ? "text-right bg-message-bg" : " bg-white"
|
||||
}`}
|
||||
isUser
|
||||
? "rounded-user-message bg-message-bg"
|
||||
: "rounded-bot-message bg-white"
|
||||
} box-border peer py-2 px-3`}
|
||||
onPointerMoveCapture={(e) =>
|
||||
getRelativePosition(e.currentTarget, message.id)
|
||||
}
|
||||
@@ -221,22 +226,11 @@ export default function ChatMessagePanel(props: ChatMessagePanelProps) {
|
||||
fontSize={fontSize}
|
||||
parentRef={scrollRef}
|
||||
defaultShow={i >= messages.length - 6}
|
||||
className={isUser ? " text-white" : "text-black"}
|
||||
className={`max-w-message-width ${
|
||||
isUser ? " text-white" : "text-black"
|
||||
}`}
|
||||
/>
|
||||
{getMessageImages(message).length > 0 && (
|
||||
<div className={`w-[100%]`}>
|
||||
{getMessageImages(message).map((image, index) => {
|
||||
return (
|
||||
<img
|
||||
className={`w-[100%] mt-2.5 rounded-chat-img`}
|
||||
key={index}
|
||||
src={image}
|
||||
alt=""
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<Imgs message={message} isMobileScreen={isMobileScreen} />
|
||||
</div>
|
||||
<MessageActions
|
||||
className={actionsBarPosition}
|
||||
|
@@ -3,8 +3,9 @@ import {
|
||||
MAX_SIDEBAR_WIDTH,
|
||||
MIN_SIDEBAR_WIDTH,
|
||||
} from "@/app/constant";
|
||||
import { useAppConfig } from "../store/config";
|
||||
import { useAppConfig } from "@/app/store/config";
|
||||
import { useRef } from "react";
|
||||
import { updateGlobalCSSVars } from "@/app/utils/client";
|
||||
|
||||
export default function useDragSideBar() {
|
||||
const limit = (x: number) =>
|
||||
@@ -35,9 +36,11 @@ export default function useDragSideBar() {
|
||||
const d = e.clientX - startX.current;
|
||||
const nextWidth = limit(startDragWidth.current + d);
|
||||
|
||||
const { menuWidth } = updateGlobalCSSVars(nextWidth);
|
||||
|
||||
document.documentElement.style.setProperty(
|
||||
"--sidebar-width",
|
||||
`${nextWidth}px`,
|
||||
"--menu-width",
|
||||
`${menuWidth}px`,
|
||||
);
|
||||
config.update((config) => {
|
||||
config.sidebarWidth = nextWidth;
|
||||
@@ -62,7 +65,7 @@ export default function useDragSideBar() {
|
||||
|
||||
// useLayoutEffect(() => {
|
||||
// const barWidth = limit(config.sidebarWidth ?? DEFAULT_SIDEBAR_WIDTH);
|
||||
// document.documentElement.style.setProperty("--sidebar-width", `${barWidth}px`);
|
||||
// document.documentElement.style.setProperty("--menu-width", `${barWidth}px`);
|
||||
// }, [config.sidebarWidth]);
|
||||
|
||||
return {
|
||||
|
@@ -8,8 +8,10 @@ import {
|
||||
DEFAULT_SIDEBAR_WIDTH,
|
||||
MAX_SIDEBAR_WIDTH,
|
||||
MIN_SIDEBAR_WIDTH,
|
||||
SIDEBAR_ID,
|
||||
} from "@/app/constant";
|
||||
import { useAppConfig } from "../store/config";
|
||||
import { useAppConfig } from "@/app/store/config";
|
||||
import { updateGlobalCSSVars } from "@/app/utils/client";
|
||||
|
||||
export const MOBILE_MAX_WIDTH = 768;
|
||||
|
||||
@@ -42,16 +44,10 @@ export default function useListenWinResize() {
|
||||
}
|
||||
}
|
||||
|
||||
nextSidebar = Math.max(
|
||||
MIN_SIDEBAR_WIDTH,
|
||||
Math.min(MAX_SIDEBAR_WIDTH, nextSidebar),
|
||||
);
|
||||
document.documentElement.style.setProperty(
|
||||
"--sidebar-width",
|
||||
`${nextSidebar}px`,
|
||||
);
|
||||
const { menuWidth } = updateGlobalCSSVars(nextSidebar);
|
||||
|
||||
config.update((config) => {
|
||||
config.sidebarWidth = nextSidebar;
|
||||
config.sidebarWidth = menuWidth;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@@ -28,4 +28,5 @@ body {
|
||||
--tip-popover-color: #434360;
|
||||
--chat-panel-bg: rgb(249, 250, 251, 1);
|
||||
--siderbar-mobile-height: 3.125rem;
|
||||
--max-message-width: calc(var(--chat-panel-max-width) * 0.6);
|
||||
}
|
||||
|
@@ -61,7 +61,7 @@
|
||||
|
||||
--window-width: 90vw;
|
||||
--window-height: 90vh;
|
||||
// --sidebar-width: 300px;
|
||||
--sidebar-width: 300px;
|
||||
--window-content-width: calc(100% - var(--sidebar-width));
|
||||
--message-max-width: 80%;
|
||||
--full-height: 100%;
|
||||
@@ -71,7 +71,7 @@
|
||||
:root {
|
||||
--window-width: 100vw;
|
||||
--window-height: var(--full-height);
|
||||
// --sidebar-width: 100vw;
|
||||
--sidebar-width: 100vw;
|
||||
--window-content-width: var(--window-width);
|
||||
--message-max-width: 100%;
|
||||
}
|
||||
|
34
app/utils/client.ts
Normal file
34
app/utils/client.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import {
|
||||
MAX_SIDEBAR_WIDTH,
|
||||
MIN_SIDEBAR_WIDTH,
|
||||
SIDEBAR_ID,
|
||||
WINDOW_WIDTH_MD,
|
||||
} from "@/app/constant";
|
||||
|
||||
export function updateGlobalCSSVars(nextSidebar: number) {
|
||||
const windowSize = window.innerWidth;
|
||||
const inMobile = windowSize <= WINDOW_WIDTH_MD;
|
||||
|
||||
nextSidebar = Math.max(
|
||||
MIN_SIDEBAR_WIDTH,
|
||||
Math.min(MAX_SIDEBAR_WIDTH, nextSidebar),
|
||||
);
|
||||
|
||||
const menuWidth = inMobile ? 0 : nextSidebar;
|
||||
const navigateBarWidth = inMobile
|
||||
? 0
|
||||
: document.querySelector(`#${SIDEBAR_ID}`)?.clientWidth ?? 0;
|
||||
const chatPanelWidth = windowSize - navigateBarWidth - menuWidth;
|
||||
|
||||
document.documentElement.style.setProperty("--menu-width", `${menuWidth}px`);
|
||||
document.documentElement.style.setProperty(
|
||||
"--navigate-bar-width",
|
||||
`${navigateBarWidth}px`,
|
||||
);
|
||||
document.documentElement.style.setProperty(
|
||||
"--chat-panel-max-width",
|
||||
`${chatPanelWidth}px`,
|
||||
);
|
||||
|
||||
return { menuWidth };
|
||||
}
|
Reference in New Issue
Block a user