mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-09-04 22:46:55 +08:00
feat: optiminize
This commit is contained in:
@@ -76,7 +76,7 @@ export default function ActionsBar(props: ActionsBarProps) {
|
||||
return (
|
||||
<div
|
||||
key={action.id}
|
||||
className={` shrink-1 grow-0 basis-[${
|
||||
className={` cursor-pointer shrink-1 grow-0 basis-[${
|
||||
(100 - 1) / arr.length
|
||||
}%] flex flex-col items-center justify-center gap-0.5
|
||||
${
|
||||
@@ -98,7 +98,7 @@ export default function ActionsBar(props: ActionsBarProps) {
|
||||
return (
|
||||
<div
|
||||
key={action.id}
|
||||
className={`p-3 ${
|
||||
className={`cursor-pointer p-3 ${
|
||||
selected === action.id
|
||||
? "bg-actions-bar-btn-default"
|
||||
: "bg-transparent"
|
||||
|
@@ -4,22 +4,22 @@ export interface CardProps {
|
||||
className?: string;
|
||||
children?: ReactNode;
|
||||
title?: ReactNode;
|
||||
inMobile?: boolean;
|
||||
}
|
||||
|
||||
export default function Card(props: CardProps) {
|
||||
const { className, children, title, inMobile } = props;
|
||||
|
||||
let titleClassName = "ml-4 mb-3";
|
||||
if (inMobile) {
|
||||
titleClassName = "ml-3 mb-3";
|
||||
}
|
||||
const { className, children, title } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
{title && (
|
||||
<div
|
||||
className={`capitalize font-black font-setting-card-title text-sm-mobile font-weight-setting-card-title ${titleClassName}`}
|
||||
className={`
|
||||
capitalize font-black font-setting-card-title text-sm-mobile font-weight-setting-card-title
|
||||
mb-3
|
||||
|
||||
ml-3
|
||||
md:ml-4
|
||||
`}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
|
@@ -4,33 +4,23 @@ import { RequestMessage } from "@/app/client/api";
|
||||
|
||||
interface ImgsProps {
|
||||
message: RequestMessage;
|
||||
isMobileScreen?: boolean;
|
||||
}
|
||||
|
||||
export default function Imgs(props: ImgsProps) {
|
||||
const { message, isMobileScreen } = props;
|
||||
const { message } = props;
|
||||
const imgSrcs = getMessageImages(message);
|
||||
|
||||
if (imgSrcs.length < 1) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
let imgVars = {
|
||||
const 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`}
|
||||
|
@@ -73,7 +73,7 @@ export default function Input(props: CommonInputProps & InputProps) {
|
||||
}}
|
||||
/>
|
||||
{type == "password" && (
|
||||
<div onClick={() => setShow((pre) => !pre)}>
|
||||
<div className=" cursor-pointer" onClick={() => setShow((pre) => !pre)}>
|
||||
{show ? <PasswordVisible /> : <PasswordInvisible />}
|
||||
</div>
|
||||
)}
|
||||
|
@@ -52,20 +52,13 @@ export function ListItem(props: ListItemProps) {
|
||||
|
||||
const context = useContext(ListContext);
|
||||
|
||||
const [childrenMeta, setMeta] = useState<ChildrenMeta>({});
|
||||
const [childrenType, setMeta] = useState<ChildrenMeta["type"]>("unknown");
|
||||
|
||||
const { isMobileScreen, inputNextLine, rangeNextLine } = context;
|
||||
|
||||
let containerClassName = "py-3";
|
||||
let titleClassName = "";
|
||||
if (isMobileScreen) {
|
||||
containerClassName = "py-2";
|
||||
titleClassName = "";
|
||||
}
|
||||
const { inputNextLine, rangeNextLine } = context;
|
||||
|
||||
let internalNextLine;
|
||||
|
||||
switch (childrenMeta.type) {
|
||||
switch (childrenType) {
|
||||
case "input":
|
||||
internalNextLine = !!(nextline || inputNextLine);
|
||||
break;
|
||||
@@ -76,20 +69,18 @@ export function ListItem(props: ListItemProps) {
|
||||
internalNextLine = false;
|
||||
}
|
||||
|
||||
const update = useCallback((m: ChildrenMeta) => {
|
||||
setMeta(m);
|
||||
const updateType = useCallback((m: ChildrenMeta) => {
|
||||
setMeta(m.type);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative after:h-[0.5px] after:bottom-0 after:w-[100%] after:left-0 after:absolute last:after:hidden after:bg-list-item-divider ${
|
||||
internalNextLine ? "" : "flex gap-3"
|
||||
} justify-between items-center px-0 ${containerClassName} ${className}`}
|
||||
} justify-between items-center px-0 py-2 md:py-3 ${className}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div
|
||||
className={`flex-1 flex flex-col justify-start gap-1 ${titleClassName}`}
|
||||
>
|
||||
<div className={`flex-1 flex flex-col justify-start gap-1`}>
|
||||
<div className=" font-common text-sm-mobile font-weight-[500] line-clamp-1">
|
||||
{title}
|
||||
</div>
|
||||
@@ -97,7 +88,7 @@ export function ListItem(props: ListItemProps) {
|
||||
<div className={` text-sm text-text-list-subtitle`}>{subTitle}</div>
|
||||
)}
|
||||
</div>
|
||||
<ListContext.Provider value={{ ...context, update }}>
|
||||
<ListContext.Provider value={{ ...context, update: updateType }}>
|
||||
<div
|
||||
className={`${
|
||||
internalNextLine ? "mt-[0.625rem]" : "max-w-[70%]"
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import useMobileScreen from "@/app/hooks/useMobileScreen";
|
||||
import BotIcon from "@/app/icons/bot.svg";
|
||||
import LoadingIcon from "@/app/icons/three-dots.svg";
|
||||
|
||||
@@ -16,15 +15,17 @@ export default function Loading({
|
||||
theme = getCSSVar("--default-container-bg");
|
||||
}
|
||||
|
||||
const isMobileScreen = useMobileScreen();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex flex-col justify-center items-center w-[100%] ${
|
||||
isMobileScreen
|
||||
? "h-[100%]"
|
||||
: `my-2.5 ml-1 mr-2.5 rounded-md h-[calc(100%-1.25rem)]`
|
||||
}`}
|
||||
className={`
|
||||
flex flex-col justify-center items-center w-[100%]
|
||||
h-[100%]
|
||||
md:my-2.5
|
||||
md:ml-1
|
||||
md:mr-2.5
|
||||
md:rounded-md
|
||||
md:h-[calc(100%-1.25rem)]
|
||||
`}
|
||||
style={{ background: useSkeleton ? theme : "" }}
|
||||
>
|
||||
{!noLogo && <BotIcon />}
|
||||
|
@@ -59,23 +59,20 @@ export default function MenuLayout<
|
||||
),
|
||||
});
|
||||
|
||||
let containerClassName = "flex h-[100%] w-[100%]";
|
||||
let listClassName =
|
||||
"relative basis-sidebar h-[calc(100%-1.25rem)] pb-6 max-md:px-4 max-md:pb-4 rounded-md my-2.5 bg-menu";
|
||||
let panelClassName = "flex-1 h-[100%] w-page";
|
||||
|
||||
if (isMobileScreen) {
|
||||
containerClassName = "h-[100%] w-[100%] relative bg-center";
|
||||
listClassName = `h-[100%] w-[100%] flex-1 px-4`;
|
||||
panelClassName = `transition-all duration-300 absolute top-0 max-h-[100vh] w-[100%] ${
|
||||
showPanel ? "left-0" : "left-[101%]"
|
||||
} z-10`;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${containerClassName}`}>
|
||||
<div
|
||||
className={`
|
||||
h-[100%] w-[100%] relative bg-center
|
||||
md:flex
|
||||
`}
|
||||
>
|
||||
<div
|
||||
className={`flex flex-col px-6 ${listClassName}`}
|
||||
className={`
|
||||
flex flex-col px-6
|
||||
h-[100%]
|
||||
max-md:w-[100%] max-md:px-4 max-md:pb-4 max-md:flex-1
|
||||
md:relative md:basis-sidebar md:h-[calc(100%-1.25rem)] md:pb-6 md:rounded-md md:my-2.5 md:bg-menu
|
||||
`}
|
||||
onClick={(e) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
navigate(Path.Home);
|
||||
@@ -101,7 +98,14 @@ export default function MenuLayout<
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={`${panelClassName}`}>
|
||||
<div
|
||||
className={`
|
||||
md:flex-1 md:h-[100%] md:w-page
|
||||
max-md:transition-all max-md:duration-300 max-md:absolute max-md:top-0 max-md:max-h-[100vh] max-md:w-[100%] ${
|
||||
showPanel ? "max-md:left-0" : "max-md:left-[101%]"
|
||||
} max-md:z-10
|
||||
`}
|
||||
>
|
||||
<PanelComponent
|
||||
{...props}
|
||||
setShowPanel={setShowPanel}
|
||||
|
@@ -184,7 +184,7 @@ export default function Popover(props: {
|
||||
)}
|
||||
{createPortal(
|
||||
<div
|
||||
className={`${popoverCommonClass} ${popoverClassName}`}
|
||||
className={`${popoverCommonClass} ${popoverClassName} cursor-pointer`}
|
||||
style={{ zIndex: baseZIndex + 1, ...placementStyle }}
|
||||
>
|
||||
{content}
|
||||
|
@@ -25,20 +25,13 @@ export default function Screen(props: ScreenProps) {
|
||||
|
||||
useListenWinResize();
|
||||
|
||||
let containerClassName = "flex h-[100%] w-[100%] bg-center overflow-hidden";
|
||||
let sidebarClassName = "flex-0 overflow-hidden";
|
||||
let pageClassName = "flex-1 h-[100%] min-w-0 overflow-hidden";
|
||||
|
||||
if (isMobileScreen) {
|
||||
containerClassName =
|
||||
"relative flex flex-col-reverse h-[100%] w-[100%] bg-center";
|
||||
sidebarClassName = "absolute w-[100%] bottom-0 z-10";
|
||||
pageClassName = "w-[100%] h-[100%]";
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`bg-global ${containerClassName}`}
|
||||
className={`
|
||||
bg-global flex h-[100%] w-[100%] bg-center
|
||||
max-md:relative max-md:flex-col-reverse
|
||||
md:overflow-hidden
|
||||
`}
|
||||
style={{
|
||||
direction: getLang() === "ar" ? "rtl" : "ltr",
|
||||
}}
|
||||
@@ -47,16 +40,26 @@ export default function Screen(props: ScreenProps) {
|
||||
props.noAuth
|
||||
) : (
|
||||
<>
|
||||
<div className={sidebarClassName} id={SIDEBAR_ID}>
|
||||
<div
|
||||
className={`
|
||||
max-md:absolute max-md:w-[100%] max-md:bottom-0 max-md:z-10
|
||||
md:flex-0 md:overflow-hidden
|
||||
`}
|
||||
id={SIDEBAR_ID}
|
||||
>
|
||||
{props.sidebar}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={pageClassName}
|
||||
className={`
|
||||
h-[100%]
|
||||
max-md:w-[100%]
|
||||
md:flex-1 md:min-w-0 md:overflow-hidden
|
||||
`}
|
||||
id={SlotID.AppBody}
|
||||
style={{
|
||||
// #3016 disable transition on ios mobile screen
|
||||
transition: isMobileScreen && isIOSMobile ? "none" : undefined,
|
||||
transition: isIOSMobile ? "none" : undefined,
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
|
@@ -52,13 +52,13 @@ const Select = <Value extends number | string>(props: SearchProps<Value>) => {
|
||||
|
||||
const content = (
|
||||
<div
|
||||
className={`px-2 py-2 flex flex-col gap-1 overflow-y-auto overflow-x-hidden`}
|
||||
className={` flex flex-col gap-1 overflow-y-auto overflow-x-hidden`}
|
||||
style={{ maxHeight }}
|
||||
>
|
||||
{options?.map((o) => (
|
||||
<div
|
||||
key={o.value}
|
||||
className={`flex items-center p-3 gap-2 rounded-md hover:bg-select-option-hovered`}
|
||||
className={`flex items-center p-3 gap-2 rounded-action-btn hover:bg-select-option-hovered`}
|
||||
onClick={() => {
|
||||
onSelect?.(o.value);
|
||||
}}
|
||||
@@ -79,13 +79,13 @@ const Select = <Value extends number | string>(props: SearchProps<Value>) => {
|
||||
placement={
|
||||
position?.poi.relativePosition[1] !== Orientation.bottom ? "rb" : "rt"
|
||||
}
|
||||
popoverClassName="border border-select-popover rounded-md shadow-select-popover-shadow w-actions-popover bg-select-popover-panel dark:bg-select-popover-panel-dark"
|
||||
popoverClassName="border border-select-popover rounded-lg shadow-select-popover-shadow w-actions-popover bg-select-popover-panel dark:bg-select-popover-panel-dark"
|
||||
onShow={(e) => {
|
||||
getRelativePosition(contentRef.current!, "");
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={`flex items-center gap-3 py-2 px-3 bg-select rounded-action-btn font-time text-sm-title ${selectClassName}`}
|
||||
className={`flex items-center gap-3 py-2 px-3 bg-select rounded-action-btn font-time text-sm-title ${selectClassName} cursor-pointer`}
|
||||
ref={contentRef}
|
||||
>
|
||||
<div className={`flex items-center gap-2 flex-1`}>
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { useContext, useEffect, useRef } from "react";
|
||||
import { ListContext } from "../List";
|
||||
import { ListContext } from "@/app/components/List";
|
||||
import useResizeObserver from "use-resize-observer";
|
||||
|
||||
interface SlideRangeProps {
|
||||
className?: string;
|
||||
@@ -30,11 +31,15 @@ export default function SlideRange(props: SlideRangeProps) {
|
||||
|
||||
const slideRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { ref, width = 1 } = useResizeObserver<HTMLDivElement>();
|
||||
|
||||
ref(slideRef.current);
|
||||
|
||||
const transformToWidth = (x: number = start) => {
|
||||
const abs = x - start;
|
||||
const maxWidth = (slideRef.current?.clientWidth || 1) - margin * 2;
|
||||
const radio = stroke / maxWidth;
|
||||
return abs / radio;
|
||||
const maxWidth = width - margin * 2;
|
||||
const result = (abs / stroke) * maxWidth;
|
||||
return result;
|
||||
};
|
||||
|
||||
const setProperty = (value?: number) => {
|
||||
@@ -44,37 +49,36 @@ export default function SlideRange(props: SlideRangeProps) {
|
||||
`${initWidth + margin}px`,
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setProperty(value);
|
||||
update?.({ type: "range" });
|
||||
}, []);
|
||||
}, [width]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex flex-col justify-center items-end gap-1 w-[100%] ${className} ${rangeClassName}`}
|
||||
>
|
||||
{!!description && (
|
||||
<div className="text-text-slider-block text-common text-sm">
|
||||
<div className="text-text-slider-block text-common text-sm ">
|
||||
{description}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="flex my-1.5 relative w-[100%] h-1.5 bg-slider rounded-slide"
|
||||
className="flex my-1.5 relative w-[100%] h-1.5 bg-slider rounded-slide cursor-pointer"
|
||||
ref={slideRef}
|
||||
>
|
||||
<div className="absolute top-0 h-[100%] w-[var(--slide-value-size)] pointer-events-none bg-slider-slided-travel rounded-slide">
|
||||
<div className="cursor-pointer absolute marker:top-0 h-[100%] w-[var(--slide-value-size)] bg-slider-slided-travel rounded-slide">
|
||||
|
||||
</div>
|
||||
<div
|
||||
className=" absolute w-[30px] top-[50%] translate-y-[-50%] left-[var(--slide-value-size)] translate-x-[-50%] pointer-events-none h-slide-btn leading-slide-btn text-sm-mobile text-center rounded-slide border border-slider-block bg-slider-block"
|
||||
className="cursor-pointer absolute z-1 w-[30px] top-[50%] translate-y-[-50%] left-[var(--slide-value-size)] translate-x-[-50%] h-slide-btn leading-slide-btn text-sm-mobile text-center rounded-slide border border-slider-block bg-slider-block"
|
||||
// onPointerDown={onPointerDown}
|
||||
>
|
||||
{value}
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
className="w-[100%] h-[100%] opacity-0"
|
||||
className="w-[100%] h-[100%] opacity-0 cursor-pointer"
|
||||
value={value}
|
||||
min={start}
|
||||
max={start + stroke}
|
||||
|
@@ -15,7 +15,7 @@ export default function Switch(props: SwitchProps) {
|
||||
<RadixSwitch.Root
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
className={` flex w-switch h-switch p-0.5 box-content rounded-md ${switchClassName} ${
|
||||
className={` cursor-pointer flex w-switch h-switch p-0.5 box-content rounded-md ${switchClassName} ${
|
||||
value
|
||||
? "bg-switch-checked justify-end"
|
||||
: "bg-switch-unchecked justify-start"
|
||||
|
Reference in New Issue
Block a user