mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
fix: hydration issue and selected model in chat (#568)
- Fixes the Hydration issue on the model selector - Add ability to show the Model
This commit is contained in:
parent
7b0baea0f2
commit
c1670cfd85
3 changed files with 82 additions and 51 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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()}
|
||||
|
|
|
|||
65
apps/web/lib/models.tsx
Normal file
65
apps/web/lib/models.tsx
Normal file
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue