mirror of
https://github.com/coaidev/coai.git
synced 2025-05-30 18:30:32 +09:00
chore: update model market tags and tailwind-merged
This commit is contained in:
parent
a340fd86c8
commit
7f1c8fad99
@ -39,9 +39,18 @@ export type ConversationInstance = {
|
||||
|
||||
export type ConversationMapper = Record<Id, Conversation>;
|
||||
|
||||
export type PlanItem = {
|
||||
id: string;
|
||||
name: string;
|
||||
value: string;
|
||||
icon: string;
|
||||
models: string[];
|
||||
};
|
||||
|
||||
export type Plan = {
|
||||
level: number;
|
||||
price: number;
|
||||
items: PlanItem[];
|
||||
};
|
||||
|
||||
export type SubscriptionUsage = Record<
|
||||
|
@ -302,7 +302,7 @@ input[type="number"] {
|
||||
|
||||
p {
|
||||
margin: auto;
|
||||
color: hsl(var(--text));
|
||||
color: hsl(var(--text-dark));
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { deeptrainApiEndpoint, useDeeptrain } from "@/utils/env.ts";
|
||||
import { ImgHTMLAttributes, useMemo } from "react";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
export interface AvatarProps extends ImgHTMLAttributes<HTMLElement> {
|
||||
username: string;
|
||||
@ -11,7 +12,7 @@ function Avatar({ username, ...props }: AvatarProps) {
|
||||
[username],
|
||||
);
|
||||
|
||||
const color = useMemo(() => {
|
||||
const background = useMemo(() => {
|
||||
const colors = [
|
||||
"bg-red-500",
|
||||
"bg-yellow-500",
|
||||
@ -28,8 +29,8 @@ function Avatar({ username, ...props }: AvatarProps) {
|
||||
return useDeeptrain ? (
|
||||
<img {...props} src={`${deeptrainApiEndpoint}/avatar/${username}`} alt="" />
|
||||
) : (
|
||||
<div {...props} className={`avatar ${color}`}>
|
||||
<p>{code}</p>
|
||||
<div {...props} className={cn("avatar", background)}>
|
||||
<p className={`text-white`}>{code}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import { Toggle } from "./ui/toggle.tsx";
|
||||
import { mobile } from "@/utils/device.ts";
|
||||
import { Button } from "./ui/button.tsx";
|
||||
import { ChatAction } from "@/components/home/assemblies/ChatAction.tsx";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type RichEditorProps = {
|
||||
value: string;
|
||||
@ -104,9 +105,11 @@ function RichEditor({ value, onChange, maxLength }: RichEditorProps) {
|
||||
</div>
|
||||
<div className={`editor-wrapper`}>
|
||||
<div
|
||||
className={`editor-object ${openInput ? "show-editor" : ""} ${
|
||||
openPreview ? "show-preview" : ""
|
||||
}`}
|
||||
className={cn(
|
||||
"editor-object",
|
||||
openInput && "show-editor",
|
||||
openPreview && "show-preview",
|
||||
)}
|
||||
>
|
||||
{openInput && (
|
||||
<Textarea
|
||||
|
@ -27,6 +27,7 @@ import { useSelector } from "react-redux";
|
||||
import { isHighContextModel } from "@/conf.ts";
|
||||
import { selectModel } from "@/store/chat.ts";
|
||||
import { ChatAction } from "@/components/home/assemblies/ChatAction.tsx";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
const MaxFileSize = 1024 * 1024 * 25; // 25MB File Size Limit
|
||||
const MaxPromptSize = 5000; // 5000 Prompt Size Limit (to avoid token overflow)
|
||||
@ -64,7 +65,7 @@ function FileProvider({ value, onChange }: FileProviderProps) {
|
||||
<DialogTrigger asChild>
|
||||
<ChatAction
|
||||
text={t("file.upload")}
|
||||
className={value.length > 0 ? "active" : ""}
|
||||
className={cn(value.length > 0 && "active")}
|
||||
>
|
||||
<Plus className={`h-4 w-4`} />
|
||||
</ChatAction>
|
||||
|
@ -35,7 +35,7 @@ export type PopupFieldProps<T> = {
|
||||
className?: string;
|
||||
classNameInput?: string;
|
||||
classNameLabel?: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type PopupFieldTextProps = PopupFieldProps<string>;
|
||||
export type PopupFieldNumberProps = PopupFieldProps<number>;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMemo } from "react";
|
||||
import { isEmailValid } from "@/utils/form.ts";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
function Required() {
|
||||
return <span className={`text-red-500 mr-0.5`}>*</span>;
|
||||
@ -27,9 +28,10 @@ export function LengthRangeRequired({
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`ml-1 text-red-500 transition-opacity ${
|
||||
onDisplay ? "" : "opacity-0"
|
||||
}`}
|
||||
className={cn(
|
||||
"ml-1 text-red-500 transition-opacity",
|
||||
!onDisplay && "opacity-0",
|
||||
)}
|
||||
>
|
||||
({t("auth.length-range", { min, max })})
|
||||
</span>
|
||||
@ -55,9 +57,10 @@ export function SameRequired({
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`ml-1 text-red-500 transition-opacity ${
|
||||
onDisplay ? "" : "opacity-0"
|
||||
}`}
|
||||
className={cn(
|
||||
"ml-1 text-red-500 transition-opacity",
|
||||
!onDisplay && "opacity-0",
|
||||
)}
|
||||
>
|
||||
({t("auth.same-rule")})
|
||||
</span>
|
||||
@ -78,9 +81,10 @@ export function EmailRequire({ content, hideOnEmpty }: EmailRequireProps) {
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`ml-1 text-red-500 transition-opacity ${
|
||||
onDisplay ? "" : "opacity-0"
|
||||
}`}
|
||||
className={cn(
|
||||
"ml-1 text-red-500 transition-opacity",
|
||||
!onDisplay && "opacity-0",
|
||||
)}
|
||||
>
|
||||
({t("auth.invalid-email")})
|
||||
</span>
|
||||
|
@ -16,6 +16,7 @@ import router from "@/router.tsx";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { mobile } from "@/utils/device.ts";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type MenuItemProps = {
|
||||
title: string;
|
||||
@ -39,7 +40,7 @@ function MenuItem({ title, icon, path }: MenuItemProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`menu-item ${active ? "active" : ""}`} onClick={redirect}>
|
||||
<div className={cn("menu-item", active && "active")} onClick={redirect}>
|
||||
<div className={`menu-item-icon`}>{icon}</div>
|
||||
<div className={`menu-item-title`}>{title}</div>
|
||||
</div>
|
||||
@ -50,7 +51,7 @@ function MenuBar() {
|
||||
const { t } = useTranslation();
|
||||
const open = useSelector(selectMenu);
|
||||
return (
|
||||
<div className={`admin-menu ${open ? "open" : ""}`}>
|
||||
<div className={cn("admin-menu", open && "open")}>
|
||||
<MenuItem title={t("admin.dashboard")} icon={<Gauge />} path={"/"} />
|
||||
<MenuItem title={t("admin.user")} icon={<Users />} path={"/users"} />
|
||||
<MenuItem
|
||||
|
@ -42,6 +42,7 @@ import {
|
||||
} from "@/admin/api/channel.ts";
|
||||
import { toast } from "@/components/ui/use-toast.ts";
|
||||
import { useEffectAsync } from "@/utils/hook.ts";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
const initialState: Channel = {
|
||||
id: -1,
|
||||
@ -484,7 +485,7 @@ function ChannelEditor({ display, id, setEnabled }: ChannelEditorProps) {
|
||||
onSelect={() =>
|
||||
dispatch({ type: "add-group", value: item })
|
||||
}
|
||||
className={`px-2 ${idx > 1 ? "gold-text" : ""}`}
|
||||
className={cn("px-2", idx > 1 && "gold-text")}
|
||||
>
|
||||
{item}
|
||||
</CommandItem>
|
||||
|
@ -36,6 +36,7 @@ import ChatInput from "@/components/home/assemblies/ChatInput.tsx";
|
||||
import ScrollAction from "@/components/home/assemblies/ScrollAction.tsx";
|
||||
import { connectionEvent } from "@/events/connection.ts";
|
||||
import { chatEvent } from "@/events/chat.ts";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type InterfaceProps = {
|
||||
setWorking: (working: boolean) => void;
|
||||
@ -166,7 +167,7 @@ function ChatWrapper() {
|
||||
<div className={`input-wrapper`}>
|
||||
<div className={`chat-box`}>
|
||||
<ChatInput
|
||||
className={align ? "align" : ""}
|
||||
className={cn(align && "align")}
|
||||
target={target}
|
||||
value={input}
|
||||
onValueChange={setInput}
|
||||
|
@ -14,6 +14,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { ConversationInstance } from "@/api/types.ts";
|
||||
import { useState } from "react";
|
||||
import { closeMarket } from "@/store/chat.ts";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type ConversationSegmentProps = {
|
||||
conversation: ConversationInstance;
|
||||
@ -35,7 +36,7 @@ function ConversationSegment({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`conversation ${current === conversation.id ? "active" : ""}`}
|
||||
className={cn("conversation", current === conversation.id && "active")}
|
||||
onClick={async (e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
if (
|
||||
|
@ -39,12 +39,23 @@ import {
|
||||
DropResult,
|
||||
} from "react-beautiful-dnd";
|
||||
import { savePreferenceModels } from "@/utils/storage.ts";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type SearchBarProps = {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
function getTags(model: Model): string[] {
|
||||
let raw = model.tag || [];
|
||||
|
||||
if (model.free && !raw.includes("free")) raw = ["free", ...raw];
|
||||
if (model.high_context && !raw.includes("high-context"))
|
||||
raw = ["high-context", ...raw];
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
function SearchBar({ value, onChange }: SearchBarProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -59,7 +70,7 @@ function SearchBar({ value, onChange }: SearchBarProps) {
|
||||
/>
|
||||
<X
|
||||
size={16}
|
||||
className={`clear-icon ${value.length > 0 ? "active" : ""}`}
|
||||
className={cn("clear-icon", value.length > 0 && "active")}
|
||||
onClick={() => onChange("")}
|
||||
/>
|
||||
</div>
|
||||
@ -107,6 +118,8 @@ function ModelItem({
|
||||
return isUrl(model.avatar) ? model.avatar : `/icons/${model.avatar}`;
|
||||
}, [model]);
|
||||
|
||||
const tags = useMemo((): string[] => getTags(model), [model]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`model-item ${className}`}
|
||||
@ -135,19 +148,18 @@ function ModelItem({
|
||||
<GripVertical className={`grip-icon h-4 w-4 translate-x-[-1rem]`} />
|
||||
<img className={`model-avatar`} src={avatar} alt={model.name} />
|
||||
<div className={`model-info`}>
|
||||
<p className={`model-name ${pro ? "pro" : ""}`}>{model.name}</p>
|
||||
<p className={cn("model-name", pro && "pro")}>{model.name}</p>
|
||||
{model.description && (
|
||||
<p className={`model-description`}>{model.description}</p>
|
||||
)}
|
||||
<div className={`model-tag`}>
|
||||
{model.tag &&
|
||||
model.tag.map((tag, index) => {
|
||||
return (
|
||||
<span className={`tag-item`} key={index}>
|
||||
{t(`tag.${tag}`)}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
{tags.map((tag, index) => {
|
||||
return (
|
||||
<span className={`tag-item`} key={index}>
|
||||
{t(`tag.${tag}`)}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`grow`} />
|
||||
@ -192,8 +204,10 @@ function MarketPlace({ search }: MarketPlaceProps) {
|
||||
const raw = splitList(search.toLowerCase(), [" ", ",", ";", "-"]);
|
||||
return supportModels.filter((model) => {
|
||||
const name = model.name.toLowerCase();
|
||||
const tag = (model.tag || []).join(" ").toLowerCase();
|
||||
const tag_translated = (model.tag || [])
|
||||
|
||||
const tag = getTags(model);
|
||||
const tag_name = tag.join(" ").toLowerCase();
|
||||
const tag_translated_name = tag
|
||||
.map((item) => t(`tag.${item}`))
|
||||
.join(" ")
|
||||
.toLowerCase();
|
||||
@ -202,8 +216,8 @@ function MarketPlace({ search }: MarketPlaceProps) {
|
||||
return raw.every(
|
||||
(item) =>
|
||||
name.includes(item) ||
|
||||
tag.includes(item) ||
|
||||
tag_translated.includes(item) ||
|
||||
tag_name.includes(item) ||
|
||||
tag_translated_name.includes(item) ||
|
||||
id.includes(item),
|
||||
);
|
||||
});
|
||||
@ -251,7 +265,7 @@ function MarketPlace({ search }: MarketPlaceProps) {
|
||||
{(provided) => (
|
||||
<ModelItem
|
||||
model={model}
|
||||
className={`${select === model.id ? "active" : ""}`}
|
||||
className={cn(select === model.id && "active")}
|
||||
forwardRef={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
|
@ -43,6 +43,7 @@ import MenuBar from "@/components/app/MenuBar.tsx";
|
||||
import { Separator } from "@/components/ui/separator.tsx";
|
||||
import { goAuth } from "@/utils/app.ts";
|
||||
import Avatar from "@/components/Avatar.tsx";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type Operation = {
|
||||
target: ConversationInstance | null;
|
||||
@ -347,7 +348,7 @@ function SideBar() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={`sidebar ${open ? "open" : ""}`}>
|
||||
<div className={cn("sidebar", open && "open")}>
|
||||
{auth ? (
|
||||
<div className={`sidebar-content`}>
|
||||
<SidebarAction setOperateConversation={setOperateConversation} />
|
||||
|
@ -4,6 +4,7 @@ import { useDispatch, useSelector } from "react-redux";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { openDialog } from "@/store/settings.ts";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type ChatActionProps = {
|
||||
className?: string;
|
||||
@ -53,11 +54,11 @@ export function WebAction({ visible }: WebActionProps) {
|
||||
return (
|
||||
visible && (
|
||||
<ChatAction
|
||||
className={web ? "active" : ""}
|
||||
className={cn(web && "active")}
|
||||
text={t("chat.web")}
|
||||
onClick={() => dispatch(toggleWeb())}
|
||||
>
|
||||
<Globe className={`h-4 w-4 web ${web ? "enable" : ""}`} />
|
||||
<Globe className={cn("h-4 w-4 web", web && "enable")} />
|
||||
</ChatAction>
|
||||
)
|
||||
);
|
||||
|
@ -41,6 +41,7 @@ import { selectAuthenticated } from "@/store/auth.ts";
|
||||
import { ToastAction } from "@/components/ui/toast.tsx";
|
||||
import { deeptrainEndpoint, docsEndpoint, useDeeptrain } from "@/utils/env.ts";
|
||||
import { useRedeem } from "@/api/redeem.ts";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type AmountComponentProps = {
|
||||
amount: number;
|
||||
@ -57,7 +58,7 @@ function AmountComponent({
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className={`amount ${active ? "active" : ""}`} onClick={onClick}>
|
||||
<div className={cn("amount", active && "active")} onClick={onClick}>
|
||||
{!other ? (
|
||||
<>
|
||||
<div className={`amount-title`}>
|
||||
|
@ -20,6 +20,7 @@ import { Label } from "@/components/ui/label.tsx";
|
||||
import { rest_api, tokenField, ws_api } from "@/conf.ts";
|
||||
import { getMemory } from "@/utils/memory.ts";
|
||||
import { Progress } from "@/components/ui/progress.tsx";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type ProgressProps = {
|
||||
current: number;
|
||||
@ -157,7 +158,7 @@ function ArticleContent() {
|
||||
onPressedChange={(state: boolean) => dispatch(setWeb(state))}
|
||||
variant={`outline`}
|
||||
>
|
||||
<Globe className={`h-4 w-4 web ${web ? "enable" : ""}`} />
|
||||
<Globe className={cn("h-4 w-4 web", web && "enable")} />
|
||||
</Toggle>
|
||||
<Label className={`ml-2.5 whitespace-nowrap`}>
|
||||
{t("article.web-checkbox")}
|
||||
|
@ -31,6 +31,7 @@ import { Button } from "@/components/ui/button.tsx";
|
||||
import { updateMarket } from "@/admin/api/market.ts";
|
||||
import { Combobox } from "@/components/ui/combo-box.tsx";
|
||||
import { channelModels } from "@/admin/channel.ts";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type Model = RawModel & {
|
||||
seed?: string;
|
||||
@ -275,7 +276,7 @@ function MarketImage({ image, idx, dispatch }: MarketImageProps) {
|
||||
variant={`outline`}
|
||||
size={`sm`}
|
||||
pressed={source === image}
|
||||
className={`market-image ${source === image ? "active" : ""}`}
|
||||
className={cn("market-image", source === image ? "active" : "")}
|
||||
onPressedChange={(state) => {
|
||||
if (!state) return;
|
||||
if (customized) {
|
||||
@ -374,7 +375,7 @@ function Market() {
|
||||
);
|
||||
}, [form]);
|
||||
|
||||
const doCheck = (index: number) => {
|
||||
const checked = (index: number) => {
|
||||
return useMemo((): boolean => {
|
||||
const model = form[index];
|
||||
|
||||
@ -429,9 +430,10 @@ function Market() {
|
||||
>
|
||||
{(provided) => (
|
||||
<div
|
||||
className={`market-item ${
|
||||
doCheck(index) ? "" : "error"
|
||||
}`}
|
||||
className={cn(
|
||||
"market-item",
|
||||
!checked(index) && "error",
|
||||
)}
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
|
@ -10,12 +10,13 @@ import UserTable from "@/components/admin/UserTable.tsx";
|
||||
import { mobile } from "@/utils/device.ts";
|
||||
import Tips from "@/components/Tips.tsx";
|
||||
import RedeemTable from "@/components/admin/RedeemTable.tsx";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
function Users() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className={`user-interface ${mobile ? "mobile" : ""}`}>
|
||||
<div className={cn("user-interface", mobile && "mobile")}>
|
||||
<Card className={`admin-card`}>
|
||||
<CardHeader className={`select-none`}>
|
||||
<CardTitle>{t("admin.user")}</CardTitle>
|
||||
|
Loading…
Reference in New Issue
Block a user