Skip to content
Merged
4 changes: 4 additions & 0 deletions CodeEdit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
D7E201B227E8D50000CB86D0 /* FindNavigatorModeSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E201B127E8D50000CB86D0 /* FindNavigatorModeSelector.swift */; };
D7E201BD27EA00E200CB86D0 /* FindNavigatorResultFileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E201BC27EA00E200CB86D0 /* FindNavigatorResultFileItem.swift */; };
D7F72DEB27EA3574000C3064 /* Search in Frameworks */ = {isa = PBXBuildFile; productRef = D7F72DEA27EA3574000C3064 /* Search */; };
DE6F77872813625500D00A76 /* TabBarDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6F77862813625500D00A76 /* TabBarDivider.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -175,6 +176,7 @@
D7E201B127E8D50000CB86D0 /* FindNavigatorModeSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindNavigatorModeSelector.swift; sourceTree = "<group>"; };
D7E201B327E9989900CB86D0 /* FindNavigatorResultList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindNavigatorResultList.swift; sourceTree = "<group>"; };
D7E201BC27EA00E200CB86D0 /* FindNavigatorResultFileItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindNavigatorResultFileItem.swift; sourceTree = "<group>"; };
DE6F77862813625500D00A76 /* TabBarDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarDivider.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -347,6 +349,7 @@
children = (
287776E827E34BC700D46668 /* TabBar.swift */,
287776EE27E3515300D46668 /* TabBarItem.swift */,
DE6F77862813625500D00A76 /* TabBarDivider.swift */,
);
path = TabBar;
sourceTree = "<group>";
Expand Down Expand Up @@ -703,6 +706,7 @@
20EBB507280C32D300F3A5DA /* QuickHelpInspector.swift in Sources */,
04C3255C2801F86900C8DA2D /* OutlineMenu.swift in Sources */,
04540D5E27DD08C300E91B77 /* WorkspaceView.swift in Sources */,
DE6F77872813625500D00A76 /* TabBarDivider.swift in Sources */,
D7211D4327E066CE008F2ED7 /* Localized+Ex.swift in Sources */,
20D839AE280E0CA700B27357 /* PopoverView.swift in Sources */,
2072FA1E280D891500C7F8D4 /* Location.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions CodeEdit/Documents/WorkspaceCodeFileView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct WorkspaceCodeFileView: View {
TabBar(windowController: windowController, workspace: workspace)
TabBarBottomDivider()
BreadcrumbsView(file: item, tappedOpenFile: workspace.openFile(item:))
Divider()
}
}
} else {
Expand Down
14 changes: 7 additions & 7 deletions CodeEdit/TabBar/TabBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ struct TabBar: View {
@Environment(\.colorScheme)
var colorScheme

@Environment(\.controlActiveState)
private var activeState

var windowController: NSWindowController

@ObservedObject
Expand Down Expand Up @@ -47,6 +50,7 @@ struct TabBar: View {
.buttonStyle(.plain)
}
.padding(.horizontal, 11)
.opacity(activeState != .inactive ? 1.0 : 0.5)
// Tab bar items.
ScrollView(.horizontal, showsIndicators: false) {
ScrollViewReader { value in
Expand All @@ -67,25 +71,21 @@ struct TabBar: View {
// TODO: Tab bar tools (e.g. split view).
}
.frame(height: tabBarHeight)
.overlay {
.overlay(alignment: .top) {
// When tab bar style is `xcode`, we put the top divider as an overlay.
if prefs.preferences.general.tabBarStyle == .xcode {
TabBarTopDivider()
.frame(height: tabBarHeight, alignment: .top)
}
}
.background {
if prefs.preferences.general.tabBarStyle == .xcode {
Color(nsColor: .controlBackgroundColor)
} else {
ZStack {
ZStack(alignment: .top) {
Color(nsColor: .black)
.opacity(colorScheme == .dark ? 0.50 : 0.05)
// Set padding top to 1 to avoid color-overlapping.
.padding(.top, 1)
.opacity(colorScheme == .dark ? 0.45 : 0.05)
// When tab bar style is `native`, we put the top divider beneath tabs.
TabBarTopDivider()
.frame(height: tabBarHeight, alignment: .top)
}
}
}
Expand Down
104 changes: 104 additions & 0 deletions CodeEdit/TabBar/TabBarDivider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//
// TabBarDivider.swift
// CodeEdit
//
// Created by Lingxi Li on 4/22/22.
//

import SwiftUI
import AppPreferences
import CodeEditUI

/// The vertical divider between tab bar items.
struct TabDivider: View {
@Environment(\.colorScheme)
var colorScheme

@StateObject
private var prefs: AppPreferencesModel = .shared

let width: CGFloat = 1

var body: some View {
Rectangle()
.frame(width: width)
.padding(.vertical, prefs.preferences.general.tabBarStyle == .xcode ? 8 : 0)
.foregroundColor(
prefs.preferences.general.tabBarStyle == .xcode
? Color(nsColor: colorScheme == .dark ? .white : .black)
.opacity(0.12)
: Color(nsColor: colorScheme == .dark ? .white : .black)
.opacity(colorScheme == .dark ? 0.08 : 0.12)
)
}
}

/// The top border for tab bar (between tab bar and titlebar).
struct TabBarTopDivider: View {
@Environment(\.colorScheme)
var colorScheme

@StateObject
private var prefs: AppPreferencesModel = .shared

var body: some View {
ZStack(alignment: .top) {
Color(nsColor: .black)
.opacity(
prefs.preferences.general.tabBarStyle == .xcode
? (colorScheme == .dark ? 0.29 : 0.11)
: (colorScheme == .dark ? 0.80 : 0.02)
)
.frame(height: prefs.preferences.general.tabBarStyle == .xcode ? 1.0 : 0.8)
// Shadow of top divider in native style.
if prefs.preferences.general.tabBarStyle == .native {
TabBarNativeShadow()
}
}
}
}

/// The bottom border for tab bar (between tab bar and breadcrumbs).
struct TabBarBottomDivider: View {
@Environment(\.colorScheme)
var colorScheme

@StateObject
private var prefs: AppPreferencesModel = .shared

var body: some View {
Rectangle()
.foregroundColor(
prefs.preferences.general.tabBarStyle == .xcode
? Color(nsColor: .separatorColor)
.opacity(colorScheme == .dark ? 0.40 : 0.45)
: Color(nsColor: .black)
.opacity(colorScheme == .dark ? 0.65 : 0.09)

)
.frame(height: prefs.preferences.general.tabBarStyle == .xcode ? 1.0 : 0.8)
}
}

/// The divider shadow for native tab bar style.
///
/// This is generally used in the top divider of tab bar when tab bar style is set to `native`.
struct TabBarNativeShadow: View {
let shadowColor = Color(nsColor: .shadowColor)

var body: some View {
LinearGradient(
colors: [
shadowColor.opacity(0.18),
shadowColor.opacity(0.06),
shadowColor.opacity(0.03),
shadowColor.opacity(0.01),
shadowColor.opacity(0)
],
startPoint: .top,
endPoint: .bottom
)
.frame(height: 3.8)
.opacity(0.70)
}
}
107 changes: 28 additions & 79 deletions CodeEdit/TabBar/TabBarItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,78 +10,13 @@ import WorkspaceClient
import AppPreferences
import CodeEditUI

/// The vertical divider between tab bar items.
struct TabDivider: View {
@Environment(\.colorScheme)
var colorScheme

@StateObject
private var prefs: AppPreferencesModel = .shared

let width: CGFloat = 1

var body: some View {
Rectangle()
.frame(width: width)
.padding(.vertical, prefs.preferences.general.tabBarStyle == .xcode ? 8 : 0)
.foregroundColor(
prefs.preferences.general.tabBarStyle == .xcode
? Color(nsColor: colorScheme == .dark ? .white : .black)
.opacity(0.12)
: Color(nsColor: colorScheme == .dark ? .white : .black)
.opacity(colorScheme == .dark ? 0.08 : 0.12)
)
}
}

/// The top border for tab bar (between tab bar and titlebar).
struct TabBarTopDivider: View {
@Environment(\.colorScheme)
var colorScheme

@StateObject
private var prefs: AppPreferencesModel = .shared

var body: some View {
Rectangle()
.foregroundColor(
Color(nsColor: .black)
.opacity(
prefs.preferences.general.tabBarStyle == .xcode
? (colorScheme == .dark ? 0.29 : 0.11)
: (colorScheme == .dark ? 0.80 : 0.15)
)
)
.frame(height: prefs.preferences.general.tabBarStyle == .xcode ? 1.0 : 0.8)
}
}

/// The bottom border for tab bar (between tab bar and breadcrumbs).
struct TabBarBottomDivider: View {
@Environment(\.colorScheme)
var colorScheme

@StateObject
private var prefs: AppPreferencesModel = .shared

var body: some View {
Rectangle()
.foregroundColor(
prefs.preferences.general.tabBarStyle == .xcode
? Color(nsColor: .separatorColor)
.opacity(colorScheme == .dark ? 0.40 : 0.45)
: Color(nsColor: .black)
.opacity(colorScheme == .dark ? 0.65 : 0.09)

)
.frame(height: prefs.preferences.general.tabBarStyle == .xcode ? 1.0 : 0.8)
}
}

struct TabBarItem: View {
@Environment(\.colorScheme)
var colorScheme

@Environment(\.controlActiveState)
private var activeState

@StateObject
private var prefs: AppPreferencesModel = .shared

Expand Down Expand Up @@ -132,7 +67,9 @@ struct TabBarItem: View {
.resizable()
.aspectRatio(contentMode: .fit)
.foregroundColor(
prefs.preferences.general.fileIconStyle == .color ? item.iconColor : .secondary
prefs.preferences.general.fileIconStyle == .color && activeState != .inactive
? item.iconColor
: .secondary
)
.frame(width: 12, height: 12)
Text(item.url.lastPathComponent)
Expand Down Expand Up @@ -231,18 +168,27 @@ struct TabBarItem: View {
}
.frame(maxWidth: .infinity, alignment: .leading)
}
.overlay {
// Only show NativeTabShadow when `tabBarStyle` is native and this tab is not active.
if prefs.preferences.general.tabBarStyle == .native && !isActive {
TabBarTopDivider()
.frame(maxHeight: .infinity, alignment: .top)
}
}
.opacity(
// Inactive states for tab bar item content.
activeState != .inactive
? 1.0
: (
isActive
? (prefs.preferences.general.tabBarStyle == .xcode ? 0.6 : 0.35)
: (prefs.preferences.general.tabBarStyle == .xcode ? 0.4 : 0.55)
)
)
TabDivider()
.opacity(
isActive && prefs.preferences.general.tabBarStyle == .xcode ? 0.0 : 1.0
)
}
.overlay(alignment: .top) {
// Only show NativeTabShadow when `tabBarStyle` is native and this tab is not active.
if prefs.preferences.general.tabBarStyle == .native && !isActive {
TabBarTopDivider()
}
}
.foregroundColor(
isActive
? (
Expand Down Expand Up @@ -279,7 +225,11 @@ struct TabBarItem: View {
.background {
if prefs.preferences.general.tabBarStyle == .xcode {
Color(nsColor: isActive ? .selectedControlColor : .clear)
.opacity(colorScheme == .dark ? 0.70 : 0.50)
.opacity(
colorScheme == .dark
? (activeState != .inactive ? 0.70 : 0.50)
: (activeState != .inactive ? 0.50 : 0.35)
)
.background(
// This layer of background is to hide dividers of other tab bar items
// because the original background above is translucent (by opacity).
Expand All @@ -301,7 +251,7 @@ struct TabBarItem: View {
ZStack {
// Native inactive tab background dim.
Color(nsColor: .black)
.opacity(colorScheme == .dark ? 0.50 : 0.05)
.opacity(colorScheme == .dark ? 0.45 : 0.05)

// Native inactive tab hover state.
Color(nsColor: colorScheme == .dark ? .white : .black)
Expand All @@ -312,7 +262,6 @@ struct TabBarItem: View {
)
.animation(.easeInOut(duration: 0.10), value: isHovering)
}
.padding(.top, colorScheme == .dark ? 0 : 1)
.padding(.horizontal, 1)
}
}
Expand Down
Loading