| | |
| | | var showNames: Bool = true |
| | | var dragModeActive: Bool = false |
| | | var onDragModeChange: ((Bool) -> Void)? = nil |
| | | var onBubbleHover: ((AppInfo, CGRect, AppBubbleHoverEvent) -> Void)? = nil |
| | | var onEditNote: ((AppInfo, CGRect) -> Void)? = nil |
| | | var bubbleDisabled: Bool = false |
| | | var dragResetToken: Int = 0 |
| | | @Binding var hoveredAppItemID: String? |
| | | var onDropApp: ((String, String, Bool) -> Void)? = nil |
| | | |
| | | /// Adaptive columns — auto-fit based on icon size and available width. |
| | | private var columns: [GridItem] { |
| | | [GridItem(.adaptive(minimum: iconSize + 28, maximum: iconSize + 64), spacing: 6)] |
| | | let itemWidth = AppGridItem.stableWidth(iconSize: iconSize) |
| | | return [GridItem(.adaptive(minimum: itemWidth, maximum: itemWidth + 36), spacing: 6)] |
| | | } |
| | | |
| | | // Subtle separator line color — adapts to light/dark mode |
| | |
| | | sourceTag: group.name, |
| | | dragModeActive: dragModeActive, |
| | | onDragModeChange: onDragModeChange, |
| | | onBubbleHover: onBubbleHover, |
| | | onEditNote: onEditNote, |
| | | bubbleDisabled: bubbleDisabled, |
| | | itemID: "\(group.name)|\(app.path.path)", |
| | | dragResetToken: dragResetToken, |
| | | hoveredAppItemID: $hoveredAppItemID, |
| | | onSelect: { onSelectApp(app) } |
| | | ) |
| | | } |