fix: make model selector dropdowns responsive to viewport
This commit is contained in:
Generated
+1
-1
@@ -2847,7 +2847,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openchamber-desktop"
|
name = "openchamber-desktop"
|
||||||
version = "1.4.1"
|
version = "1.4.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"axum",
|
"axum",
|
||||||
|
|||||||
@@ -1870,7 +1870,7 @@ export const ModelControls: React.FC<ModelControlsProps> = ({ className }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Scrollable content */}
|
{/* Scrollable content */}
|
||||||
<ScrollableOverlay outerClassName="max-h-[400px] flex-1">
|
<ScrollableOverlay outerClassName="max-h-[min(400px,calc(100dvh-12rem))] flex-1">
|
||||||
<div className="p-1">
|
<div className="p-1">
|
||||||
{!hasResults && (
|
{!hasResults && (
|
||||||
<div className="px-2 py-4 text-center typography-meta text-muted-foreground">
|
<div className="px-2 py-4 text-center typography-meta text-muted-foreground">
|
||||||
|
|||||||
@@ -111,8 +111,10 @@ export const ModelMultiSelect: React.FC<ModelMultiSelectProps> = ({
|
|||||||
const [isOpen, setIsOpen] = React.useState(false);
|
const [isOpen, setIsOpen] = React.useState(false);
|
||||||
const [searchQuery, setSearchQuery] = React.useState('');
|
const [searchQuery, setSearchQuery] = React.useState('');
|
||||||
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
||||||
|
const [availableHeight, setAvailableHeight] = React.useState<number | null>(null);
|
||||||
const searchInputRef = React.useRef<HTMLInputElement>(null);
|
const searchInputRef = React.useRef<HTMLInputElement>(null);
|
||||||
const dropdownRef = React.useRef<HTMLDivElement>(null);
|
const dropdownRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
const triggerRef = React.useRef<HTMLButtonElement>(null);
|
||||||
const itemRefs = React.useRef<(HTMLButtonElement | null)[]>([]);
|
const itemRefs = React.useRef<(HTMLButtonElement | null)[]>([]);
|
||||||
|
|
||||||
// Count occurrences of each model for display purposes
|
// Count occurrences of each model for display purposes
|
||||||
@@ -193,6 +195,17 @@ export const ModelMultiSelect: React.FC<ModelMultiSelectProps> = ({
|
|||||||
|
|
||||||
const hasResults = filteredFavorites.length > 0 || filteredRecents.length > 0 || filteredProviders.length > 0;
|
const hasResults = filteredFavorites.length > 0 || filteredRecents.length > 0 || filteredProviders.length > 0;
|
||||||
|
|
||||||
|
// Calculate available height when dropdown opens
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (isOpen && triggerRef.current) {
|
||||||
|
const rect = triggerRef.current.getBoundingClientRect();
|
||||||
|
// Space above trigger minus padding from top edge
|
||||||
|
const spaceAbove = rect.top - 100;
|
||||||
|
// Cap at 400px max, minimum 150px
|
||||||
|
setAvailableHeight(Math.max(150, Math.min(400, spaceAbove)));
|
||||||
|
}
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
// Focus search input when opened
|
// Focus search input when opened
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (isOpen && searchInputRef.current) {
|
if (isOpen && searchInputRef.current) {
|
||||||
@@ -280,6 +293,7 @@ export const ModelMultiSelect: React.FC<ModelMultiSelectProps> = ({
|
|||||||
{/* Add model button (dropdown trigger) */}
|
{/* Add model button (dropdown trigger) */}
|
||||||
<div className="relative" ref={dropdownRef}>
|
<div className="relative" ref={dropdownRef}>
|
||||||
<Button
|
<Button
|
||||||
|
ref={triggerRef}
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -369,7 +383,10 @@ export const ModelMultiSelect: React.FC<ModelMultiSelectProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Models list */}
|
{/* Models list */}
|
||||||
<ScrollableOverlay outerClassName="max-h-[400px] flex-1">
|
<ScrollableOverlay
|
||||||
|
outerClassName="flex-1"
|
||||||
|
style={{ maxHeight: availableHeight ? `${availableHeight}px` : '300px' }}
|
||||||
|
>
|
||||||
<div className="p-1">
|
<div className="p-1">
|
||||||
{!hasResults && (
|
{!hasResults && (
|
||||||
<div className="px-2 py-4 text-center typography-meta text-muted-foreground">
|
<div className="px-2 py-4 text-center typography-meta text-muted-foreground">
|
||||||
|
|||||||
@@ -563,7 +563,7 @@ export const ModelSelector: React.FC<ModelSelectorProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Scrollable content */}
|
{/* Scrollable content */}
|
||||||
<ScrollableOverlay outerClassName="max-h-[400px] flex-1">
|
<ScrollableOverlay outerClassName="max-h-[min(400px,calc(100dvh-12rem))] flex-1">
|
||||||
<div className="p-1">
|
<div className="p-1">
|
||||||
{/* Not selected option */}
|
{/* Not selected option */}
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user