Skip to content

Commit 8c88570

Browse files
authored
Merge pull request #989 from austincondiff/tab-ui-improvements
Improved overall tab UI design
2 parents 78bf33e + c9d0bdc commit 8c88570

8 files changed

Lines changed: 220 additions & 116 deletions

File tree

CodeEdit.xcodeproj/project.pbxproj

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -312,11 +312,13 @@
312312
6C48D8F22972DAFC00D6D205 /* Env+IsFullscreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48D8F12972DAFC00D6D205 /* Env+IsFullscreen.swift */; };
313313
6C48D8F42972DB1A00D6D205 /* Env+Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48D8F32972DB1A00D6D205 /* Env+Window.swift */; };
314314
6C48D8F72972E5F300D6D205 /* WindowObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48D8F62972E5F300D6D205 /* WindowObserver.swift */; };
315-
6CDA84AB284C0E4A00C1CC3A /* TabBarItemButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CDA84AA284C0E4A00C1CC3A /* TabBarItemButtonStyle.swift */; };
316315
6CDA84AD284C1BA000C1CC3A /* TabBarContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CDA84AC284C1BA000C1CC3A /* TabBarContextMenu.swift */; };
317316
B62617282964924E00E866AB /* CodeEditKit in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 2801BB89290D5A8E00EBF552 /* CodeEditKit */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
318317
B658FB3427DA9E1000EA4DBD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B658FB3327DA9E1000EA4DBD /* Assets.xcassets */; };
319318
B658FB3727DA9E1000EA4DBD /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B658FB3627DA9E1000EA4DBD /* Preview Assets.xcassets */; };
319+
B6C6A42A297716A500A3D28F /* TabBarItemCloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C6A429297716A500A3D28F /* TabBarItemCloseButton.swift */; };
320+
B6C6A42E29771A8D00A3D28F /* TabBarItemButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C6A42D29771A8D00A3D28F /* TabBarItemButtonStyle.swift */; };
321+
B6C6A43029771F7100A3D28F /* TabBarItemBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C6A42F29771F7100A3D28F /* TabBarItemBackground.swift */; };
320322
B6D7EA592971078500301FAC /* InspectorSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D7EA582971078500301FAC /* InspectorSection.swift */; };
321323
B6D7EA5C297107DD00301FAC /* InspectorField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D7EA5B297107DD00301FAC /* InspectorField.swift */; };
322324
B6EE989027E8879A00CDD8AB /* InspectorSidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EE988F27E8879A00CDD8AB /* InspectorSidebarView.swift */; };
@@ -687,7 +689,6 @@
687689
6C48D8F12972DAFC00D6D205 /* Env+IsFullscreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Env+IsFullscreen.swift"; sourceTree = "<group>"; };
688690
6C48D8F32972DB1A00D6D205 /* Env+Window.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Env+Window.swift"; sourceTree = "<group>"; };
689691
6C48D8F62972E5F300D6D205 /* WindowObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowObserver.swift; sourceTree = "<group>"; };
690-
6CDA84AA284C0E4A00C1CC3A /* TabBarItemButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarItemButtonStyle.swift; sourceTree = "<group>"; };
691692
6CDA84AC284C1BA000C1CC3A /* TabBarContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarContextMenu.swift; sourceTree = "<group>"; };
692693
B658FB2C27DA9E0F00EA4DBD /* CodeEdit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CodeEdit.app; sourceTree = BUILT_PRODUCTS_DIR; };
693694
B658FB3127DA9E0F00EA4DBD /* WorkspaceView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = WorkspaceView.swift; sourceTree = "<group>"; tabWidth = 4; };
@@ -696,6 +697,9 @@
696697
B658FB3827DA9E1000EA4DBD /* CodeEdit.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CodeEdit.entitlements; sourceTree = "<group>"; };
697698
B658FB3D27DA9E1000EA4DBD /* CodeEditTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CodeEditTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
698699
B658FB4727DA9E1000EA4DBD /* CodeEditUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CodeEditUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
700+
B6C6A429297716A500A3D28F /* TabBarItemCloseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarItemCloseButton.swift; sourceTree = "<group>"; };
701+
B6C6A42D29771A8D00A3D28F /* TabBarItemButtonStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarItemButtonStyle.swift; sourceTree = "<group>"; };
702+
B6C6A42F29771F7100A3D28F /* TabBarItemBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarItemBackground.swift; sourceTree = "<group>"; };
699703
B6D7EA582971078500301FAC /* InspectorSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorSection.swift; sourceTree = "<group>"; };
700704
B6D7EA5B297107DD00301FAC /* InspectorField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorField.swift; sourceTree = "<group>"; };
701705
B6EE988F27E8879A00CDD8AB /* InspectorSidebarView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = InspectorSidebarView.swift; sourceTree = "<group>"; tabWidth = 4; };
@@ -1795,12 +1799,14 @@
17951799
children = (
17961800
287776E827E34BC700D46668 /* TabBarView.swift */,
17971801
287776EE27E3515300D46668 /* TabBarItemView.swift */,
1802+
B6C6A429297716A500A3D28F /* TabBarItemCloseButton.swift */,
17981803
6CDA84AC284C1BA000C1CC3A /* TabBarContextMenu.swift */,
1799-
6CDA84AA284C0E4A00C1CC3A /* TabBarItemButtonStyle.swift */,
1804+
B6C6A42D29771A8D00A3D28F /* TabBarItemButtonStyle.swift */,
18001805
DE6F77862813625500D00A76 /* TabBarDivider.swift */,
18011806
DE6405A52817734700881FDF /* TabBarNative.swift */,
18021807
DE513F51281B672D002260B9 /* TabBarAccessory.swift */,
18031808
DE513F53281DE5D0002260B9 /* TabBarXcode.swift */,
1809+
B6C6A42F29771F7100A3D28F /* TabBarItemBackground.swift */,
18041810
);
18051811
path = Views;
18061812
sourceTree = "<group>";
@@ -2605,6 +2611,7 @@
26052611
201169E72837B5CA00F92B46 /* SourceControlModel.swift in Sources */,
26062612
58798265292EC4080085B254 /* ExtensionsStoreAPI.swift in Sources */,
26072613
58822528292C280D00E83CDE /* StatusBarEncodingSelector.swift in Sources */,
2614+
B6C6A43029771F7100A3D28F /* TabBarItemBackground.swift in Sources */,
26082615
58F2EB0F292FB2B0004A9BDE /* PreferencesSection.swift in Sources */,
26092616
587B9E8C29301D8F00AC7927 /* GitHubOpenness.swift in Sources */,
26102617
587B9E8229301D8F00AC7927 /* GitHubPreviewHeader.swift in Sources */,
@@ -2675,6 +2682,7 @@
26752682
58F2EAEE292FB2B0004A9BDE /* TextEditingPreferencesView.swift in Sources */,
26762683
58D01C95293167DC00C5B6B4 /* Bundle+Info.swift in Sources */,
26772684
587D9B762933BF5700BF7490 /* Mocks.swift in Sources */,
2685+
B6C6A42A297716A500A3D28F /* TabBarItemCloseButton.swift in Sources */,
26782686
58A5DF7D2931787A00D1BD5D /* ShellClient.swift in Sources */,
26792687
5879821A292D92370085B254 /* SearchResultModel.swift in Sources */,
26802688
587B9E8929301D8F00AC7927 /* GitHubGist.swift in Sources */,
@@ -2771,6 +2779,7 @@
27712779
587B9E8629301D8F00AC7927 /* GitHubComment.swift in Sources */,
27722780
58F2EAE9292FB2B0004A9BDE /* SourceControlPreferencesView.swift in Sources */,
27732781
587B9E9029301D8F00AC7927 /* BitBucketTokenRouter.swift in Sources */,
2782+
B6C6A42E29771A8D00A3D28F /* TabBarItemButtonStyle.swift in Sources */,
27742783
58822525292C280D00E83CDE /* StatusBarMenuLabel.swift in Sources */,
27752784
58F2EB11292FB2B0004A9BDE /* PreferencesToolbar.swift in Sources */,
27762785
58F2EAF0292FB2B0004A9BDE /* PreviewThemeView.swift in Sources */,
@@ -2790,7 +2799,6 @@
27902799
58F2EAF9292FB2B0004A9BDE /* AccountSelectionDialog.swift in Sources */,
27912800
58F2EAE8292FB2B0004A9BDE /* TerminalPreferencesView.swift in Sources */,
27922801
58AFAA2F2933C69E00482B53 /* TabBarItemID.swift in Sources */,
2793-
6CDA84AB284C0E4A00C1CC3A /* TabBarItemButtonStyle.swift in Sources */,
27942802
28FFE1BF27E3A441001939DB /* NavigatorSidebarToolbarBottom.swift in Sources */,
27952803
58F2EAFA292FB2B0004A9BDE /* GitLabHostedLoginView.swift in Sources */,
27962804
);

