mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 07:05:24 +00:00
fix: let the hover side menu overlay content instead of resizing it (Plugin-Remote-Desktop#2)
This commit is contained in:
1 parent
8e2221cb8f
commit
c3f6db69e9
3 files changed
+257
-228
No files matched your search
@@ -7,6 +7,10 @@
|
|||||||
- Hide sidebar after opening, in Customize Sidebar, closes the host list once you open a host
|
- Hide sidebar after opening, in Customize Sidebar, closes the host list once you open a host
|
||||||
- Sort the dashboard's Host Status card by name, IP address or status
|
- Sort the dashboard's Host Status card by name, IP address or status
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The side menu now opens over the page when it expands on hover, so open sessions like remote desktop are not resized each time
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Picking a section lower down in the host editor, like Warpgate, stuttered on the way and sometimes stopped before it got there
|
- Picking a section lower down in the host editor, like Warpgate, stuttered on the way and sometimes stopped before it got there
|
||||||
|
|||||||
+241
-228
@@ -312,255 +312,268 @@ export function AppRail({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Expanding on hover draws over the content instead of pushing it, so open
|
||||||
|
// sessions like remote desktop are not resized each time.
|
||||||
|
const takesSpace = pinned || managing;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
// The desktop app keeps the rail however narrow its window gets.
|
// The desktop app keeps the rail however narrow its window gets.
|
||||||
className={`${isElectron() ? "flex" : "hidden md:flex"} flex-col items-stretch bg-sidebar border-r border-border shrink-0 overflow-hidden pt-2 gap-1 transition-[width] duration-200 min-h-0`}
|
className={`${isElectron() ? "flex" : "hidden md:flex"} relative shrink-0 transition-[width] duration-200 min-h-0`}
|
||||||
style={{ width: rem(railExpanded ? 172 : 40) }}
|
style={{ width: rem(takesSpace ? 172 : 40) }}
|
||||||
onMouseEnter={() => setHovered(true)}
|
|
||||||
onMouseLeave={() => setHovered(false)}
|
|
||||||
onContextMenu={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
// Keep the menu on screen when right-clicking near the viewport edges
|
|
||||||
const MENU_W = 200;
|
|
||||||
const MENU_H = 180;
|
|
||||||
setMenuPos({
|
|
||||||
x: Math.min(e.clientX, window.innerWidth - MENU_W - 8),
|
|
||||||
y: Math.min(e.clientY, window.innerHeight - MENU_H - 8),
|
|
||||||
});
|
|
||||||
if (!(e.target as HTMLElement).closest("[data-rail-item]")) {
|
|
||||||
setMenuTarget(null);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{onOpenPalette && (
|
<div
|
||||||
<>
|
className="absolute inset-y-0 left-0 z-40 flex flex-col items-stretch bg-sidebar border-r border-border overflow-hidden pt-2 gap-1 transition-[width] duration-200 min-h-0"
|
||||||
<button
|
style={{ width: rem(railExpanded ? 172 : 40) }}
|
||||||
type="button"
|
onMouseEnter={() => setHovered(true)}
|
||||||
onClick={onOpenPalette}
|
onMouseLeave={() => setHovered(false)}
|
||||||
title={t("nav.searchEverything")}
|
onContextMenu={(e) => {
|
||||||
aria-label={t("nav.searchEverything")}
|
e.preventDefault();
|
||||||
style={btnStyle}
|
// Keep the menu on screen when right-clicking near the viewport edges
|
||||||
className={`${btnBase} ${idle}`}
|
const MENU_W = 200;
|
||||||
>
|
const MENU_H = 180;
|
||||||
<RailIcon>
|
setMenuPos({
|
||||||
<Search size={16} />
|
x: Math.min(e.clientX, window.innerWidth - MENU_W - 8),
|
||||||
</RailIcon>
|
y: Math.min(e.clientY, window.innerHeight - MENU_H - 8),
|
||||||
<RailLabel expanded={railExpanded}>{t("nav.search")}</RailLabel>
|
});
|
||||||
</button>
|
if (!(e.target as HTMLElement).closest("[data-rail-item]")) {
|
||||||
<Rule expanded={railExpanded} />
|
setMenuTarget(null);
|
||||||
</>
|
}
|
||||||
)}
|
}}
|
||||||
|
>
|
||||||
<div className="flex flex-col flex-1 gap-1 overflow-y-auto scrollbar-none min-h-0">
|
{onOpenPalette && (
|
||||||
{!pluginsSettled
|
|
||||||
? Array.from({ length: mainItems.length || 8 }, (_, i) => (
|
|
||||||
<div
|
|
||||||
key={`rail-skeleton-${i}`}
|
|
||||||
style={btnStyle}
|
|
||||||
className="flex items-center h-7 shrink-0"
|
|
||||||
>
|
|
||||||
<Skeleton className="size-4 shrink-0" />
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
: bands.map((band, i) => (
|
|
||||||
<div key={band.group} className="flex flex-col gap-1">
|
|
||||||
{i > 0 && (
|
|
||||||
<GroupDivider group={band.group} expanded={railExpanded} />
|
|
||||||
)}
|
|
||||||
{band.items.map(renderItem)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{pluginsSettled && hiddenItems.length > 0 && (
|
|
||||||
<>
|
|
||||||
<Rule expanded={railExpanded} />
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setManaging((v) => !v)}
|
|
||||||
aria-expanded={managing}
|
|
||||||
title={t("nav.hiddenCount", { count: hiddenItems.length })}
|
|
||||||
style={btnStyle}
|
|
||||||
className={`${btnBase} ${managing ? activeClass : idle}`}
|
|
||||||
>
|
|
||||||
<RailIcon>
|
|
||||||
<EyeOff size={16} />
|
|
||||||
</RailIcon>
|
|
||||||
<RailLabel expanded={railExpanded}>
|
|
||||||
{t("nav.hiddenCount", { count: hiddenItems.length })}
|
|
||||||
</RailLabel>
|
|
||||||
</button>
|
|
||||||
{managing &&
|
|
||||||
hiddenItems.map((item) => {
|
|
||||||
const Icon = item.icon;
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={`hidden-${item.id}`}
|
|
||||||
type="button"
|
|
||||||
onClick={() => void toggleHiddenRailTab(item.id)}
|
|
||||||
title={t("nav.showInRail")}
|
|
||||||
style={btnStyle}
|
|
||||||
className={`${btnBase} text-muted-foreground/70 hover:text-foreground hover:bg-muted/60`}
|
|
||||||
>
|
|
||||||
<RailIcon>
|
|
||||||
<Icon size={16} />
|
|
||||||
</RailIcon>
|
|
||||||
<span className="min-w-0 truncate text-xs font-medium whitespace-nowrap">
|
|
||||||
{t(item.labelKey)}
|
|
||||||
</span>
|
|
||||||
<Eye className="ml-auto size-3 shrink-0 opacity-60" />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="shrink-0 flex flex-col gap-1 border-t border-border pt-1 pb-1">
|
|
||||||
{showPinButton && (
|
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setRailPreference("pinAppRail", !pinned)}
|
onClick={onOpenPalette}
|
||||||
|
title={t("nav.searchEverything")}
|
||||||
|
aria-label={t("nav.searchEverything")}
|
||||||
style={btnStyle}
|
style={btnStyle}
|
||||||
title={
|
className={`${btnBase} ${idle}`}
|
||||||
pinned ? t("nav.collapseSideMenu") : t("nav.keepSideMenuOpen")
|
|
||||||
}
|
|
||||||
className={`${btnBase} ${pinned ? activeClass : idle}`}
|
|
||||||
>
|
>
|
||||||
<RailIcon>
|
<RailIcon>
|
||||||
<Pin size={16} />
|
<Search size={16} />
|
||||||
</RailIcon>
|
</RailIcon>
|
||||||
<RailLabel expanded={railExpanded}>
|
<RailLabel expanded={railExpanded}>{t("nav.search")}</RailLabel>
|
||||||
{pinned ? t("nav.collapseSideMenu") : t("nav.keepSideMenuOpen")}
|
|
||||||
</RailLabel>
|
|
||||||
</button>
|
</button>
|
||||||
<Rule expanded={railExpanded} />
|
<Rule expanded={railExpanded} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{footerItems.map(renderItem)}
|
|
||||||
{footerItems.length > 0 && !isElectron() && (
|
|
||||||
<Rule expanded={railExpanded} />
|
|
||||||
)}
|
|
||||||
{/* The desktop signs in to its own local profile by itself. */}
|
|
||||||
{!isElectron() && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => onLogout({ manual: true })}
|
|
||||||
style={btnStyle}
|
|
||||||
title={t("common.logout")}
|
|
||||||
aria-label={t("common.logout")}
|
|
||||||
className={`${btnBase} text-muted-foreground hover:text-destructive hover:bg-destructive/10`}
|
|
||||||
>
|
|
||||||
<RailIcon>
|
|
||||||
<LogOut size={16} />
|
|
||||||
</RailIcon>
|
|
||||||
<RailLabel expanded={railExpanded}>{t("common.logout")}</RailLabel>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="shrink-0 border-t border-border">
|
<div className="flex flex-col flex-1 gap-1 overflow-y-auto scrollbar-none min-h-0">
|
||||||
<button
|
{!pluginsSettled
|
||||||
type="button"
|
? Array.from({ length: mainItems.length || 8 }, (_, i) => (
|
||||||
onClick={onOpenSettings}
|
<div
|
||||||
title={t("nav.openSettings")}
|
key={`rail-skeleton-${i}`}
|
||||||
aria-label={t("nav.openSettings")}
|
style={btnStyle}
|
||||||
className="flex items-center gap-2.5 w-full h-10 text-muted-foreground hover:text-foreground hover:bg-muted/60 transition-colors focus-visible:ring-1 focus-visible:ring-ring"
|
className="flex items-center h-7 shrink-0"
|
||||||
style={{ padding: `0 ${rem(8)}` }}
|
>
|
||||||
>
|
<Skeleton className="size-4 shrink-0" />
|
||||||
<div
|
</div>
|
||||||
className="rounded-full bg-accent-brand/20 border border-accent-brand/30 flex items-center justify-center font-bold text-accent-brand shrink-0"
|
))
|
||||||
style={{ width: rem(24), height: rem(24), fontSize: rem(11) }}
|
: bands.map((band, i) => (
|
||||||
>
|
<div key={band.group} className="flex flex-col gap-1">
|
||||||
{username.charAt(0).toUpperCase() || "U"}
|
{i > 0 && (
|
||||||
</div>
|
<GroupDivider group={band.group} expanded={railExpanded} />
|
||||||
<div
|
)}
|
||||||
className={`flex flex-col items-start overflow-hidden transition-opacity duration-150 ${
|
{band.items.map(renderItem)}
|
||||||
railExpanded ? "opacity-100 delay-75" : "opacity-0"
|
</div>
|
||||||
}`}
|
))}
|
||||||
>
|
|
||||||
<span className="text-xs font-semibold leading-tight whitespace-nowrap">
|
|
||||||
{username || t("nav.roleUser")}
|
|
||||||
</span>
|
|
||||||
<span className="text-[10px] text-muted-foreground leading-tight whitespace-nowrap">
|
|
||||||
{isAdmin ? t("nav.roleAdministrator") : t("nav.roleUser")}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{menuPos && (
|
{pluginsSettled && hiddenItems.length > 0 && (
|
||||||
<div
|
|
||||||
data-rail-context-menu
|
|
||||||
role="menu"
|
|
||||||
style={{ position: "fixed", left: menuPos.x, top: menuPos.y }}
|
|
||||||
className="z-[10000] bg-popover border border-border shadow-lg py-1 min-w-[200px]"
|
|
||||||
>
|
|
||||||
{menuTarget && (
|
|
||||||
<>
|
<>
|
||||||
{menuTarget.promotable && (
|
<Rule expanded={railExpanded} />
|
||||||
<MenuItem
|
<button
|
||||||
icon={<SquareArrowOutUpRight className="size-3" />}
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => setManaging((v) => !v)}
|
||||||
onOpenTab?.(menuTarget.id as TabType);
|
aria-expanded={managing}
|
||||||
setMenuPos(null);
|
title={t("nav.hiddenCount", { count: hiddenItems.length })}
|
||||||
}}
|
style={btnStyle}
|
||||||
>
|
className={`${btnBase} ${managing ? activeClass : idle}`}
|
||||||
{t("nav.openAsTab")}
|
>
|
||||||
</MenuItem>
|
<RailIcon>
|
||||||
)}
|
<EyeOff size={16} />
|
||||||
{menuTarget.rightDockable && (
|
</RailIcon>
|
||||||
<MenuItem
|
<RailLabel expanded={railExpanded}>
|
||||||
icon={<PanelRight className="size-3" />}
|
{t("nav.hiddenCount", { count: hiddenItems.length })}
|
||||||
onClick={() => {
|
</RailLabel>
|
||||||
onOpenInRightDock?.(menuTarget.id);
|
</button>
|
||||||
setMenuPos(null);
|
{managing &&
|
||||||
}}
|
hiddenItems.map((item) => {
|
||||||
>
|
const Icon = item.icon;
|
||||||
{t("nav.openInRightDock")}
|
return (
|
||||||
</MenuItem>
|
<button
|
||||||
)}
|
key={`hidden-${item.id}`}
|
||||||
{menuTarget.hideable && (
|
type="button"
|
||||||
<MenuItem
|
onClick={() => void toggleHiddenRailTab(item.id)}
|
||||||
icon={<EyeOff className="size-3" />}
|
title={t("nav.showInRail")}
|
||||||
onClick={() => {
|
style={btnStyle}
|
||||||
void toggleHiddenRailTab(menuTarget.id);
|
className={`${btnBase} text-muted-foreground/70 hover:text-foreground hover:bg-muted/60`}
|
||||||
setMenuPos(null);
|
>
|
||||||
}}
|
<RailIcon>
|
||||||
>
|
<Icon size={16} />
|
||||||
{t("nav.hideFromRail")}
|
</RailIcon>
|
||||||
</MenuItem>
|
<span className="min-w-0 truncate text-xs font-medium whitespace-nowrap">
|
||||||
)}
|
{t(item.labelKey)}
|
||||||
<div className="h-px bg-border my-1" />
|
</span>
|
||||||
|
<Eye className="ml-auto size-3 shrink-0 opacity-60" />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<MenuItem
|
|
||||||
icon={pinned ? <Check className="size-3" /> : null}
|
|
||||||
onClick={togglePinned}
|
|
||||||
checked={pinned}
|
|
||||||
>
|
|
||||||
{t("newUi.sidebar.userProfile.pinAppRail")}
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem
|
|
||||||
icon={expandOnHover ? <Check className="size-3" /> : null}
|
|
||||||
onClick={toggleExpandOnHover}
|
|
||||||
checked={expandOnHover}
|
|
||||||
>
|
|
||||||
{t("newUi.sidebar.userProfile.expandAppRailOnHover")}
|
|
||||||
</MenuItem>
|
|
||||||
<div className="h-px bg-border my-1" />
|
|
||||||
<MenuItem
|
|
||||||
icon={<SlidersHorizontal className="size-3" />}
|
|
||||||
onClick={() => {
|
|
||||||
onOpenNavigationSettings();
|
|
||||||
setMenuPos(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t("nav.openSettings")}
|
|
||||||
</MenuItem>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
<div className="shrink-0 flex flex-col gap-1 border-t border-border pt-1 pb-1">
|
||||||
|
{showPinButton && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setRailPreference("pinAppRail", !pinned)}
|
||||||
|
style={btnStyle}
|
||||||
|
title={
|
||||||
|
pinned ? t("nav.collapseSideMenu") : t("nav.keepSideMenuOpen")
|
||||||
|
}
|
||||||
|
className={`${btnBase} ${pinned ? activeClass : idle}`}
|
||||||
|
>
|
||||||
|
<RailIcon>
|
||||||
|
<Pin size={16} />
|
||||||
|
</RailIcon>
|
||||||
|
<RailLabel expanded={railExpanded}>
|
||||||
|
{pinned
|
||||||
|
? t("nav.collapseSideMenu")
|
||||||
|
: t("nav.keepSideMenuOpen")}
|
||||||
|
</RailLabel>
|
||||||
|
</button>
|
||||||
|
<Rule expanded={railExpanded} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{footerItems.map(renderItem)}
|
||||||
|
{footerItems.length > 0 && !isElectron() && (
|
||||||
|
<Rule expanded={railExpanded} />
|
||||||
|
)}
|
||||||
|
{/* The desktop signs in to its own local profile by itself. */}
|
||||||
|
{!isElectron() && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => onLogout({ manual: true })}
|
||||||
|
style={btnStyle}
|
||||||
|
title={t("common.logout")}
|
||||||
|
aria-label={t("common.logout")}
|
||||||
|
className={`${btnBase} text-muted-foreground hover:text-destructive hover:bg-destructive/10`}
|
||||||
|
>
|
||||||
|
<RailIcon>
|
||||||
|
<LogOut size={16} />
|
||||||
|
</RailIcon>
|
||||||
|
<RailLabel expanded={railExpanded}>
|
||||||
|
{t("common.logout")}
|
||||||
|
</RailLabel>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="shrink-0 border-t border-border">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onOpenSettings}
|
||||||
|
title={t("nav.openSettings")}
|
||||||
|
aria-label={t("nav.openSettings")}
|
||||||
|
className="flex items-center gap-2.5 w-full h-10 text-muted-foreground hover:text-foreground hover:bg-muted/60 transition-colors focus-visible:ring-1 focus-visible:ring-ring"
|
||||||
|
style={{ padding: `0 ${rem(8)}` }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="rounded-full bg-accent-brand/20 border border-accent-brand/30 flex items-center justify-center font-bold text-accent-brand shrink-0"
|
||||||
|
style={{ width: rem(24), height: rem(24), fontSize: rem(11) }}
|
||||||
|
>
|
||||||
|
{username.charAt(0).toUpperCase() || "U"}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`flex flex-col items-start overflow-hidden transition-opacity duration-150 ${
|
||||||
|
railExpanded ? "opacity-100 delay-75" : "opacity-0"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span className="text-xs font-semibold leading-tight whitespace-nowrap">
|
||||||
|
{username || t("nav.roleUser")}
|
||||||
|
</span>
|
||||||
|
<span className="text-[10px] text-muted-foreground leading-tight whitespace-nowrap">
|
||||||
|
{isAdmin ? t("nav.roleAdministrator") : t("nav.roleUser")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{menuPos && (
|
||||||
|
<div
|
||||||
|
data-rail-context-menu
|
||||||
|
role="menu"
|
||||||
|
style={{ position: "fixed", left: menuPos.x, top: menuPos.y }}
|
||||||
|
className="z-[10000] bg-popover border border-border shadow-lg py-1 min-w-[200px]"
|
||||||
|
>
|
||||||
|
{menuTarget && (
|
||||||
|
<>
|
||||||
|
{menuTarget.promotable && (
|
||||||
|
<MenuItem
|
||||||
|
icon={<SquareArrowOutUpRight className="size-3" />}
|
||||||
|
onClick={() => {
|
||||||
|
onOpenTab?.(menuTarget.id as TabType);
|
||||||
|
setMenuPos(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("nav.openAsTab")}
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
{menuTarget.rightDockable && (
|
||||||
|
<MenuItem
|
||||||
|
icon={<PanelRight className="size-3" />}
|
||||||
|
onClick={() => {
|
||||||
|
onOpenInRightDock?.(menuTarget.id);
|
||||||
|
setMenuPos(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("nav.openInRightDock")}
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
{menuTarget.hideable && (
|
||||||
|
<MenuItem
|
||||||
|
icon={<EyeOff className="size-3" />}
|
||||||
|
onClick={() => {
|
||||||
|
void toggleHiddenRailTab(menuTarget.id);
|
||||||
|
setMenuPos(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("nav.hideFromRail")}
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
<div className="h-px bg-border my-1" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<MenuItem
|
||||||
|
icon={pinned ? <Check className="size-3" /> : null}
|
||||||
|
onClick={togglePinned}
|
||||||
|
checked={pinned}
|
||||||
|
>
|
||||||
|
{t("newUi.sidebar.userProfile.pinAppRail")}
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
icon={expandOnHover ? <Check className="size-3" /> : null}
|
||||||
|
onClick={toggleExpandOnHover}
|
||||||
|
checked={expandOnHover}
|
||||||
|
>
|
||||||
|
{t("newUi.sidebar.userProfile.expandAppRailOnHover")}
|
||||||
|
</MenuItem>
|
||||||
|
<div className="h-px bg-border my-1" />
|
||||||
|
<MenuItem
|
||||||
|
icon={<SlidersHorizontal className="size-3" />}
|
||||||
|
onClick={() => {
|
||||||
|
onOpenNavigationSettings();
|
||||||
|
setMenuPos(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("nav.openSettings")}
|
||||||
|
</MenuItem>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,18 @@ describe("AppRail", () => {
|
|||||||
expect(screen.queryByLabelText("common.logout")).toBeNull();
|
expect(screen.queryByLabelText("common.logout")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("expands over the content on hover without taking more room", () => {
|
||||||
|
renderRail();
|
||||||
|
const rail = screen
|
||||||
|
.getByLabelText("common.logout")
|
||||||
|
.closest(".absolute") as HTMLElement;
|
||||||
|
const slot = rail.parentElement as HTMLElement;
|
||||||
|
const collapsed = slot.style.width;
|
||||||
|
fireEvent.mouseEnter(rail);
|
||||||
|
expect(rail.style.width).not.toBe(collapsed);
|
||||||
|
expect(slot.style.width).toBe(collapsed);
|
||||||
|
});
|
||||||
|
|
||||||
it("puts a footer item above the profile with its badge", async () => {
|
it("puts a footer item above the profile with its badge", async () => {
|
||||||
registerRailItem({
|
registerRailItem({
|
||||||
id: "inbox",
|
id: "inbox",
|
||||||
|
|||||||
Reference in new issue
Block a user