feat(navigator): responsive layout + saved-search refinement (P4 wave 1c)

- Stack sidebar above results below sm; cap card width to viewport
- Fix tab-bar wrap overlapping content on narrow screens (max-height/height/flex reset)
- Saved-search rows: whole row opens search, hover-reveal delete (no layout shift), bolt icon, empty state
- Hover affordance on navigator grid items and saved-search rows
This commit is contained in:
simoleo89
2026-05-31 00:42:52 +02:00
committed by simoleo89
parent b17cd891b3
commit 641593c3ef
4 changed files with 61 additions and 27 deletions
+4 -4
View File
@@ -109,7 +109,7 @@ export const NavigatorView: FC<{}> = props =>
<>
{ isVisible &&
<NitroCard
className={ `${ isOpenSavesSearches ? 'w-[600px] min-w-[600px]' : 'w-navigator-w min-w-navigator-w' } h-navigator-h min-h-navigator-h` }
className={ `${ isOpenSavesSearches ? 'w-[600px] sm:min-w-[600px]' : 'w-navigator-w sm:min-w-navigator-w' } max-w-[calc(100vw-1rem)] h-navigator-h min-h-navigator-h` }
uniqueKey="navigator">
<NitroCard.Header
headerText={ LocalizeText(isCreatorOpen ? 'navigator.createroom.title' : 'navigator.title') }
@@ -136,12 +136,12 @@ export const NavigatorView: FC<{}> = props =>
</NitroCard.Tabs>
<NitroCard.Content>
{ !isCreatorOpen &&
<div className="flex h-full overflow-hidden gap-2">
<div className="flex flex-col sm:flex-row h-full overflow-hidden gap-2">
{ isOpenSavesSearches &&
<div className="overflow-hidden pr-1 shrink-0">
<div className="overflow-hidden pr-1 shrink-0 w-full sm:w-auto max-h-40 sm:max-h-none">
<NavigatorSearchSavesResultView searches={ navigatorSearches || [] } />
</div> }
<div className="flex flex-col w-full overflow-hidden gap-2">
<div className="flex flex-col w-full min-h-0 overflow-hidden gap-2">
<NavigatorSearchView searchResult={ searchResult } />
<div ref={ elementRef } className="flex flex-col flex-1 min-h-0 overflow-auto gap-2">
{ (isFetching && !searchResult) &&
@@ -1,5 +1,6 @@
import { NavigatorDeleteSavedSearchComposer, NavigatorSavedSearch, NavigatorSearchComposer } from '@nitrots/nitro-renderer';
import { FC, useState } from 'react';
import { FC, MouseEvent } from 'react';
import { FaBolt } from 'react-icons/fa';
import { LocalizeText, SendMessageComposer } from '../../../../api';
import { Flex, Text } from '../../../../common';
@@ -11,7 +12,6 @@ export interface NavigatorSearchSavesResultItemViewProps
export const NavigatorSearchSavesResultItemView: FC<NavigatorSearchSavesResultItemViewProps> = props =>
{
const { search = null } = props;
const [ isHovered, setIsHovered ] = useState(false);
const getResultTitle = () =>
{
@@ -24,23 +24,33 @@ export const NavigatorSearchSavesResultItemView: FC<NavigatorSearchSavesResultIt
return ('navigator.searchcode.title.' + name);
};
const openSearch = () => SendMessageComposer(new NavigatorSearchComposer(search.code.split('.').reverse()[0], search.filter));
const deleteSearch = (event: MouseEvent) =>
{
event.stopPropagation();
SendMessageComposer(new NavigatorDeleteSavedSearchComposer(search.id));
};
return (
<Flex grow pointer alignItems="center" gap={ 1 } onMouseEnter={ () => setIsHovered(true) } onMouseLeave={ () => setIsHovered(false) }>
{ isHovered &&
<i
className="nitro-icon icon-navigator-search-delete cursor-pointer flex-shrink-0"
title={ LocalizeText('navigator.tooltip.remove.saved.search') }
onClick={ () => SendMessageComposer(new NavigatorDeleteSavedSearchComposer(search.id)) }
/> }
<Text
small
pointer
variant="black"
title={ LocalizeText('navigator.tooltip.open.saved.search') }
onClick={ () => SendMessageComposer(new NavigatorSearchComposer(search.code.split('.').reverse()[0], search.filter)) }
>
<Flex
grow
pointer
alignItems="center"
gap={ 1 }
className="saved-search-row group px-1 py-0.5"
title={ LocalizeText('navigator.tooltip.open.saved.search') }
onClick={ openSearch }
>
<FaBolt className="text-orange-500 shrink-0 text-[10px]" />
<Text small pointer truncate variant="black" className="grow! min-w-0">
{ LocalizeText(getResultTitle()) }
</Text>
<i
className="nitro-icon icon-navigator-search-delete cursor-pointer flex-shrink-0 opacity-0 transition-opacity group-hover:opacity-100"
title={ LocalizeText('navigator.tooltip.remove.saved.search') }
onClick={ deleteSearch }
/>
</Flex>
);
};
@@ -15,16 +15,19 @@ export const NavigatorSearchSavesResultView: FC<NavigatorSearchSavesResultViewPr
const { searches = [] } = props;
return (
<Column className="nitro-navigator-search-saves-result min-w-[100px]">
<Flex className="rounded px-2 py-1 bg-orange-500" gap={ 1 } alignItems="center">
<Column className="nitro-navigator-search-saves-result h-full min-w-[100px] sm:w-[150px]" gap={ 1 }>
<Flex className="rounded px-2 py-1 bg-orange-500 shrink-0" gap={ 1 } alignItems="center">
<FaBolt color="white" />
<Text variant="white">{ LocalizeText('navigator.quick.links.title') }</Text>
<Text variant="white" truncate>{ LocalizeText('navigator.quick.links.title') }</Text>
</Flex>
<Column className="p-1 overflow-x-hidden overflow-y-auto">
{ (searches && searches.length > 0) &&
searches.map((search: NavigatorSavedSearch) => (
<Column className="flex-1 min-h-0 p-1 overflow-x-hidden overflow-y-auto" gap={ 0 }>
{ (searches && searches.length > 0)
? searches.map((search: NavigatorSavedSearch) => (
<NavigatorSearchSavesResultItemView key={ search.id } search={ search } />
)) }
))
: <Flex center className="py-4 opacity-30">
<FaBolt className="text-orange-500" size={ 22 } />
</Flex> }
</Column>
</Column>
);
+21
View File
@@ -476,6 +476,24 @@ body {
border-color: #aeb7aa !important;
}
.navigator-grid .navigator-item {
border-radius: 6px;
transition: background-color .15s ease;
}
.navigator-grid .navigator-item:hover {
background: rgba(0, 0, 0, 0.07);
}
.nitro-navigator-search-saves-result .saved-search-row {
border-radius: 6px;
transition: background-color .15s ease;
}
.nitro-navigator-search-saves-result .saved-search-row:hover {
background: rgba(0, 0, 0, 0.07);
}
.nitro-card-divider {
border-color: #c4cabf !important;
box-shadow: none !important;
@@ -523,6 +541,9 @@ body {
flex-wrap: wrap;
gap: 3px;
padding: 4px 6px 0;
max-height: none;
height: auto;
flex: 0 0 auto;
}
.nitro-card-tab-item {