From 1b7d97a989b5f8101576b3d0e9f0d414f7801553 Mon Sep 17 00:00:00 2001 From: Stefan Lange-Hegermann Date: Wed, 17 Sep 2025 23:17:19 +0200 Subject: [PATCH] library search --- Cable/ComponentLibraryView.swift | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Cable/ComponentLibraryView.swift b/Cable/ComponentLibraryView.swift index b840c8d..662b40b 100644 --- a/Cable/ComponentLibraryView.swift +++ b/Cable/ComponentLibraryView.swift @@ -140,8 +140,9 @@ final class ComponentLibraryViewModel: ObservableObject { struct ComponentLibraryView: View { @Environment(\.dismiss) private var dismiss @StateObject private var viewModel = ComponentLibraryViewModel() + @State private var searchText: String = "" let onSelect: (ComponentLibraryItem) -> Void - + var body: some View { NavigationStack { content @@ -161,6 +162,7 @@ struct ComponentLibraryView: View { .refreshable { await viewModel.refresh() } + .searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search components") } @ViewBuilder @@ -186,21 +188,21 @@ struct ComponentLibraryView: View { } .padding() .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) - } else if viewModel.items.isEmpty { + } else if filteredItems.isEmpty { VStack(spacing: 12) { - Image(systemName: "sparkles.rectangle.stack") + Image(systemName: searchText.isEmpty ? "sparkles.rectangle.stack" : "magnifyingglass") .font(.system(size: 32)) .foregroundColor(.secondary) - Text("No components available") + Text(searchText.isEmpty ? "No components available" : "No matches") .font(.headline) - Text("Check back soon for new loads from VoltPlan.") + Text(searchText.isEmpty ? "Check back soon for new loads from VoltPlan." : "Try searching for a different name.") .font(.caption) .foregroundColor(.secondary) } .padding() .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) } else { - List(viewModel.items) { item in + List(filteredItems) { item in Button { onSelect(item) dismiss() @@ -212,6 +214,15 @@ struct ComponentLibraryView: View { .listStyle(.insetGrouped) } } + + private var filteredItems: [ComponentLibraryItem] { + let trimmedQuery = searchText.trimmingCharacters(in: .whitespacesAndNewlines) + guard !trimmedQuery.isEmpty else { return viewModel.items } + + return viewModel.items.filter { item in + item.name.localizedCaseInsensitiveContains(trimmedQuery) + } + } } private struct ComponentRow: View {