Ariver
2026-05-29 1797e722aa5453f646187ab61483f70f7e19fd1f
Apptag/ContentView.swift
@@ -664,7 +664,7 @@
                    }
                    .zIndex(899)
                QuickSearchOverlayView(
                QuickSearchPanelPresentationView(
                    query: $quickSearchQuery,
                    results: quickSearchResults,
                    selectedID: quickSearchSelectedID,
@@ -672,16 +672,15 @@
                    selectionScrollToken: quickSearchSelectionScrollToken,
                    isLoading: quickSearchDocuments.isEmpty && refreshInProgress,
                    maxVisibleRows: quickSearchMaxVisibleRows(in: proxy.size),
                    panelTopY: quickSearchPanelTopY(in: proxy.size),
                    panelHeight: quickSearchPanelContentHeight(in: proxy.size),
                    errorMessage: quickSearchErrorMessage,
                    onCommand: handleQuickSearchCommand,
                    onHover: selectQuickSearchResult,
                    onLaunch: launchQuickSearchResult
                )
                .position(
                    x: proxy.size.width / 2,
                    y: quickSearchPanelCenterY(in: proxy.size)
                )
                .transition(.scale(scale: 0.98).combined(with: .opacity))
                .frame(width: 0, height: 0)
                .allowsHitTesting(false)
                .zIndex(900)
            }
        }
@@ -689,10 +688,15 @@
        .animation(.easeOut(duration: 0.12), value: quickSearchVisible)
    }
    private func quickSearchPanelCenterY(in size: CGSize) -> CGFloat {
        let visibleRows = max(1, min(quickSearchResults.isEmpty ? 1 : quickSearchResults.count, quickSearchMaxVisibleRows(in: size)))
        let estimatedPanelHeight = CGFloat(visibleRows) * 76 + 122
        return quickSearchPanelTopY(in: size) + estimatedPanelHeight / 2
    private func quickSearchPanelContentHeight(in size: CGSize) -> CGFloat {
        let hasResultList = !(quickSearchDocuments.isEmpty && refreshInProgress)
            && quickSearchErrorMessage == nil
            && !quickSearchResults.isEmpty
        let visibleRows = min(max(1, quickSearchResults.count), quickSearchMaxVisibleRows(in: size))
        return QuickSearchPanelMetrics.contentHeight(
            hasResultList: hasResultList,
            visibleRows: visibleRows
        )
    }
    private func quickSearchPanelTopY(in size: CGSize) -> CGFloat {
@@ -701,8 +705,11 @@
    private func quickSearchMaxVisibleRows(in size: CGSize) -> Int {
        let bottomClearance: CGFloat = 84
        let chromeHeight: CGFloat = 122
        let rowHeightWithSpacing: CGFloat = 76
        let chromeHeight = QuickSearchPanelMetrics.headerHeight
            + QuickSearchPanelMetrics.dividerHeight
            + QuickSearchPanelMetrics.resultListVerticalInset * 2
        let rowHeightWithSpacing = QuickSearchPanelMetrics.rowHeight
            + QuickSearchPanelMetrics.rowSpacing
        let availableHeight = max(0, size.height - quickSearchPanelTopY(in: size) - bottomClearance - chromeHeight)
        return max(1, min(8, Int(floor(availableHeight / rowHeightWithSpacing))))
    }
@@ -934,11 +941,25 @@
            contentInsets: isHorizontal
                ? NSEdgeInsets(top: 3, left: 24, bottom: 3, right: tagPosition == "top" ? floatingControlsReservedWidth : 24)
                : NSEdgeInsets(top: 12, left: 12, bottom: 12, right: 12),
            dragModeActive: tagNavDragModeActive,
            draggingItemID: tagNavDragItem,
            onActivate: { tagID in
                activateTagNavigation(tagID)
            },
            onHoverChange: { tagID, active in
                handleTagNavigationHover(tagID, active: active)
            },
            canReorder: { tagID in
                canReorderTag(tagID)
            },
            onReorderBegan: { tagID in
                beginTagNavReorder(tagID)
            },
            onReorderMoved: { tagID, targetID in
                reorderTagNavItem(fromName: tagID, to: targetID)
            },
            onReorderEnded: {
                endTagNavReorder()
            }
        )
    }
@@ -2054,11 +2075,18 @@
    private func reorderTagNavItem(at location: CGPoint) {
        guard let fromName = tagNavDragItem,
              let targetName = tagNavReorderFrames.first(where: { $0.value.contains(location) })?.key,
              fromName != targetName,
              fromName != targetName
        else { return }
        reorderTagNavItem(fromName: fromName, to: targetName)
    }
    private func reorderTagNavItem(fromName: String, to targetName: String) {
        guard fromName != targetName,
              canReorderTag(fromName),
              canReorderTag(targetName),
              let fromIndex = draggedTagNames.firstIndex(of: fromName),
              let toIndex = draggedTagNames.firstIndex(of: targetName)
        else { return }
        tagNavReorderDidMove = true
        withAnimation(.spring(response: 0.22, dampingFraction: 0.82)) {
            let destination = toIndex > fromIndex ? toIndex + 1 : toIndex