diff --git a/phpmon/Common/Extensions/StringExtension.swift b/phpmon/Common/Extensions/StringExtension.swift index 897832d..a8746c1 100644 --- a/phpmon/Common/Extensions/StringExtension.swift +++ b/phpmon/Common/Extensions/StringExtension.swift @@ -5,6 +5,7 @@ // Copyright © 2022 Nico Verbruggen. All rights reserved. // import Foundation +import SwiftUI extension String { var localized: String { @@ -17,6 +18,10 @@ extension String { return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "") } + var localizedForSwiftUI: LocalizedStringKey { + return LocalizedStringKey(self.localized) + } + func localized(_ args: CVarArg...) -> String { String(format: self.localized, arguments: args) } diff --git a/phpmon/Domain/Onboarding/OnboardingWC.swift b/phpmon/Domain/Onboarding/OnboardingWC.swift index 57477b7..6696c75 100644 --- a/phpmon/Domain/Onboarding/OnboardingWC.swift +++ b/phpmon/Domain/Onboarding/OnboardingWC.swift @@ -20,12 +20,14 @@ class OnboardingWC: PMWindowController { public static func create(delegate: NSWindowDelegate?) { let windowController = OnboardingWC() windowController.window = NSWindow() - windowController.window!.title = "onboarding.title".localized - windowController.window!.delegate = delegate - windowController.window!.styleMask = [.titled, .closable, .miniaturizable] - windowController.window!.delegate = windowController - windowController.window!.contentView = NSHostingView(rootView: OnboardingView()) - windowController.window!.setContentSize(NSSize(width: 600, height: 600)) + + guard let window = windowController.window else { return } + window.title = "" + window.styleMask = [.titled, .closable, .miniaturizable] + window.titlebarAppearsTransparent = true + window.delegate = delegate ?? windowController + window.contentView = NSHostingView(rootView: OnboardingView()) + window.setContentSize(NSSize(width: 600, height: 600)) App.shared.onboardingWindowController = windowController } diff --git a/phpmon/Domain/SwiftUI/Onboarding/OnboardingView.swift b/phpmon/Domain/SwiftUI/Onboarding/OnboardingView.swift index 9711ac2..0ab42e0 100644 --- a/phpmon/Domain/SwiftUI/Onboarding/OnboardingView.swift +++ b/phpmon/Domain/SwiftUI/Onboarding/OnboardingView.swift @@ -10,25 +10,34 @@ import SwiftUI struct OnboardingView: View { var body: some View { - VStack(alignment: .center) { - Image(nsImage: NSApp.applicationIconImage) - .resizable() - .frame(width: 90, height: 90) - Text("onboarding.welcome".localized) - .font(.title) - .bold() - .padding(.bottom, 5) - Text("onboarding.explore".localized) - .padding(.bottom) + VStack { + VStack(alignment: .leading) { + HStack { + Image(nsImage: NSApp.applicationIconImage) + .resizable() + .frame(width: 80, height: 80) + .padding(.bottom, 5) + .padding(.trailing, 25) + VStack(alignment: .leading, spacing: 0) { + Text("onboarding.welcome".localized) + .font(.title) + .bold() + .padding(.bottom, 5) + Text("onboarding.explore".localized) + .padding(.bottom) + }.padding(.top, 10) + } + TabView { VStack { Image("Tour.MenuBar") .resizable() .aspectRatio(contentMode: .fit) .padding(.top) - Text("onboarding.tour.menu_bar".localized) + Text("onboarding.tour.menu_bar".localizedForSwiftUI) .padding(.init(top: 5, leading: 20, bottom: 20, trailing: 20)) - }.tabItem { Label("onboarding.tour.menu_bar.title".localized, systemImage: "") } + }.tabItem { Label("onboarding.tour.menu_bar.title".localized, + systemImage: "info.circle.fill") } VStack { Image("Tour.Domains") .resizable() @@ -36,7 +45,8 @@ struct OnboardingView: View { .padding(.top) Text("onboarding.tour.domains".localized) .padding(.init(top: 5, leading: 20, bottom: 20, trailing: 20)) - }.tabItem { Label("onboarding.tour.domains.title".localized, systemImage: "") } + }.tabItem { Label("onboarding.tour.domains.title".localized, + systemImage: "info.circle.fill") } VStack { Image("Tour.Isolation") .resizable() @@ -44,18 +54,36 @@ struct OnboardingView: View { .padding(.top) Text("onboarding.tour.isolation".localized) .padding(.init(top: 5, leading: 20, bottom: 20, trailing: 20)) - }.tabItem { Label("onboarding.tour.isolation.title".localized, systemImage: "") } + }.tabItem { Label("onboarding.tour.isolation.title".localized, + systemImage: "info.circle.fill") } } + } + .frame(maxWidth: .infinity) + + VStack(alignment: .center) { + HStack { + Image(systemName: "person.fill.questionmark") + .resizable() + .frame(width: 24, height: 24) + .foregroundColor(.appSecondary) + .padding(.trailing, 16) + Text("onboarding.tour.faq_hint".localizedForSwiftUI) + }.padding() Text("onboarding.tour.once".localized) .font(.subheadline) .foregroundColor(.gray) .padding(.top, 5) + .padding(.bottom, 5) Button("Close Tour") { App.shared.onboardingWindowController?.close() } } .frame(maxWidth: .infinity) - .padding() + } + .padding(.top, 8) + .padding(.leading) + .padding(.trailing) + .padding(.bottom) } } diff --git a/phpmon/Localizable.strings b/phpmon/Localizable.strings index 834939e..794eb52 100644 --- a/phpmon/Localizable.strings +++ b/phpmon/Localizable.strings @@ -500,11 +500,12 @@ You can do this by running `composer global update` in your terminal. After that // ONBOARDING -"onboarding.title" = ""; +"onboarding.title" = "Welcome Tour"; "onboarding.welcome" = "Welcome to PHP Monitor!"; -"onboarding.explore" = "Explore some of the features below, or close the tour and get started."; +"onboarding.explore" = "Explore some of the cool features PHP Monitor has to offer."; "onboarding.tour.menu_bar.title" = "Get Started"; "onboarding.tour.menu_bar" = "PHP Monitor lives in your menu bar. From here, you can switch the globally linked PHP version, start or stop services, locate configuration files, and more."; +"onboarding.tour.faq_hint" = "**If you are new to PHP Monitor**, I recommend that you check out the [README](https://github.com/nicoverbruggen/phpmon/blob/main/README.md) on GitHub: it contains a comprehensive FAQ with various tips and common questions and answers. Don't hesitate to get in touch either."; "onboarding.tour.domains.title" = "Domains"; "onboarding.tour.domains" = "By opening the Domains window via the Menu Bar item, you can view which domains are linked and parked."; "onboarding.tour.isolation.title" = "Isolation";