From 520cf9641d3a51d474accedad7edd0ea15b6ee83 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 16 Jun 2025 05:23:56 +0200 Subject: [PATCH] Add Help menu to menu bar with website and issue links - Add Help submenu with links to website and GitHub issues - Include Check for Updates functionality (using Sparkle stub) - Display app version (0.1.3) in Help menu - Move About option from main menu to Help submenu - Update About description to "Turn any browser into your Mac's terminal." --- VibeTunnel/Presentation/Views/AboutView.swift | 2 +- VibeTunnel/Views/MenuBarView.swift | 105 ++++++++++++++++-- 2 files changed, 95 insertions(+), 12 deletions(-) diff --git a/VibeTunnel/Presentation/Views/AboutView.swift b/VibeTunnel/Presentation/Views/AboutView.swift index f2556260..96bf9db8 100644 --- a/VibeTunnel/Presentation/Views/AboutView.swift +++ b/VibeTunnel/Presentation/Views/AboutView.swift @@ -51,7 +51,7 @@ struct AboutView: View { } private var descriptionSection: some View { - Text("Connect to AI providers with a unified interface") + Text("Turn any browser into your Mac's terminal.") .font(.body) .foregroundStyle(.secondary) } diff --git a/VibeTunnel/Views/MenuBarView.swift b/VibeTunnel/Views/MenuBarView.swift index 71b5b818..e5c7d60b 100644 --- a/VibeTunnel/Views/MenuBarView.swift +++ b/VibeTunnel/Views/MenuBarView.swift @@ -7,9 +7,11 @@ import SwiftUI +/// Main menu bar view displaying session status and app controls struct MenuBarView: View { @Environment(SessionMonitor.self) var sessionMonitor @AppStorage("showInDock") private var showInDock = false + @State private var showHelpMenu = false var body: some View { VStack(alignment: .leading, spacing: 0) { @@ -28,6 +30,23 @@ struct MenuBarView: View { Divider() .padding(.vertical, 4) + // Help menu + Button(action: { + showHelpMenu.toggle() + }) { + HStack { + Label("Help", systemImage: "questionmark.circle") + Spacer() + Image(systemName: "chevron.right") + .font(.system(size: 10)) + .foregroundColor(.secondary) + } + } + .buttonStyle(MenuButtonStyle()) + .popover(isPresented: $showHelpMenu, arrowEdge: .trailing) { + HelpMenuView(showAboutInSettings: showAboutInSettings) + } + // Settings button Button(action: { NSApp.openSettings() @@ -38,17 +57,6 @@ struct MenuBarView: View { .buttonStyle(MenuButtonStyle()) .keyboardShortcut(",", modifiers: .command) - Divider() - .padding(.vertical, 4) - - // About button - Button(action: { - showAboutInSettings() - }) { - Label("About VibeTunnel", systemImage: "info.circle") - } - .buttonStyle(MenuButtonStyle()) - Divider() .padding(.vertical, 4) @@ -67,6 +75,7 @@ struct MenuBarView: View { // MARK: - Session Count View +/// Displays the count of active SSH sessions struct SessionCountView: View { let count: Int @@ -91,6 +100,7 @@ struct SessionCountView: View { // MARK: - Session List View +/// Lists active SSH sessions with truncation for large lists struct SessionListView: View { let sessions: [String: SessionMonitor.SessionInfo] @@ -119,6 +129,7 @@ struct SessionListView: View { // MARK: - Session Row View +/// Individual row displaying session information struct SessionRowView: View { let session: (key: String, value: SessionMonitor.SessionInfo) @@ -139,6 +150,7 @@ struct SessionRowView: View { // MARK: - Menu Button Style +/// Custom button style for menu items with hover effects struct MenuButtonStyle: ButtonStyle { @State private var isHovered = false @@ -158,6 +170,77 @@ struct MenuButtonStyle: ButtonStyle { } } +// MARK: - Help Menu View + +/// Help menu with links and app information +struct HelpMenuView: View { + @Environment(\.dismiss) private var dismiss + let showAboutInSettings: () -> Void + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + // Website + Button(action: { + dismiss() + if let url = URL(string: "http://vibetunnel.sh") { + NSWorkspace.shared.open(url) + } + }) { + Label("Website", systemImage: "globe") + } + .buttonStyle(MenuButtonStyle()) + + // Report Issue + Button(action: { + dismiss() + if let url = URL(string: "https://github.com/amantus-ai/vibetunnel/issues") { + NSWorkspace.shared.open(url) + } + }) { + Label("Report Issue", systemImage: "exclamationmark.triangle") + } + .buttonStyle(MenuButtonStyle()) + + Divider() + .padding(.vertical, 4) + + // Check for Updates + Button(action: { + dismiss() + SparkleUpdaterManager.shared.checkForUpdates() + }) { + Label("Check for Updates…", systemImage: "arrow.down.circle") + } + .buttonStyle(MenuButtonStyle()) + + // Version + HStack { + Text("Version \(appVersion)") + .font(.system(size: 13)) + .foregroundColor(.secondary) + Spacer() + } + .padding(.horizontal, 12) + .padding(.vertical, 6) + + // About + Button(action: { + dismiss() + showAboutInSettings() + }) { + Label("About VibeTunnel", systemImage: "info.circle") + } + .buttonStyle(MenuButtonStyle()) + } + .frame(minWidth: 200) + .padding(.vertical, 4) + } + + private var appVersion: String { + Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "0.0.0" + } +} + // MARK: - Helper Functions /// Shows the About section in the Settings window