CodeEdit/Features/Breadcrumbs/Views/BreadcrumbsView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct BreadcrumbsView: View {
4343
.padding(.horizontal, 10)
4444
}
4545
.frame(height: 28, alignment: .center)
46+
.background(EffectView(.headerView).frame(height: 28))
4647
.onAppear {
4748
fileInfo(self.file)
4849
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//
2+
// TabBarItemBackground.swift
3+
// CodeEdit
4+
//
5+
// Created by Austin Condiff on 1/17/23.
6+
//
7+
8+
import SwiftUI
9+
10+
struct TabBarItemBackground: View {
11+
var isActive: Bool
12+
var isPressing: Bool
13+
var isDragging: Bool
14+
15+
@Environment(\.colorScheme)
16+
private var colorScheme
17+
18+
@Environment(\.controlActiveState)
19+
private var activeState
20+
21+
private var inHoldingState: Bool {
22+
isPressing || isDragging
23+
}
24+
25+
var body: some View {
26+
ZStack {
27+
// Content background (visible if active)
28+
EffectView(.contentBackground)
29+
.opacity(isActive ? 1 : 0)
30+
31+
// Accent color (visible if active)
32+
Color(.controlAccentColor)
33+
.hueRotation(.degrees(-5))
34+
.opacity(
35+
isActive
36+
? colorScheme == .dark
37+
? activeState == .inactive ? 0.22 : inHoldingState ? 0.33 : 0.26
38+
: activeState == .inactive ? 0.1 : inHoldingState ? 0.27 : 0.2
39+
: 0
40+
)
41+
42+
// Highlight (if in dark mode)
43+
Color(.white)
44+
.blendMode(.plusLighter)
45+
.opacity(
46+
colorScheme == .dark
47+
? isActive
48+
? activeState == .inactive ? 0.04 : inHoldingState ? 0.14 : 0.09
49+
: isPressing ? 0.05 : 0
50+
: 0
51+
)
52+
53+
// Dragging color (if not active)
54+
Color(.unemphasizedSelectedTextBackgroundColor)
55+
.opacity(isDragging && !isActive ? 0.85 : 0)
56+
}
57+
}
58+
}
59+
60+
struct TabBarItemBackground_Previews: PreviewProvider {
61+
static var previews: some View {
62+
TabBarItemBackground(isActive: false, isPressing: false, isDragging: false)
63+
}
64+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//
2+
// TabBarItemCloseButton.swift
3+
// CodeEdit
4+
//
5+
// Created by Austin Condiff on 1/17/23.
6+
//
7+
8+
import SwiftUI
9+
10+
struct TabBarItemCloseButton: View {
11+
var isActive: Bool
12+
var isHoveringTab: Bool
13+
var isDragging: Bool
14+
var closeAction: () -> Void
15+
16+
@Binding
17+
var closeButtonGestureActive: Bool
18+
19+
@Environment(\.colorScheme)
20+
var colorScheme
21+
22+
@StateObject
23+
private var prefs: AppPreferencesModel = .shared
24+
25+
@State
26+
private var isPressingClose: Bool = false
27+
28+
@State
29+
private var isHoveringClose: Bool = false
30+
31+
let buttonSize: CGFloat = 16
32+
33+
var body: some View {
34+
HStack {
35+
if prefs.preferences.general.tabBarStyle == .xcode {
36+
Image(systemName: "xmark")
37+
.font(.system(size: 11.5, weight: .regular, design: .rounded))
38+
.foregroundColor(
39+
isActive
40+
? colorScheme == .dark ? .primary : Color(.controlAccentColor)
41+
: .secondary
42+
)
43+
.padding(.top, -0.5)
44+
} else {
45+
Image(systemName: "xmark")
46+
.font(.system(size: 9.5, weight: .medium, design: .rounded))
47+
}
48+
}
49+
.frame(width: buttonSize, height: buttonSize)
50+
.background(
51+
colorScheme == .dark
52+
? Color(nsColor: .white)
53+
.opacity(isPressingClose ? 0.10 : isHoveringClose ? 0.05 : 0)
54+
: (
55+
prefs.preferences.general.tabBarStyle == .xcode
56+
? Color(nsColor: isActive ? .controlAccentColor : .black)
57+
.opacity(
58+
isPressingClose
59+
? 0.25
60+
: (isHoveringClose ? (isActive ? 0.10 : 0.06) : 0)
61+
)
62+
: Color(nsColor: .black)
63+
.opacity(isPressingClose ? 0.29 : (isHoveringClose ? 0.11 : 0))
64+
)
65+
)
66+
.foregroundColor(isPressingClose ? .primary : .secondary)
67+
.cornerRadius(2)
68+
.contentShape(Rectangle())
69+
.gesture(
70+
DragGesture(minimumDistance: 0)
71+
.onChanged({ _ in
72+
isPressingClose = true
73+
closeButtonGestureActive = true
74+
})
75+
.onEnded({ value in
76+
if value.location.x > 0
77+
&& value.location.x < buttonSize
78+
&& value.location.y > 0
79+
&& value.location.y < buttonSize {
80+
closeAction()
81+
}
82+
isPressingClose = false
83+
closeButtonGestureActive = false
84+
})
85+
)
86+
.onHover { hover in
87+
isHoveringClose = hover
88+
}
89+
.accessibilityLabel(Text("Close"))
90+
// Only show when the mouse is hovering and there is no tab dragging.
91+
.opacity(isHoveringTab && !isDragging ? 1 : 0)
92+
.animation(.easeInOut(duration: 0.08), value: isHoveringTab)
93+
.padding(.leading, 4)
94+
}
95+
}
96+
97+
struct TabBarItemCloseButton_Previews: PreviewProvider {
98+
@State static var closeButtonGestureActive = true
99+
100+
static var previews: some View {
101+
TabBarItemCloseButton(
102+
isActive: false,
103+
isHoveringTab: false,
104+
isDragging: false,
105+
closeAction: { print("Close tab") },
106+
closeButtonGestureActive: $closeButtonGestureActive
107+
)
108+
}
109+
}

0 commit comments

Comments
 (0)