This commit is contained in:
Krzysztof Czerwinski
2026-01-19 16:49:24 +09:00
parent ccf3f5ae32
commit 923f6fc2b9
4 changed files with 60 additions and 23 deletions

View File

@@ -9,7 +9,7 @@ type LlmModelSchema = RJSFSchema & {
llm_model_metadata?: LlmModelMetadataMap;
};
export const LlmModelField = (props: FieldProps) => {
export function LlmModelField(props: FieldProps) {
const { schema, formData, onChange, disabled, readonly, fieldPathId } = props;
const metadata = useMemo(() => {
@@ -53,4 +53,4 @@ export const LlmModelField = (props: FieldProps) => {
disabled={disabled || readonly}
/>
);
};
}

View File

@@ -38,7 +38,7 @@ export function LlmIcon({ value, size = 20 }: Props) {
if (src) {
return (
<div
className="flex h-5 w-5 items-center justify-center overflow-hidden rounded-xsmall"
className="flex items-center justify-center overflow-hidden rounded-xsmall"
style={{ width: size, height: size }}
>
<Image
@@ -55,7 +55,7 @@ export function LlmIcon({ value, size = 20 }: Props) {
const fallback = value?.trim().slice(0, 1).toUpperCase() || "?";
return (
<div
className="flex h-5 w-5 items-center justify-center rounded-xsmall bg-zinc-100"
className="flex items-center justify-center rounded-xsmall bg-zinc-100"
style={{ width: size, height: size }}
>
<Text variant="small" className="text-zinc-500">

View File

@@ -1,12 +1,8 @@
"use client";
import { useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { CaretDownIcon } from "@phosphor-icons/react";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/__legacy__/ui/popover";
import { Popover, PopoverContent, PopoverTrigger } from "./Popover";
import { Text } from "@/components/atoms/Text/Text";
import { cn } from "@/lib/utils";
import {
@@ -44,13 +40,14 @@ export function LlmModelPicker({
const [activeCreator, setActiveCreator] = useState<string | null>(null);
const [activeTitle, setActiveTitle] = useState<string | null>(null);
const creators = useMemo(() => {
const grouped = groupByCreator(models);
return Array.from(grouped.keys()).sort((a, b) => a.localeCompare(b));
}, [models]);
const modelsByCreator = useMemo(() => groupByCreator(models), [models]);
const creators = useMemo(() => {
return Array.from(modelsByCreator.keys()).sort((a, b) =>
a.localeCompare(b),
);
}, [modelsByCreator]);
const creatorIconValues = useMemo(() => {
const map = new Map<string, string>();
for (const [creator, entries] of modelsByCreator.entries()) {
@@ -73,10 +70,14 @@ export function LlmModelPicker({
}, [open, selectedModel, creators]);
const currentCreator = activeCreator ?? creators[0] ?? null;
const currentModels = currentCreator
? (modelsByCreator.get(currentCreator) ?? [])
: [];
const currentCreatorIcon = currentModels[0]?.creator ?? currentCreator;
const currentModels = useMemo(() => {
return currentCreator ? (modelsByCreator.get(currentCreator) ?? []) : [];
}, [currentCreator, modelsByCreator]);
const currentCreatorIcon = useMemo(() => {
return currentModels[0]?.creator ?? currentCreator;
}, [currentModels, currentCreator]);
const modelsByTitle = useMemo(
() => groupByTitle(currentModels),
@@ -103,10 +104,13 @@ export function LlmModelPicker({
return modelsByTitle.get(activeTitle) ?? [];
}, [activeTitle, modelsByTitle]);
const handleSelectModel = (modelName: string) => {
onSelect(modelName);
setOpen(false);
};
const handleSelectModel = useCallback(
(modelName: string) => {
onSelect(modelName);
setOpen(false);
},
[onSelect],
);
const triggerModel = selectedModel ?? recommendedModel ?? models[0];
const triggerTitle = triggerModel

View File

@@ -0,0 +1,33 @@
"use client";
import * as PopoverPrimitive from "@radix-ui/react-popover";
import * as React from "react";
import { cn } from "@/lib/utils";
const Popover = PopoverPrimitive.Root;
const PopoverTrigger = PopoverPrimitive.Trigger;
const PopoverAnchor = PopoverPrimitive.Anchor;
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-lg border border-zinc-200 bg-white p-4 text-zinc-900 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
</PopoverPrimitive.Portal>
));
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };