mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
Merge pull request #3344 from nexu-io/eli/fix/remove-pet-composer-button
fix(web): remove pet button from chat composer
This commit is contained in:
commit
69ed068721
1 changed files with 0 additions and 113 deletions
|
|
@ -283,9 +283,6 @@ export const ChatComposer = forwardRef<ChatComposerHandle, Props>(
|
||||||
const toolsMenuRef = useRef<HTMLDivElement | null>(null);
|
const toolsMenuRef = useRef<HTMLDivElement | null>(null);
|
||||||
const toolsTriggerRef = useRef<HTMLButtonElement | null>(null);
|
const toolsTriggerRef = useRef<HTMLButtonElement | null>(null);
|
||||||
const petEnabled = Boolean(onAdoptPet && onTogglePet);
|
const petEnabled = Boolean(onAdoptPet && onTogglePet);
|
||||||
const [petMenuOpen, setPetMenuOpen] = useState(false);
|
|
||||||
const petWrapRef = useRef<HTMLDivElement | null>(null);
|
|
||||||
const [petMenuStyle, setPetMenuStyle] = useState<React.CSSProperties>({});
|
|
||||||
const linkedDirs = projectMetadata?.linkedDirs ?? [];
|
const linkedDirs = projectMetadata?.linkedDirs ?? [];
|
||||||
// initialDraft is only honored on the first non-empty value the parent
|
// initialDraft is only honored on the first non-empty value the parent
|
||||||
// hands us. After we seed once, the composer is fully under user control
|
// hands us. After we seed once, the composer is fully under user control
|
||||||
|
|
@ -329,52 +326,6 @@ export const ChatComposer = forwardRef<ChatComposerHandle, Props>(
|
||||||
};
|
};
|
||||||
}, [toolsOpen]);
|
}, [toolsOpen]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!petMenuOpen) return;
|
|
||||||
function onPointer(e: MouseEvent) {
|
|
||||||
const target = e.target as Node;
|
|
||||||
if (petWrapRef.current?.contains(target)) return;
|
|
||||||
setPetMenuOpen(false);
|
|
||||||
}
|
|
||||||
function onKey(e: KeyboardEvent) {
|
|
||||||
if (e.key === 'Escape') setPetMenuOpen(false);
|
|
||||||
}
|
|
||||||
document.addEventListener('mousedown', onPointer);
|
|
||||||
document.addEventListener('keydown', onKey);
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener('mousedown', onPointer);
|
|
||||||
document.removeEventListener('keydown', onKey);
|
|
||||||
};
|
|
||||||
}, [petMenuOpen]);
|
|
||||||
|
|
||||||
// Viewport-aware pet menu positioning — flips the popover to stay
|
|
||||||
// within screen bounds instead of clipping at the edge.
|
|
||||||
useEffect(() => {
|
|
||||||
if (!petMenuOpen) return;
|
|
||||||
const wrap = petWrapRef.current;
|
|
||||||
if (!wrap) return;
|
|
||||||
const rect = wrap.getBoundingClientRect();
|
|
||||||
const menuW = 260;
|
|
||||||
const menuH = 200;
|
|
||||||
const gap = 6;
|
|
||||||
const viewW = window.innerWidth;
|
|
||||||
const viewH = window.innerHeight;
|
|
||||||
// Prefer opening upward (bottom of menu above the button).
|
|
||||||
// Flip downward when there isn't enough room above.
|
|
||||||
// When neither direction fits, clamp to viewport bounds.
|
|
||||||
let top: number;
|
|
||||||
if (rect.top >= menuH + gap) {
|
|
||||||
top = rect.top - menuH - gap;
|
|
||||||
} else if (rect.bottom + menuH + gap <= viewH) {
|
|
||||||
top = rect.bottom + gap;
|
|
||||||
} else {
|
|
||||||
top = Math.max(gap, viewH - menuH - gap);
|
|
||||||
}
|
|
||||||
// Right-align by default (menu right edge ≈ button right edge).
|
|
||||||
// Shift left when the menu would spill past the viewport left edge.
|
|
||||||
const left = Math.max(8, Math.min(viewW - menuW - 8, rect.right - menuW));
|
|
||||||
setPetMenuStyle({ position: 'fixed', top, left });
|
|
||||||
}, [petMenuOpen]);
|
|
||||||
|
|
||||||
// Lazy-fetch the user's external MCP servers list once on mount so the
|
// Lazy-fetch the user's external MCP servers list once on mount so the
|
||||||
// `/mcp …` slash palette and the composer's MCP button popover have
|
// `/mcp …` slash palette and the composer's MCP button popover have
|
||||||
|
|
@ -1756,70 +1707,6 @@ export const ChatComposer = forwardRef<ChatComposerHandle, Props>(
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{petEnabled ? (
|
|
||||||
<div className="composer-pet-wrap" ref={petWrapRef}>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`composer-pet${petConfig?.adopted ? ' adopted' : ''}`}
|
|
||||||
onClick={() => {
|
|
||||||
if (petConfig?.adopted) {
|
|
||||||
if (!petConfig.enabled) setPetMenuOpen(true);
|
|
||||||
else setPetMenuOpen((v) => !v);
|
|
||||||
} else {
|
|
||||||
setPetMenuOpen((v) => !v);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
title={t('pet.composerTitle')}
|
|
||||||
aria-haspopup="menu"
|
|
||||||
aria-expanded={petMenuOpen}
|
|
||||||
aria-label={t('pet.composerTitle')}
|
|
||||||
>
|
|
||||||
<span className="composer-pet-glyph">
|
|
||||||
{petConfig?.adopted ? (petConfig?.custom?.glyph || '🐾') : '🐾'}
|
|
||||||
</span>
|
|
||||||
<span className="composer-pet-label">
|
|
||||||
{petConfig?.adopted ? (petConfig?.custom?.name || 'Buddy') : t('pet.composerMenuTitle')}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
{petMenuOpen ? (
|
|
||||||
<div
|
|
||||||
className="composer-pet-menu"
|
|
||||||
style={petMenuStyle}
|
|
||||||
>
|
|
||||||
<div className="composer-pet-menu-head">
|
|
||||||
<strong>{t('pet.composerMenuTitle')}</strong>
|
|
||||||
<span>{t('pet.composerMenuHint')}</span>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="composer-pet-menu-row toggle"
|
|
||||||
onClick={() => {
|
|
||||||
if (petConfig?.adopted) {
|
|
||||||
onTogglePet?.();
|
|
||||||
} else {
|
|
||||||
onOpenPetSettings?.();
|
|
||||||
}
|
|
||||||
setPetMenuOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon name={petConfig?.enabled ? 'eye-off' : 'eye'} size={12} />
|
|
||||||
<span>{petConfig?.enabled ? t('pet.tuck') : t('pet.wake')}</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="composer-pet-menu-row settings"
|
|
||||||
onClick={() => {
|
|
||||||
onOpenPetSettings?.();
|
|
||||||
setPetMenuOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon name="settings" size={12} />
|
|
||||||
<span>{t('pet.composerOpenSettings')}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<button
|
<button
|
||||||
className="icon-btn"
|
className="icon-btn"
|
||||||
data-testid="chat-attach"
|
data-testid="chat-attach"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue