mirror of
https://github.com/coaidev/coai.git
synced 2025-05-24 07:20:15 +09:00
fix: fix enter send message on macos (merge #151 from yongman/fix-enter-macos)
This commit is contained in:
commit
b9690b4aa2
@ -74,7 +74,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog.tsx";
|
} from "@/components/ui/dialog.tsx";
|
||||||
import { getUniqueList, parseNumber } from "@/utils/base.ts";
|
import { getUniqueList, isEnter, parseNumber } from "@/utils/base.ts";
|
||||||
import { defaultChannelModels } from "@/admin/channel.ts";
|
import { defaultChannelModels } from "@/admin/channel.ts";
|
||||||
import { getPricing } from "@/admin/datasets/charge.ts";
|
import { getPricing } from "@/admin/datasets/charge.ts";
|
||||||
import { useAllModels } from "@/admin/hook.tsx";
|
import { useAllModels } from "@/admin/hook.tsx";
|
||||||
@ -102,9 +102,9 @@ function reducer(state: ChargeProps, action: any): ChargeProps {
|
|||||||
if (action.payload.trim().length === 0) return state;
|
if (action.payload.trim().length === 0) return state;
|
||||||
return state.models.includes(action.payload)
|
return state.models.includes(action.payload)
|
||||||
? {
|
? {
|
||||||
...state,
|
...state,
|
||||||
models: state.models.filter((model) => model !== action.payload),
|
models: state.models.filter((model) => model !== action.payload),
|
||||||
}
|
}
|
||||||
: { ...state, models: [...state.models, action.payload] };
|
: { ...state, models: [...state.models, action.payload] };
|
||||||
case "remove-model":
|
case "remove-model":
|
||||||
return {
|
return {
|
||||||
@ -469,7 +469,7 @@ function ChargeEditor({
|
|||||||
onChange={(e) => setModel(e.target.value)}
|
onChange={(e) => setModel(e.target.value)}
|
||||||
placeholder={t("admin.channels.model")}
|
placeholder={t("admin.channels.model")}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (isEnter(e)) {
|
||||||
dispatch({ type: "add-model", payload: model });
|
dispatch({ type: "add-model", payload: model });
|
||||||
setModel("");
|
setModel("");
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ import {
|
|||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { Input } from "@/components/ui/input.tsx";
|
import { Input } from "@/components/ui/input.tsx";
|
||||||
import PopupDialog, { popupTypes } from "@/components/PopupDialog.tsx";
|
import PopupDialog, { popupTypes } from "@/components/PopupDialog.tsx";
|
||||||
import { getNumber, parseNumber } from "@/utils/base.ts";
|
import { getNumber, isEnter, parseNumber } from "@/utils/base.ts";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { selectUsername } from "@/store/auth.ts";
|
import { selectUsername } from "@/store/auth.ts";
|
||||||
import { PaginationAction } from "@/components/ui/pagination.tsx";
|
import { PaginationAction } from "@/components/ui/pagination.tsx";
|
||||||
@ -378,7 +378,7 @@ function UserTable() {
|
|||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => setSearch(e.target.value)}
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
onKeyDown={async (e) => {
|
onKeyDown={async (e) => {
|
||||||
if (e.key === "Enter") await update();
|
if (isEnter(e)) await update();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button size={`icon`} className={`flex-shrink-0 ml-2`} onClick={update}>
|
<Button size={`icon`} className={`flex-shrink-0 ml-2`} onClick={update}>
|
||||||
|
@ -50,6 +50,7 @@ import Paragraph, {
|
|||||||
} from "@/components/Paragraph.tsx";
|
} from "@/components/Paragraph.tsx";
|
||||||
import { MultiCombobox } from "@/components/ui/multi-combobox.tsx";
|
import { MultiCombobox } from "@/components/ui/multi-combobox.tsx";
|
||||||
import { useChannelModels } from "@/admin/hook.tsx";
|
import { useChannelModels } from "@/admin/hook.tsx";
|
||||||
|
import { isEnter } from "@/utils/base.ts";
|
||||||
|
|
||||||
type CustomActionProps = {
|
type CustomActionProps = {
|
||||||
onPost: (model: string) => void;
|
onPost: (model: string) => void;
|
||||||
@ -73,7 +74,7 @@ function CustomAction({ onPost }: CustomActionProps) {
|
|||||||
className={`rounded-r-none`}
|
className={`rounded-r-none`}
|
||||||
onChange={(e) => setModel(e.target.value)}
|
onChange={(e) => setModel(e.target.value)}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") post();
|
if (isEnter(e)) post();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button className={`rounded-l-none`} onClick={post}>
|
<Button className={`rounded-l-none`} onClick={post}>
|
||||||
|
@ -6,6 +6,7 @@ import { useSelector } from "react-redux";
|
|||||||
import { senderSelector } from "@/store/settings.ts";
|
import { senderSelector } from "@/store/settings.ts";
|
||||||
import { blobEvent } from "@/events/blob.ts";
|
import { blobEvent } from "@/events/blob.ts";
|
||||||
import { cn } from "@/components/ui/lib/utils.ts";
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
|
import { isEnter } from "@/utils/base.ts";
|
||||||
|
|
||||||
type ChatInputProps = {
|
type ChatInputProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -41,7 +42,7 @@ function ChatInput({
|
|||||||
}}
|
}}
|
||||||
placeholder={sender ? t("chat.placeholder-enter") : t("chat.placeholder")}
|
placeholder={sender ? t("chat.placeholder-enter") : t("chat.placeholder")}
|
||||||
onKeyDown={async (e) => {
|
onKeyDown={async (e) => {
|
||||||
if (e.key === "Enter") {
|
if (isEnter(e)) {
|
||||||
if (sender) {
|
if (sender) {
|
||||||
// on Enter, clear the input
|
// on Enter, clear the input
|
||||||
// on Ctrl + Enter or Shift + Enter, keep the input
|
// on Ctrl + Enter or Shift + Enter, keep the input
|
||||||
|
@ -19,7 +19,7 @@ import Require, { LengthRangeRequired } from "@/components/Require.tsx";
|
|||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import { formReducer, isTextInRange } from "@/utils/form.ts";
|
import { formReducer, isTextInRange } from "@/utils/form.ts";
|
||||||
import { doLogin, LoginForm } from "@/api/auth.ts";
|
import { doLogin, LoginForm } from "@/api/auth.ts";
|
||||||
import { getErrorMessage } from "@/utils/base.ts";
|
import { getErrorMessage, isEnter } from "@/utils/base.ts";
|
||||||
|
|
||||||
function DeepAuth() {
|
function DeepAuth() {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@ -146,7 +146,7 @@ function Login() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// listen to enter key and auto submit
|
// listen to enter key and auto submit
|
||||||
const listener = async (e: KeyboardEvent) => {
|
const listener = async (e: KeyboardEvent) => {
|
||||||
if (e.key === "Enter") await onSubmit();
|
if (isEnter(e)) await onSubmit();
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener("keydown", listener);
|
document.addEventListener("keydown", listener);
|
||||||
|
@ -13,6 +13,7 @@ import { handleGenerationData } from "@/utils/processor.ts";
|
|||||||
import { selectModel } from "@/store/chat.ts";
|
import { selectModel } from "@/store/chat.ts";
|
||||||
import ModelFinder from "@/components/home/ModelFinder.tsx";
|
import ModelFinder from "@/components/home/ModelFinder.tsx";
|
||||||
import { appLogo } from "@/conf/env.ts";
|
import { appLogo } from "@/conf/env.ts";
|
||||||
|
import { isEnter } from "@/utils/base.ts";
|
||||||
|
|
||||||
type WrapperProps = {
|
type WrapperProps = {
|
||||||
onSend?: (value: string, model: string) => boolean;
|
onSend?: (value: string, model: string) => boolean;
|
||||||
@ -73,9 +74,9 @@ function Wrapper({ onSend }: WrapperProps) {
|
|||||||
const target = ref.current as HTMLInputElement | null;
|
const target = ref.current as HTMLInputElement | null;
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
target.focus();
|
target.focus();
|
||||||
target.removeEventListener("keydown", () => {});
|
target.removeEventListener("keydown", () => { });
|
||||||
target.addEventListener("keydown", (e) => {
|
target.addEventListener("keydown", (e) => {
|
||||||
if (e.key === "Enter") {
|
if (isEnter(e)) {
|
||||||
// cannot use model here, because model is not updated
|
// cannot use model here, because model is not updated
|
||||||
handleSend(modelRef.current);
|
handleSend(modelRef.current);
|
||||||
}
|
}
|
||||||
@ -85,7 +86,7 @@ function Wrapper({ onSend }: WrapperProps) {
|
|||||||
ref.current &&
|
ref.current &&
|
||||||
(ref.current as HTMLInputElement).removeEventListener(
|
(ref.current as HTMLInputElement).removeEventListener(
|
||||||
"keydown",
|
"keydown",
|
||||||
() => {},
|
() => { },
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}, [ref]);
|
}, [ref]);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
export function insert<T>(arr: T[], idx: number, value: T): T[] {
|
export function insert<T>(arr: T[], idx: number, value: T): T[] {
|
||||||
return [...arr.slice(0, idx), value, ...arr.slice(idx)];
|
return [...arr.slice(0, idx), value, ...arr.slice(idx)];
|
||||||
}
|
}
|
||||||
@ -92,6 +94,10 @@ export function isUrl(value: string): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isEnter<T extends HTMLElement>(e: React.KeyboardEvent<T> | KeyboardEvent): boolean {
|
||||||
|
return e.key === "Enter" && e.keyCode != 229;
|
||||||
|
}
|
||||||
|
|
||||||
export function resetJsArray<T>(arr: T[], target: T[]): T[] {
|
export function resetJsArray<T>(arr: T[], target: T[]): T[] {
|
||||||
/**
|
/**
|
||||||
* this function is used to reset an array to another array without changing the *pointer
|
* this function is used to reset an array to another array without changing the *pointer
|
||||||
|
Loading…
Reference in New Issue
Block a user