feat(AI): thinking toggle as NOMAD Switch + info tooltip
Address review feedback on the per-model thinking control:
- Use the shared Switch component (matches AI Assistant settings) instead
of a raw checkbox.
- Label "Thinking:" with a colon to match the adjacent "Model:" label.
- Add an InfoTooltip explaining what thinking does and where the default
lives. Extend InfoTooltip with optional `position` ('top'|'bottom') and
`align` ('center'|'right') so it opens downward and expands leftward from
the right-edge header slot instead of being clipped/crushed against the
viewport edge. Defaults preserve existing (benchmark page) behavior.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d64cadafc2
commit
25fcf55179
|
|
@ -4,9 +4,21 @@ import { useState } from 'react'
|
|||
interface InfoTooltipProps {
|
||||
text: string
|
||||
className?: string
|
||||
// Which side of the icon the tooltip pops toward. Defaults to 'top' (existing behavior);
|
||||
// use 'bottom' when the icon sits near the top of the viewport so it isn't clipped.
|
||||
position?: 'top' | 'bottom'
|
||||
// Horizontal anchoring. 'center' (default) centers the bubble on the icon. Use 'right' when
|
||||
// the icon sits near the right edge so the bubble expands leftward into open space instead of
|
||||
// being squeezed against the viewport edge (which forces one-word-per-line wrapping).
|
||||
align?: 'center' | 'right'
|
||||
}
|
||||
|
||||
export default function InfoTooltip({ text, className = '' }: InfoTooltipProps) {
|
||||
export default function InfoTooltip({
|
||||
text,
|
||||
className = '',
|
||||
position = 'top',
|
||||
align = 'center',
|
||||
}: InfoTooltipProps) {
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
|
||||
return (
|
||||
|
|
@ -23,10 +35,24 @@ export default function InfoTooltip({ text, className = '' }: InfoTooltipProps)
|
|||
<IconInfoCircle className="w-4 h-4" />
|
||||
</button>
|
||||
{isVisible && (
|
||||
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-50">
|
||||
<div className="bg-desert-stone-dark text-white text-xs rounded-lg px-3 py-2 max-w-xs whitespace-normal shadow-lg">
|
||||
<div
|
||||
className={`absolute z-50 ${position === 'bottom' ? 'top-full mt-2' : 'bottom-full mb-2'} ${
|
||||
align === 'right' ? 'right-0' : 'left-1/2 -translate-x-1/2'
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`bg-desert-stone-dark text-white text-xs rounded-lg px-3 py-2 whitespace-normal shadow-lg ${
|
||||
align === 'right' ? 'w-64' : 'max-w-xs'
|
||||
}`}
|
||||
>
|
||||
{text}
|
||||
<div className="absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-desert-stone-dark" />
|
||||
<div
|
||||
className={`absolute border-4 border-transparent ${
|
||||
position === 'bottom'
|
||||
? 'bottom-full border-b-desert-stone-dark'
|
||||
: 'top-full border-t-desert-stone-dark'
|
||||
} ${align === 'right' ? 'right-3' : 'left-1/2 -translate-x-1/2'}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import classNames from '~/lib/classNames'
|
|||
import { IconX } from '@tabler/icons-react'
|
||||
import { DEFAULT_QUERY_REWRITE_MODEL } from '../../../constants/ollama'
|
||||
import { useSystemSetting } from '~/hooks/useSystemSetting'
|
||||
import Switch from '~/components/inputs/Switch'
|
||||
import InfoTooltip from '~/components/InfoTooltip'
|
||||
|
||||
interface ChatProps {
|
||||
enabled: boolean
|
||||
|
|
@ -534,18 +536,19 @@ export default function Chat({
|
|||
)}
|
||||
</div>
|
||||
{selectedModelSupportsThinking && (
|
||||
<label
|
||||
className="flex items-center gap-1.5 text-sm text-text-secondary cursor-pointer select-none"
|
||||
title="When on, this model reasons before answering. Remembered for this model."
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={effectiveThinking(selectedModel)}
|
||||
onChange={(e) => setModelThinking(selectedModel, e.target.checked)}
|
||||
className="h-4 w-4 rounded border-border-default text-desert-green focus:ring-desert-green"
|
||||
<div className="flex items-center">
|
||||
<span className="text-sm text-text-secondary select-none">Thinking:</span>
|
||||
<InfoTooltip
|
||||
position="bottom"
|
||||
align="right"
|
||||
text="When on, this model works through its reasoning before answering. Slower, but often better on tricky questions. Your choice is remembered for this model; the default for other models is set in AI Assistant settings."
|
||||
/>
|
||||
Thinking
|
||||
</label>
|
||||
<Switch
|
||||
id="chat-thinking-toggle"
|
||||
checked={effectiveThinking(selectedModel)}
|
||||
onChange={(v) => setModelThinking(selectedModel, v)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{isInModal && (
|
||||
<button
|
||||
|
|
|
|||
Loading…
Reference in New Issue