From e5abde729aea1679fbf9568f6f45f22cfd496717 Mon Sep 17 00:00:00 2001 From: kirich1409 Date: Fri, 17 Apr 2026 14:07:16 +0300 Subject: [PATCH] Add project search and filter UI on Welcome Screen Implement search field with magnifying glass icon above project list. Filter projects by name and path (case-insensitive). Show 'No Matching Projects' state when search returns no results. Support clear button to reset search. Both favorites and recent sections are filtered by the same search text. Closes #146. --- MacApp/Relay/Welcome/WelcomeView.swift | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/MacApp/Relay/Welcome/WelcomeView.swift b/MacApp/Relay/Welcome/WelcomeView.swift index 2b5f1e5..5ae6eea 100644 --- a/MacApp/Relay/Welcome/WelcomeView.swift +++ b/MacApp/Relay/Welcome/WelcomeView.swift @@ -80,8 +80,45 @@ struct WelcomeView: View { Divider() + // Search field + HStack(spacing: 8) { + Image(systemName: "magnifyingglass") + .foregroundStyle(.tertiary) + .accessibilityHidden(true) + + TextField( + "Search projects…", + text: Binding( + get: { store.searchText }, + set: { store.send(.searchTextChanged($0)) } + ) + ) + .textFieldStyle(.plain) + .accessibilityLabel("Search projects by name or path") + + if !store.searchText.isEmpty { + Button(action: clearSearch) { + Image(systemName: "xmark.circle.fill") + .foregroundStyle(.tertiary) + } + .buttonStyle(.plain) + .accessibilityLabel("Clear search") + .accessibilityAddTraits(.isButton) + } + } + .padding(.horizontal, 12) + .padding(.vertical, 8) + .background(Color(nsColor: .controlBackgroundColor)) + .cornerRadius(6) + .padding(.horizontal, 16) + .padding(.vertical, 12) + + Divider() + if store.recentProjects.isEmpty { emptyState + } else if store.filteredProjects.isEmpty && !store.searchText.isEmpty { + noSearchResultsState } else { projectsList } @@ -110,6 +147,27 @@ struct WelcomeView: View { .accessibilityLabel("No recent projects. Open a folder to get started.") } + // MARK: - No search results state + + private var noSearchResultsState: some View { + VStack(spacing: 12) { + Spacer() + Image(systemName: "magnifyingglass") + .font(.system(size: 40)) + .foregroundStyle(.tertiary) + .accessibilityHidden(true) + Text("No Matching Projects") + .font(.title3) + .foregroundStyle(.secondary) + Text("Try a different search term.") + .font(.subheadline) + .foregroundStyle(.tertiary) + Spacer() + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .accessibilityLabel("No projects matching your search.") + } + // MARK: - Projects list private var projectsList: some View { @@ -190,6 +248,10 @@ struct WelcomeView: View { private func deleteProject(_ project: ProjectInfo) { store.send(.removeRecent(URL(filePath: project.path))) } + + private func clearSearch() { + store.send(.searchTextChanged("")) + } } // MARK: - RecentProjectRow