wip(app): full-height sidebar

This commit is contained in:
adamelmore
2026-01-26 08:06:53 -06:00
parent ff35db0360
commit 7016be0739
2 changed files with 13 additions and 11 deletions

View File

@@ -137,7 +137,7 @@ export default function Layout(props: ParentProps) {
const [hoverSession, setHoverSession] = createSignal<string | undefined>() const [hoverSession, setHoverSession] = createSignal<string | undefined>()
const [hoverProject, setHoverProject] = createSignal<string | undefined>() const [hoverProject, setHoverProject] = createSignal<string | undefined>()
const navRef = { current: undefined as HTMLElement | undefined } const [nav, setNav] = createSignal<HTMLElement | undefined>(undefined)
const sidebarHovering = createMemo(() => !layout.sidebar.opened() && hoverProject() !== undefined) const sidebarHovering = createMemo(() => !layout.sidebar.opened() && hoverProject() !== undefined)
const sidebarExpanded = createMemo(() => layout.sidebar.opened() || sidebarHovering()) const sidebarExpanded = createMemo(() => layout.sidebar.opened() || sidebarHovering())
@@ -1702,10 +1702,11 @@ export default function Layout(props: ParentProps) {
> >
<HoverCard <HoverCard
openDelay={1000} openDelay={1000}
closeDelay={0} closeDelay={sidebarHovering() ? 300 : 0}
placement="right" placement="right"
gutter={28} gutter={28}
trigger={item} trigger={item}
mount={!props.mobile ? nav() : undefined}
open={hoverSession() === props.session.id} open={hoverSession() === props.session.id}
onOpenChange={(open) => setHoverSession(open ? props.session.id : undefined)} onOpenChange={(open) => setHoverSession(open ? props.session.id : undefined)}
> >
@@ -1743,7 +1744,7 @@ export default function Layout(props: ParentProps) {
"group-focus-within/session:opacity-100 group-focus-within/session:pointer-events-auto": true, "group-focus-within/session:opacity-100 group-focus-within/session:pointer-events-auto": true,
}} }}
> >
<DropdownMenu open={menuOpen()} onOpenChange={setMenuOpen}> <DropdownMenu modal={!sidebarHovering()} open={menuOpen()} onOpenChange={setMenuOpen}>
<Tooltip value={language.t("common.moreOptions")} placement="top"> <Tooltip value={language.t("common.moreOptions")} placement="top">
<DropdownMenu.Trigger <DropdownMenu.Trigger
as={IconButton} as={IconButton}
@@ -1753,7 +1754,7 @@ export default function Layout(props: ParentProps) {
aria-label={language.t("common.moreOptions")} aria-label={language.t("common.moreOptions")}
/> />
</Tooltip> </Tooltip>
<DropdownMenu.Portal mount={!props.mobile ? navRef.current : undefined}> <DropdownMenu.Portal mount={!props.mobile ? nav() : undefined}>
<DropdownMenu.Content <DropdownMenu.Content
onCloseAutoFocus={(event) => { onCloseAutoFocus={(event) => {
if (!pendingRename()) return if (!pendingRename()) return
@@ -1993,7 +1994,7 @@ export default function Layout(props: ParentProps) {
"group-focus-within/workspace:opacity-100 group-focus-within/workspace:pointer-events-auto": true, "group-focus-within/workspace:opacity-100 group-focus-within/workspace:pointer-events-auto": true,
}} }}
> >
<DropdownMenu open={menuOpen()} onOpenChange={setMenuOpen}> <DropdownMenu modal={!sidebarHovering()} open={menuOpen()} onOpenChange={setMenuOpen}>
<Tooltip value={language.t("common.moreOptions")} placement="top"> <Tooltip value={language.t("common.moreOptions")} placement="top">
<DropdownMenu.Trigger <DropdownMenu.Trigger
as={IconButton} as={IconButton}
@@ -2003,7 +2004,7 @@ export default function Layout(props: ParentProps) {
aria-label={language.t("common.moreOptions")} aria-label={language.t("common.moreOptions")}
/> />
</Tooltip> </Tooltip>
<DropdownMenu.Portal mount={!props.mobile ? navRef.current : undefined}> <DropdownMenu.Portal mount={!props.mobile ? nav() : undefined}>
<DropdownMenu.Content <DropdownMenu.Content
onCloseAutoFocus={(event) => { onCloseAutoFocus={(event) => {
if (!pendingRename()) return if (!pendingRename()) return
@@ -2411,7 +2412,7 @@ export default function Layout(props: ParentProps) {
</Tooltip> </Tooltip>
</div> </div>
<DropdownMenu> <DropdownMenu modal={!sidebarHovering()}>
<DropdownMenu.Trigger <DropdownMenu.Trigger
as={IconButton} as={IconButton}
icon="dot-grid" icon="dot-grid"
@@ -2419,7 +2420,7 @@ export default function Layout(props: ParentProps) {
class="shrink-0 size-6 rounded-md opacity-0 group-hover/project:opacity-100 data-[expanded]:opacity-100 data-[expanded]:bg-surface-base-active" class="shrink-0 size-6 rounded-md opacity-0 group-hover/project:opacity-100 data-[expanded]:opacity-100 data-[expanded]:bg-surface-base-active"
aria-label={language.t("common.moreOptions")} aria-label={language.t("common.moreOptions")}
/> />
<DropdownMenu.Portal mount={!panelProps.mobile ? navRef.current : undefined}> <DropdownMenu.Portal mount={!panelProps.mobile ? nav() : undefined}>
<DropdownMenu.Content class="mt-1"> <DropdownMenu.Content class="mt-1">
<DropdownMenu.Item onSelect={() => dialog.show(() => <DialogEditProject project={p} />)}> <DropdownMenu.Item onSelect={() => dialog.show(() => <DialogEditProject project={p} />)}>
<DropdownMenu.ItemLabel>{language.t("common.edit")}</DropdownMenu.ItemLabel> <DropdownMenu.ItemLabel>{language.t("common.edit")}</DropdownMenu.ItemLabel>
@@ -2660,7 +2661,7 @@ export default function Layout(props: ParentProps) {
}} }}
style={{ width: layout.sidebar.opened() ? `${Math.max(layout.sidebar.width(), 244)}px` : "64px" }} style={{ width: layout.sidebar.opened() ? `${Math.max(layout.sidebar.width(), 244)}px` : "64px" }}
ref={(el) => { ref={(el) => {
navRef.current = el setNav(el)
}} }}
onMouseLeave={() => { onMouseLeave={() => {
setHoverSession(undefined) setHoverSession(undefined)

View File

@@ -3,19 +3,20 @@ import { ComponentProps, JSXElement, ParentProps, splitProps } from "solid-js"
export interface HoverCardProps extends ParentProps, Omit<ComponentProps<typeof Kobalte>, "children"> { export interface HoverCardProps extends ParentProps, Omit<ComponentProps<typeof Kobalte>, "children"> {
trigger: JSXElement trigger: JSXElement
mount?: HTMLElement
class?: ComponentProps<"div">["class"] class?: ComponentProps<"div">["class"]
classList?: ComponentProps<"div">["classList"] classList?: ComponentProps<"div">["classList"]
} }
export function HoverCard(props: HoverCardProps) { export function HoverCard(props: HoverCardProps) {
const [local, rest] = splitProps(props, ["trigger", "class", "classList", "children"]) const [local, rest] = splitProps(props, ["trigger", "mount", "class", "classList", "children"])
return ( return (
<Kobalte gutter={4} {...rest}> <Kobalte gutter={4} {...rest}>
<Kobalte.Trigger as="div" data-slot="hover-card-trigger"> <Kobalte.Trigger as="div" data-slot="hover-card-trigger">
{local.trigger} {local.trigger}
</Kobalte.Trigger> </Kobalte.Trigger>
<Kobalte.Portal> <Kobalte.Portal mount={local.mount}>
<Kobalte.Content <Kobalte.Content
data-component="hover-card-content" data-component="hover-card-content"
classList={{ classList={{