Skip to content

Commit d26af96

Browse files
committed
Create New Pane Filter Style
1 parent f97b089 commit d26af96

6 files changed

Lines changed: 258 additions & 133 deletions

File tree

CodeEdit/Features/CodeEditUI/Views/PaneTextField.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ struct PaneTextField<LeadingAccessories: View, TrailingAccessories: View>: View
122122
.disabled(true)
123123
.edgesIgnoringSafeArea(.all)
124124
)
125-
126125
.onTapGesture {
127126
isFocused = true
128127
}

CodeEdit/Features/NavigatorArea/FindNavigator/FindNavigatorToolbarBottom.swift

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,24 @@ struct FindNavigatorToolbarBottom: View {
1111
@State private var text = ""
1212

1313
var body: some View {
14-
HStack(spacing: 2) {
15-
PaneTextField(
16-
"Filter",
17-
text: $text,
18-
leadingAccessories: {
19-
Image(
20-
systemName: text.isEmpty
21-
? "line.3.horizontal.decrease.circle"
22-
: "line.3.horizontal.decrease.circle.fill"
23-
)
24-
.foregroundStyle(
25-
text.isEmpty
26-
? Color(nsColor: .secondaryLabelColor)
27-
: Color(nsColor: .controlAccentColor)
28-
)
29-
.padding(.leading, 4)
30-
.help("Show results with matching text")
31-
},
32-
clearable: true
33-
)
34-
}
35-
.frame(height: 28, alignment: .center)
36-
.frame(maxWidth: .infinity)
37-
.padding(.horizontal, 5)
38-
.overlay(alignment: .top) {
39-
Divider()
40-
.opacity(0)
41-
}
14+
NavigatorFilterView(
15+
text: $text,
16+
menu: { EmptyView() },
17+
leadingAccessories: {
18+
Image(
19+
systemName: text.isEmpty
20+
? "line.3.horizontal.decrease.circle"
21+
: "line.3.horizontal.decrease.circle.fill"
22+
)
23+
.foregroundStyle(
24+
text.isEmpty
25+
? Color(nsColor: .secondaryLabelColor)
26+
: Color(nsColor: .controlAccentColor)
27+
)
28+
.padding(.leading, 4)
29+
.help("Show results with matching text")
30+
},
31+
trailingAccessories: { EmptyView() }
32+
)
4233
}
4334
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// FilterDropDownIconButton.swift
3+
// CodeEdit
4+
//
5+
// Created by Khan Winter on 9/2/25.
6+
//
7+
8+
import SwiftUI
9+
10+
struct FilterDropDownIconButton<MenuView: View>: View {
11+
@Environment(\.controlActiveState)
12+
private var activeState
13+
14+
var menu: () -> MenuView
15+
16+
var isOn: Bool?
17+
18+
var body: some View {
19+
Menu { menu() } label: {}
20+
.background {
21+
if isOn == true {
22+
Image(ImageResource.line3HorizontalDecreaseChevronFilled)
23+
.foregroundStyle(.tint)
24+
} else {
25+
Image(ImageResource.line3HorizontalDecreaseChevron)
26+
}
27+
}
28+
.menuStyle(.borderlessButton)
29+
.menuIndicator(.hidden)
30+
.frame(width: 26, height: 13)
31+
.clipShape(.rect(cornerRadius: 6.5))
32+
}
33+
}

CodeEdit/Features/NavigatorArea/ProjectNavigator/ProjectNavigatorToolbarBottom.swift

Lines changed: 43 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -20,56 +20,50 @@ struct ProjectNavigatorToolbarBottom: View {
2020
@State var recentsFilter: Bool = false
2121

2222
var body: some View {
23-
HStack(spacing: 5) {
24-
addNewFileButton
25-
PaneTextField(
26-
"Filter",
27-
text: $workspace.navigatorFilter,
28-
leadingAccessories: {
29-
FilterDropDownIconButton(menu: {
30-
ForEach([(true, "Folders on top"), (false, "Alphabetically")], id: \.0) { value, title in
31-
Toggle(title, isOn: Binding(get: {
32-
workspace.sortFoldersOnTop == value
33-
}, set: { _ in
34-
// Avoid calling the handleFilterChange method
35-
if workspace.sortFoldersOnTop != value {
36-
workspace.sortFoldersOnTop = value
37-
}
38-
}))
39-
}
40-
}, isOn: !workspace.navigatorFilter.isEmpty)
41-
.padding(.leading, 4)
42-
.foregroundStyle(
43-
workspace.navigatorFilter.isEmpty
44-
? Color(nsColor: .secondaryLabelColor)
45-
: Color(nsColor: .controlAccentColor)
46-
)
47-
.help("Show files with matching name")
48-
},
49-
trailingAccessories: {
50-
HStack(spacing: 0) {
51-
Toggle(isOn: $recentsFilter) {
52-
Image(systemName: "clock")
53-
}
54-
.help("Show only recent files")
55-
Toggle(isOn: $workspace.sourceControlFilter) {
56-
Image(systemName: "plusminus.circle")
57-
}
58-
.help("Show only files with source-control status")
23+
NavigatorFilterView(
24+
text: $workspace.navigatorFilter,
25+
hasValue: { !workspace.navigatorFilter.isEmpty || recentsFilter || workspace.sourceControlFilter },
26+
menu: { addNewFileButton },
27+
leadingAccessories: { leadingAccessories },
28+
trailingAccessories: { trailingAccessories }
29+
)
30+
}
31+
32+
@ViewBuilder private var leadingAccessories: some View {
33+
FilterDropDownIconButton(menu: {
34+
ForEach([(true, "Folders on top"), (false, "Alphabetically")], id: \.0) { value, title in
35+
Toggle(title, isOn: Binding(get: {
36+
workspace.sortFoldersOnTop == value
37+
}, set: { _ in
38+
// Avoid calling the handleFilterChange method
39+
if workspace.sortFoldersOnTop != value {
40+
workspace.sortFoldersOnTop = value
5941
}
60-
.toggleStyle(.icon(font: .system(size: 14), size: CGSize(width: 18, height: 20)))
61-
.padding(.trailing, 2.5)
62-
},
63-
clearable: true,
64-
hasValue: !workspace.navigatorFilter.isEmpty || recentsFilter || workspace.sourceControlFilter
65-
)
66-
}
67-
.padding(.horizontal, 5)
68-
.frame(height: 28, alignment: .center)
69-
.frame(maxWidth: .infinity)
70-
.overlay(alignment: .top) {
71-
Divider()
42+
}))
43+
}
44+
}, isOn: !workspace.navigatorFilter.isEmpty)
45+
.padding(.leading, 4)
46+
.foregroundStyle(
47+
workspace.navigatorFilter.isEmpty
48+
? Color(nsColor: .secondaryLabelColor)
49+
: Color(nsColor: .controlAccentColor)
50+
)
51+
.help("Show files with matching name")
52+
}
53+
54+
@ViewBuilder private var trailingAccessories: some View {
55+
HStack(spacing: 0) {
56+
Toggle(isOn: $recentsFilter) {
57+
Image(systemName: "clock")
58+
}
59+
.help("Show only recent files")
60+
Toggle(isOn: $workspace.sourceControlFilter) {
61+
Image(systemName: "plusminus.circle")
62+
}
63+
.help("Show only files with source-control status")
7264
}
65+
.toggleStyle(.icon(font: .system(size: 14), size: CGSize(width: 18, height: 20)))
66+
.padding(.trailing, 2.5)
7367
}
7468

7569
/// Retrieves the active tab URL from the underlying editor instance, if theres no
@@ -96,7 +90,7 @@ struct ProjectNavigatorToolbarBottom: View {
9690
return workspace.workspaceFileManager.unsafelyUnwrapped.folderUrl
9791
}
9892

99-
private var addNewFileButton: some View {
93+
@ViewBuilder private var addNewFileButton: some View {
10094
Menu {
10195
Button("Add File") {
10296
let filePathURL = activeTabURL()
@@ -159,28 +153,3 @@ struct ProjectNavigatorToolbarBottom: View {
159153
.opacity(activeState == .inactive ? 0.45 : 1)
160154
}
161155
}
162-
163-
struct FilterDropDownIconButton<MenuView: View>: View {
164-
@Environment(\.controlActiveState)
165-
private var activeState
166-
167-
var menu: () -> MenuView
168-
169-
var isOn: Bool?
170-
171-
var body: some View {
172-
Menu { menu() } label: {}
173-
.background {
174-
if isOn == true {
175-
Image(ImageResource.line3HorizontalDecreaseChevronFilled)
176-
.foregroundStyle(.tint)
177-
} else {
178-
Image(ImageResource.line3HorizontalDecreaseChevron)
179-
}
180-
}
181-
.menuStyle(.borderlessButton)
182-
.menuIndicator(.hidden)
183-
.frame(width: 26, height: 13)
184-
.clipShape(.rect(cornerRadius: 6.5))
185-
}
186-
}

CodeEdit/Features/NavigatorArea/SourceControlNavigator/Views/SourceControlNavigatorToolbarBottom.swift

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,38 +14,30 @@ struct SourceControlNavigatorToolbarBottom: View {
1414
@State private var text = ""
1515

1616
var body: some View {
17-
HStack(spacing: 5) {
18-
sourceControlMenu
19-
PaneTextField(
20-
"Filter",
21-
text: $text,
22-
leadingAccessories: {
23-
Image(
24-
systemName: text.isEmpty
25-
? "line.3.horizontal.decrease.circle"
26-
: "line.3.horizontal.decrease.circle.fill"
27-
)
28-
.foregroundStyle(
29-
text.isEmpty
30-
? Color(nsColor: .secondaryLabelColor)
31-
: Color(nsColor: .controlAccentColor)
32-
)
33-
.padding(.leading, 4)
34-
.help("Filter Changes Navigator")
35-
},
36-
clearable: true
37-
)
38-
}
39-
.frame(height: 28, alignment: .center)
40-
.frame(maxWidth: .infinity)
41-
.padding(.horizontal, 5)
42-
.overlay(alignment: .top) {
43-
Divider()
44-
.opacity(0)
45-
}
17+
NavigatorFilterView(
18+
text: $text,
19+
menu: { sourceControlMenu },
20+
leadingAccessories: { leadingAccessories },
21+
trailingAccessories: { EmptyView() }
22+
)
23+
}
24+
25+
@ViewBuilder private var leadingAccessories: some View {
26+
Image(
27+
systemName: text.isEmpty
28+
? "line.3.horizontal.decrease.circle"
29+
: "line.3.horizontal.decrease.circle.fill"
30+
)
31+
.foregroundStyle(
32+
text.isEmpty
33+
? Color(nsColor: .secondaryLabelColor)
34+
: Color(nsColor: .controlAccentColor)
35+
)
36+
.padding(.leading, 4)
37+
.help("Filter Changes Navigator")
4638
}
4739

48-
private var sourceControlMenu: some View {
40+
@ViewBuilder private var sourceControlMenu: some View {
4941
Menu {
5042
Button("Discard All Changes...") {
5143
if sourceControlManager.changedFiles.isEmpty {

0 commit comments

Comments
 (0)