├── .gitignore
├── .swiftpm
└── xcode
│ ├── package.xcworkspace
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ └── xcschemes
│ ├── TranslucentWindowStyle.xcscheme
│ └── TranslucentWindowStyleTest.xcscheme
├── Package.swift
├── README.md
├── Sources
└── TranslucentWindowStyle
│ └── TranslucentWindowStyle.swift
├── Tests
└── TranslucentWindowStyleTests
│ └── TranslucentWindowStyleTests.swift
└── screenshot.png
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 | DerivedData/
7 | .swiftpm/config/registries.json
8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9 | .netrc
10 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/xcshareddata/xcschemes/TranslucentWindowStyle.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
54 |
55 |
61 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/xcshareddata/xcschemes/TranslucentWindowStyleTest.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
68 |
69 |
75 |
76 |
82 |
83 |
84 |
85 |
87 |
88 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.7
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "TranslucentWindowStyle",
8 | platforms: [.macOS(.v12)],
9 | products: [
10 | // Products define the executables and libraries a package produces, and make them visible to other packages.
11 | .library(
12 | name: "TranslucentWindowStyle",
13 | targets: ["TranslucentWindowStyle"]),
14 | ],
15 | dependencies: [
16 | // Dependencies declare other packages that this package depends on.
17 | // .package(url: /* package url */, from: "1.0.0"),
18 | ],
19 | targets: [
20 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
21 | // Targets can depend on other targets in this package, and on products in packages this package depends on.
22 | .target(
23 | name: "TranslucentWindowStyle",
24 | dependencies: []),
25 | .testTarget(
26 | name: "TranslucentWindowStyleTests",
27 | dependencies: ["TranslucentWindowStyle"]),
28 | ]
29 | )
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TranslucentWindowStyle
2 |
3 | Translucent Window Background Style is a Swift package with a custom SwiftUI window background style that creates a translucent window with a blur effect. This package allows you to add a translucent background style to your SwiftUI app's windows.
4 |
5 | ## Overview
6 |
7 | The Translucent Window Background Style package provides a `TranslucentBackgroundStyle` struct that conforms to the `WindowBackgroundStyle` protocol. This style creates a translucent window with a blur effect.
8 |
9 | ## Usage
10 |
11 | To use the Translucent Window Background Style in your SwiftUI app, follow these steps:
12 |
13 | 1. Import the package in your SwiftUI view file:
14 |
15 | ```swift
16 | import TranslucentWindowBackgroundStyle
17 | ```
18 |
19 | 2. Apply the `presentedWindowBackgroundStyle` modifier to your window view, and pass in an instance of `TranslucentBackgroundStyle`:
20 |
21 | ```swift
22 | WindowGroup {
23 | ContentView()
24 | .presentedWindowBackgroundStyle(.hiddenTitleBarTranslucent)
25 | }
26 | ```
27 |
28 | 3. The `hiddenTitleBarTranslucent` static property of `TranslucentBackgroundStyle` provides a convenient method to create a translucent window without a title bar.
29 |
30 | ```swift
31 | TranslucentBackgroundStyle.hiddenTitleBarTranslucent
32 | ```
33 |
34 | ### Example
35 |
36 | 
37 |
38 | ## Installation
39 |
40 | The Translucent Window Background Style package can be installed via Swift Package Manager. To install, follow these steps:
41 |
42 | 1. Open your project in Xcode.
43 |
44 | 2. Click on File > Swift Packages > Add Package Dependency.
45 |
46 | 3. Enter the following URL in the search bar:
47 |
48 | ```javascript
49 | https://github.com/DominatorVbN/TranslucentWindowBackgroundStyle
50 | ```
51 |
52 | Replace "your-username" with your GitHub username or the URL of your forked repository if you want to used the foked version in your app.
53 |
54 | 4. Choose the version or branch of the package that you want to install.
55 |
56 | 5. Click on the Add Package button.
57 |
58 | 6. Add `TranslucentWindowBackgroundStyle` to the list of dependencies for your target in your project's `Package.swift` file:
59 |
60 | ```swift
61 | dependencies: [
62 | .package(url: "https://github.com/DominatorVbN/TranslucentWindowBackgroundStyle", .upToNextMinor(from: "1.0.0"))
63 | ]
64 | ```
65 |
66 | Replace "your-username" with your GitHub username or the URL of your forked repository if you want to used the foked version in your app., and "1.0.0" with the version or branch that you installed.
67 |
68 | 7. Import the package in your SwiftUI view file:
69 |
70 | ```swift
71 | import TranslucentWindowBackgroundStyle
72 | ```
73 |
74 | 8. You're now ready to use the Translucent Window Background Style in your SwiftUI app!
75 |
76 | ## Contributing
77 |
78 | Contributions are always welcome, whether it's bug fixes, feature enhancements, or documentation improvements. To contribute, please follow these steps:
79 |
80 | 1. Fork the repository
81 | 2. Create a new branch for your changes: `git checkout -b feature/your-feature-name`
82 | 3. Make your changes and commit them: `git commit -m 'Add some feature'`
83 | 4. Push your changes to your forked repository: `git push origin feature/your-feature-name`
84 | 5. Create a pull request on the original repository, with a description of your changes
85 |
86 | Thank you for your contributions!
87 |
--------------------------------------------------------------------------------
/Sources/TranslucentWindowStyle/TranslucentWindowStyle.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 |
4 | public protocol WindowBackgroundStyle {
5 | associatedtype Body : View
6 | @ViewBuilder @MainActor var backgroud: Self.Body { get }
7 | }
8 |
9 | extension WindowBackgroundStyle where Self == TranslucentBackgroundStyle {
10 | public static var hiddenTitleBar: TranslucentBackgroundStyle { TranslucentBackgroundStyle(config: .translucent) }
11 |
12 | public static func hiddenTitleBar(material: NSVisualEffectView.Material) -> TranslucentBackgroundStyle {
13 | TranslucentBackgroundStyle(config: .translucent(material: material))
14 | }
15 | }
16 |
17 | public struct TranslucentBackgroundStyle: WindowBackgroundStyle {
18 | let config: TranslucentWindowBackground.WindowConfiguration
19 | public var backgroud: some View {
20 | TranslucentWindowBackground(config: config)
21 | }
22 | }
23 |
24 | extension View {
25 |
26 | @MainActor public func presentedWindowBackgroundStyle(_ style: S) -> some View where S : WindowBackgroundStyle {
27 | self.background(style.backgroud)
28 | }
29 |
30 | }
31 |
32 | struct TranslucentWindowBackground: NSViewRepresentable {
33 |
34 | let config: WindowConfiguration
35 |
36 | enum ContentViewConfiguration {
37 | case embed(NSView?)
38 | case replace(NSView?)
39 | }
40 |
41 | enum StyleMaskConfiguration {
42 | case insert(NSWindow.StyleMask)
43 | case replace(NSWindow.StyleMask)
44 | }
45 |
46 | struct WindowConfiguration {
47 | let isOpaque: Bool
48 | let backgroundColor: NSColor
49 | let contentViewCofiguration: ContentViewConfiguration
50 | let styleMaskConfiguration: StyleMaskConfiguration
51 | let titlebarAppearsTransparent: Bool
52 | let titleVisibility: NSWindow.TitleVisibility
53 | let standardWindowButtonConfig: StandardWindowButtonConfiguration
54 | let isMovableByWindowBackground: Bool
55 |
56 | public struct StandardWindowButtonConfiguration {
57 | let miniaturizeButtonIsHidden: Bool
58 | let closeButtonIsHidden: Bool
59 | let zoomButtonIsHidden: Bool
60 | }
61 |
62 | static func getTranlucentBackground(material: NSVisualEffectView.Material) -> NSView {
63 | let visualEffect = NSVisualEffectView()
64 | visualEffect.blendingMode = .behindWindow
65 | visualEffect.state = .followsWindowActiveState
66 | visualEffect.material = material
67 | return visualEffect
68 | }
69 |
70 | static let translucent: WindowConfiguration = WindowConfiguration(
71 | isOpaque: false,
72 | backgroundColor: NSColor.clear,
73 | contentViewCofiguration: .embed(getTranlucentBackground(material: .sidebar)),
74 | styleMaskConfiguration: .insert(.titled),
75 | titlebarAppearsTransparent: true,
76 | titleVisibility: .hidden,
77 | standardWindowButtonConfig: StandardWindowButtonConfiguration(
78 | miniaturizeButtonIsHidden: true,
79 | closeButtonIsHidden: true,
80 | zoomButtonIsHidden: true
81 | ),
82 | isMovableByWindowBackground: true
83 | )
84 |
85 | static func translucent(material: NSVisualEffectView.Material) -> WindowConfiguration {
86 | WindowConfiguration(
87 | isOpaque: false,
88 | backgroundColor: NSColor.clear,
89 | contentViewCofiguration: .embed(getTranlucentBackground(material: material)),
90 | styleMaskConfiguration: .insert(.titled),
91 | titlebarAppearsTransparent: true,
92 | titleVisibility: .hidden,
93 | standardWindowButtonConfig: StandardWindowButtonConfiguration(
94 | miniaturizeButtonIsHidden: true,
95 | closeButtonIsHidden: true,
96 | zoomButtonIsHidden: true
97 | ),
98 | isMovableByWindowBackground: true
99 | )
100 | }
101 |
102 | static func configure(window: NSWindow, forConfig config: WindowConfiguration) {
103 |
104 | window.isOpaque = config.isOpaque
105 | window.backgroundColor = config.backgroundColor
106 |
107 | switch config.contentViewCofiguration {
108 | case let .replace(view):
109 | window.contentView = view
110 | case let .embed(view):
111 | let currentContentView = window.contentView
112 | window.contentView = view
113 | if let currentContentView = currentContentView {
114 | view?.addSubview(currentContentView)
115 | }
116 | }
117 |
118 | switch config.styleMaskConfiguration {
119 | case let .replace(mask):
120 | window.styleMask = mask
121 | case let .insert(mask):
122 | window.styleMask.insert(mask)
123 | }
124 |
125 | window.titlebarAppearsTransparent = config.titlebarAppearsTransparent
126 | window.titleVisibility = config.titleVisibility
127 | window.standardWindowButton(.miniaturizeButton)?.isHidden = config.standardWindowButtonConfig.miniaturizeButtonIsHidden
128 | window.standardWindowButton(.closeButton)?.isHidden = config.standardWindowButtonConfig.closeButtonIsHidden
129 | window.standardWindowButton(.zoomButton)?.isHidden = config.standardWindowButtonConfig.zoomButtonIsHidden
130 | window.isMovableByWindowBackground = config.isMovableByWindowBackground
131 | }
132 | }
133 |
134 |
135 | func makeCoordinator() -> Coordinator {
136 | Coordinator(config: config)
137 | }
138 |
139 |
140 | class Coordinator: NSObject {
141 |
142 | let config: WindowConfiguration
143 | private var _originalWindowConfiguration: WindowConfiguration?
144 |
145 | init(config: WindowConfiguration) {
146 | self.config = config
147 | }
148 |
149 | func createWindowConfigurationForCurrentContext(_ context: NSWindow) -> WindowConfiguration {
150 | WindowConfiguration(
151 | isOpaque: context.isOpaque,
152 | backgroundColor: context.backgroundColor,
153 | contentViewCofiguration: .replace(context.contentView),
154 | styleMaskConfiguration: .replace(context.styleMask),
155 | titlebarAppearsTransparent: context.titlebarAppearsTransparent,
156 | titleVisibility: context.titleVisibility,
157 | standardWindowButtonConfig: WindowConfiguration.StandardWindowButtonConfiguration(
158 | miniaturizeButtonIsHidden: context.standardWindowButton(.miniaturizeButton)?.isHidden ?? false,
159 | closeButtonIsHidden: context.standardWindowButton(.closeButton)?.isHidden ?? false,
160 | zoomButtonIsHidden: context.standardWindowButton(.zoomButton)?.isHidden ?? false
161 | ),
162 | isMovableByWindowBackground: context.isMovableByWindowBackground
163 | )
164 | }
165 |
166 | func makeWindowTranslucent(window: NSWindow?) {
167 | guard let window = window else { return }
168 | self._originalWindowConfiguration = createWindowConfigurationForCurrentContext(window)
169 | let translucentWindowConfiguration = config
170 | WindowConfiguration.configure(window: window, forConfig: translucentWindowConfiguration)
171 | }
172 |
173 | func resetWindow(window: NSWindow) {
174 | if let originalWindowConfiguration = _originalWindowConfiguration {
175 | WindowConfiguration.configure(window: window, forConfig: originalWindowConfiguration)
176 | }
177 | }
178 | }
179 |
180 | func makeNSView(context: Context) -> NSView {
181 | let view = NSView()
182 | DispatchQueue.main.async {
183 | let window = view.window
184 | context.coordinator.makeWindowTranslucent(window: window)
185 | }
186 | return view
187 | }
188 |
189 | func updateNSView(_ nsView: NSView, context: Context) {
190 |
191 | }
192 |
193 | static func dismantleNSView(_ nsView: NSView, coordinator: Coordinator) {
194 | guard let window = nsView.window else {
195 | return
196 | }
197 | coordinator.resetWindow(window: window)
198 | }
199 | }
200 |
201 |
202 |
--------------------------------------------------------------------------------
/Tests/TranslucentWindowStyleTests/TranslucentWindowStyleTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import TranslucentWindowStyle
3 |
4 | final class TranslucentWindowStyleTests: XCTestCase {
5 | }
6 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DominatorVbN/TranslucentWindowStyle/67833e921348b69e1c3c560734a374bdf5bc0504/screenshot.png
--------------------------------------------------------------------------------