diff options
| author | MaheshtheDev <[email protected]> | 2025-11-09 07:29:01 +0000 |
|---|---|---|
| committer | MaheshtheDev <[email protected]> | 2025-11-09 07:29:01 +0000 |
| commit | c1670cfd8540d898d08c12d3cba7fbe354ebbc7c (patch) | |
| tree | d6bb31d8973914e75440f53fb870bdf1dad77504 /apps | |
| parent | add support for responses api in openai typescript sdk (#549) (diff) | |
| download | supermemory-c1670cfd8540d898d08c12d3cba7fbe354ebbc7c.tar.xz supermemory-c1670cfd8540d898d08c12d3cba7fbe354ebbc7c.zip | |
fix: hydration issue and selected model in chat (#568)11-08-fix_hydration_issue_and_selected_model_in_chat
- Fixes the Hydration issue on the model selector
- Add ability to show the Model
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/web/components/model-selector.tsx | 44 | ||||
| -rw-r--r-- | apps/web/components/views/chat/chat-messages.tsx | 24 | ||||
| -rw-r--r-- | apps/web/lib/models.tsx | 65 |
3 files changed, 82 insertions, 51 deletions
diff --git a/apps/web/components/model-selector.tsx b/apps/web/components/model-selector.tsx index d0e29974..f71e7d58 100644 --- a/apps/web/components/model-selector.tsx +++ b/apps/web/components/model-selector.tsx @@ -4,26 +4,7 @@ import { useState } from "react" import { Button } from "@repo/ui/components/button" import { ChevronDown } from "lucide-react" import { motion } from "motion/react" - -const models = [ - { - id: "gpt-5", - name: "GPT 5", - description: "OpenAI's latest model", - }, - { - id: "claude-sonnet-4.5", - name: "Claude Sonnet 4.5", - description: "Anthropic's advanced model", - }, - { - id: "gemini-2.5-pro", - name: "Gemini 2.5 Pro", - description: "Google's most capable model", - }, -] as const - -type ModelId = (typeof models)[number]["id"] +import { models, type ModelId, ModelIcon } from "@/lib/models" interface ModelSelectorProps { selectedModel?: ModelId @@ -54,28 +35,7 @@ export function ModelSelector({ onClick={() => !disabled && setIsOpen(!isOpen)} disabled={disabled} > - <svg - xmlns="http://www.w3.org/2000/svg" - width="24" - height="24" - fill="none" - viewBox="0 0 24 24" - > - <g - stroke="currentColor" - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth="1.5" - clipPath="url(#clip0_4418_9868)" - > - <path d="m12.92 2.26 6.51 3.51c.76.41.76 1.58 0 1.99l-6.51 3.51c-.58.31-1.26.31-1.84 0L4.57 7.76c-.76-.41-.76-1.58 0-1.99l6.51-3.51c.58-.31 1.26-.31 1.84 0M3.61 10.13l6.05 3.03c.75.38 1.23 1.15 1.23 1.99v5.72c0 .83-.87 1.36-1.61.99l-6.05-3.03A2.24 2.24 0 0 1 2 16.84v-5.72c0-.83.87-1.36 1.61-.99M20.39 10.13l-6.05 3.03c-.75.38-1.23 1.15-1.23 1.99v5.72c0 .83.87 1.36 1.61.99l6.05-3.03c.75-.38 1.23-1.15 1.23-1.99v-5.72c0-.83-.87-1.36-1.61-.99"></path> - </g> - <defs> - <clipPath id="clip0_4418_9868"> - <path fill="#fff" d="M0 0h24v24H0z"></path> - </clipPath> - </defs> - </svg> + <ModelIcon width={24} height={24} /> <span className="text-xs font-medium max-w-32 truncate"> {currentModel.name} </span> diff --git a/apps/web/components/views/chat/chat-messages.tsx b/apps/web/components/views/chat/chat-messages.tsx index 22bc8a2a..ff4eca34 100644 --- a/apps/web/components/views/chat/chat-messages.tsx +++ b/apps/web/components/views/chat/chat-messages.tsx @@ -19,6 +19,7 @@ import { Streamdown } from "streamdown" import { TextShimmer } from "@/components/text-shimmer" import { usePersistentChat, useProject } from "@/stores" import { useGraphHighlights } from "@/stores/highlights" +import { modelNames, ModelIcon } from "@/lib/models" import { Spinner } from "../../spinner" interface MemoryResult { @@ -242,14 +243,7 @@ export function ChatMessages() { const [input, setInput] = useState("") const [selectedModel, setSelectedModel] = useState< "gpt-5" | "claude-sonnet-4.5" | "gemini-2.5-pro" - >( - (sessionStorage.getItem(storageKey) as - | "gpt-5" - | "claude-sonnet-4.5" - | "gemini-2.5-pro") || - "gemini-2.5-pro" || - "gemini-2.5-pro", - ) + >("gemini-2.5-pro") const activeChatIdRef = useRef<string | null>(null) const shouldGenerateTitleRef = useRef<boolean>(false) const hasRunInitialMessageRef = useRef<boolean>(false) @@ -293,6 +287,7 @@ export function ChatMessages() { }, [currentChatId, id]) useEffect(() => { + if (typeof window === "undefined") return if (currentChatId) { const savedModel = sessionStorage.getItem(storageKey) as | "gpt-5" @@ -309,6 +304,7 @@ export function ChatMessages() { }, [currentChatId, storageKey]) useEffect(() => { + if (typeof window === "undefined") return if (currentChatId && !hasRunInitialMessageRef.current) { // Check if there's an initial message from the home page in sessionStorage const storageKey = `chat-initial-${currentChatId}` @@ -637,7 +633,17 @@ export function ChatMessages() { className="w-full text-foreground placeholder:text-muted-foreground rounded-md outline-none resize-none text-base leading-relaxed px-3 py-3 bg-transparent" rows={3} /> - <div className="absolute bottom-2 right-2"> + <div className="absolute bottom-2 right-2 flex items-center gap-4"> + <div className="flex items-center gap-1.5"> + <ModelIcon + width={16} + height={16} + className="text-muted-foreground" + /> + <span className="text-xs text-muted-foreground"> + {modelNames[selectedModel]} + </span> + </div> <Button type="submit" disabled={!input.trim()} diff --git a/apps/web/lib/models.tsx b/apps/web/lib/models.tsx new file mode 100644 index 00000000..06082d5c --- /dev/null +++ b/apps/web/lib/models.tsx @@ -0,0 +1,65 @@ +export const models = [ + { + id: "gpt-5", + name: "GPT 5", + description: "OpenAI's latest model", + }, + { + id: "claude-sonnet-4.5", + name: "Claude Sonnet 4.5", + description: "Anthropic's advanced model", + }, + { + id: "gemini-2.5-pro", + name: "Gemini 2.5 Pro", + description: "Google's most capable model", + }, +] as const + +export type ModelId = (typeof models)[number]["id"] + +export const modelNames: Record<ModelId, string> = { + "gpt-5": "GPT 5", + "claude-sonnet-4.5": "Claude Sonnet 4.5", + "gemini-2.5-pro": "Gemini 2.5 Pro", +} + +interface ModelIconProps { + width?: number + height?: number + className?: string +} + +export function ModelIcon({ + width = 24, + height = 24, + className, +}: ModelIconProps) { + return ( + <svg + xmlns="http://www.w3.org/2000/svg" + width={width} + height={height} + fill="none" + viewBox="0 0 24 24" + className={className} + aria-label="Model icon" + > + <title>Model icon</title> + <g + stroke="currentColor" + strokeLinecap="round" + strokeLinejoin="round" + strokeWidth="1.5" + clipPath="url(#clip0_4418_9868)" + > + <path d="m12.92 2.26 6.51 3.51c.76.41.76 1.58 0 1.99l-6.51 3.51c-.58.31-1.26.31-1.84 0L4.57 7.76c-.76-.41-.76-1.58 0-1.99l6.51-3.51c.58-.31 1.26-.31 1.84 0M3.61 10.13l6.05 3.03c.75.38 1.23 1.15 1.23 1.99v5.72c0 .83-.87 1.36-1.61.99l-6.05-3.03A2.24 2.24 0 0 1 2 16.84v-5.72c0-.83.87-1.36 1.61-.99M20.39 10.13l-6.05 3.03c-.75.38-1.23 1.15-1.23 1.99v5.72c0 .83.87 1.36 1.61.99l6.05-3.03c.75-.38 1.23-1.15 1.23-1.99v-5.72c0-.83.87-1.36-1.61-.99" /> + </g> + <defs> + <clipPath id="clip0_4418_9868"> + <path fill="#fff" d="M0 0h24v24H0z" /> + </clipPath> + </defs> + </svg> + ) +} |