mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-09-05 23:30:31 +08:00
feat: chat panel UE done
This commit is contained in:
118
app/components/ActionsBar/index.tsx
Normal file
118
app/components/ActionsBar/index.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import { isValidElement } from "react";
|
||||
|
||||
type IconMap = {
|
||||
active?: JSX.Element;
|
||||
inactive?: JSX.Element;
|
||||
mobileActive?: JSX.Element;
|
||||
mobileInactive?: JSX.Element;
|
||||
};
|
||||
interface Action {
|
||||
id: string;
|
||||
title?: string;
|
||||
icons: JSX.Element | IconMap;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
type Groups = {
|
||||
normal: string[][];
|
||||
mobile: string[][];
|
||||
};
|
||||
|
||||
export interface ActionsBarProps {
|
||||
actionsShema: Action[];
|
||||
onSelect?: (id: string) => void;
|
||||
selected?: string;
|
||||
groups: string[][] | Groups;
|
||||
className?: string;
|
||||
inMobile?: boolean;
|
||||
}
|
||||
|
||||
export default function ActionsBar(props: ActionsBarProps) {
|
||||
const { actionsShema, onSelect, selected, groups, className, inMobile } =
|
||||
props;
|
||||
|
||||
const handlerClick =
|
||||
(action: Action) => (e: { preventDefault: () => void }) => {
|
||||
e.preventDefault();
|
||||
if (action.onClick) {
|
||||
action.onClick();
|
||||
}
|
||||
if (selected !== action.id) {
|
||||
onSelect?.(action.id);
|
||||
}
|
||||
};
|
||||
|
||||
const internalGroup = Array.isArray(groups)
|
||||
? groups
|
||||
: inMobile
|
||||
? groups.mobile
|
||||
: groups.normal;
|
||||
|
||||
const content = internalGroup.reduce((res, group, ind, arr) => {
|
||||
res.push(
|
||||
...group.map((i) => {
|
||||
const action = actionsShema.find((a) => a.id === i);
|
||||
if (!action) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const { icons } = action;
|
||||
let activeIcon, inactiveIcon, mobileActiveIcon, mobileInactiveIcon;
|
||||
|
||||
if (isValidElement(icons)) {
|
||||
activeIcon = icons;
|
||||
inactiveIcon = icons;
|
||||
mobileActiveIcon = icons;
|
||||
mobileInactiveIcon = icons;
|
||||
} else {
|
||||
activeIcon = (icons as IconMap).active;
|
||||
inactiveIcon = (icons as IconMap).inactive;
|
||||
mobileActiveIcon = (icons as IconMap).mobileActive;
|
||||
mobileInactiveIcon = (icons as IconMap).mobileInactive;
|
||||
}
|
||||
|
||||
if (inMobile) {
|
||||
return (
|
||||
<div
|
||||
key={action.id}
|
||||
className={` shrink-1 grow-0 basis-[${
|
||||
(100 - 1) / arr.length
|
||||
}%] flex flex-col items-center justify-center gap-0.5
|
||||
${
|
||||
selected === action.id
|
||||
? "text-blue-700"
|
||||
: "text-gray-400"
|
||||
}
|
||||
`}
|
||||
onClick={handlerClick(action)}
|
||||
>
|
||||
{selected === action.id ? mobileActiveIcon : mobileInactiveIcon}
|
||||
<div className=" leading-3 text-sm-mobile-tab h-3 font-common w-[100%]">
|
||||
{action.title || " "}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={action.id}
|
||||
className={`p-3 ${
|
||||
selected === action.id ? "bg-blue-900" : "bg-transparent"
|
||||
} rounded-md items-center ${action.className}`}
|
||||
onClick={handlerClick(action)}
|
||||
>
|
||||
{selected === action.id ? activeIcon : inactiveIcon}
|
||||
</div>
|
||||
);
|
||||
}),
|
||||
);
|
||||
if (ind < arr.length - 1) {
|
||||
res.push(<div key={String(ind)} className=" flex-1"></div>);
|
||||
}
|
||||
return res;
|
||||
}, [] as JSX.Element[]);
|
||||
|
||||
return <div className={`flex items-center ${className} `}>{content}</div>;
|
||||
}
|
Reference in New Issue
Block a user