// Collapsed-sidebar folder flyout. When the sidebar is in the Colapsado // (mini) state, clicking a folder opens this popup to its right, listing the // folder's playlists (max 4 rows visible; a scrollbar appears beyond four). // Mirrors Tauri's collapsed folder popover. Rendered at the AppShell level // because the sidebar clips its own overflow. import { Theme } from "../foundation/semantic-colors.slint"; import { Radius } from "../foundation/radius.slint"; import { QbzIcon } from "../primitives/QbzIcon.slint"; import { ListScrollbar } from "../primitives/ListScrollbar.slint"; import { SidebarFolderPopupState, SidebarActions, SidebarEntry } from "../state.slint"; // One playlist row inside the popup. component FpRow inherits Rectangle { in property entry; callback clicked(); height: 32px; border-radius: 5px; background: ta.has-hover ? Theme.surface-hover : transparent; HorizontalLayout { padding-left: 12px; padding-right: 12px; spacing: 8px; VerticalLayout { alignment: center; QbzIcon { source: @image-url("../assets/icons/list-music.svg"); width: 14px; height: 14px; tint: Theme.text-muted; } } Text { text: root.entry.name; color: Theme.text-secondary; font-size: 13px; vertical-alignment: center; horizontal-stretch: 1; overflow: elide; } } ta := TouchArea { mouse-cursor: pointer; clicked => { root.clicked(); } } } export component SidebarFolderPopup inherits Rectangle { visible: SidebarFolderPopupState.open; property row-h: 32px; property visible-rows: Math.min(SidebarFolderPopupState.count, 4); property list-h: root.visible-rows * root.row-h; // Scrim — a click anywhere outside the panel closes the popup. if SidebarFolderPopupState.open: TouchArea { clicked => { SidebarFolderPopupState.open = false; } } if SidebarFolderPopupState.open: Rectangle { x: SidebarFolderPopupState.anchor-x; y: SidebarFolderPopupState.anchor-y; width: 230px; height: 34px + 1px + root.list-h + 8px; Rectangle { background: Theme.surface-main; border-radius: Radius.sm; border-width: 1px; border-color: Theme.border-muted; drop-shadow-blur: 24px; drop-shadow-color: Theme.card-shadow; drop-shadow-offset-y: 6px; // Swallow clicks so the scrim doesn't close while interacting. TouchArea { } VerticalLayout { padding-top: 4px; padding-bottom: 4px; // Header — folder name. HorizontalLayout { height: 30px; padding-left: 12px; padding-right: 12px; spacing: 8px; VerticalLayout { alignment: center; QbzIcon { source: @image-url("../assets/icons/folder-open.svg"); width: 14px; height: 14px; tint: Theme.accent; } } Text { text: SidebarFolderPopupState.folder-name; color: Theme.text-primary; font-size: 13px; font-weight: 600; vertical-alignment: center; horizontal-stretch: 1; overflow: elide; } } Rectangle { height: 1px; background: Theme.border-subtle; } // Playlist list — capped at four rows; scrolls beyond that. Rectangle { height: root.list-h; fp-flick := Flickable { width: 100%; height: 100%; viewport-width: self.width; viewport-height: SidebarFolderPopupState.count * root.row-h; VerticalLayout { width: parent.width; alignment: start; for entry in SidebarFolderPopupState.playlists: FpRow { entry: entry; clicked => { SidebarActions.open-playlist(entry.id); SidebarFolderPopupState.open = false; } } } } if SidebarFolderPopupState.count > 4: ListScrollbar { x: parent.width - self.width; width: 10px; height: 100%; viewport-height: fp-flick.viewport-height; visible-height: fp-flick.height; viewport-y <=> fp-flick.viewport-y; } } } } } }