Repository navigation
Add settings sidebar shell #3244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
d2c9ca9
Add settings sidebar shell
lawrencecchen 95d4ca1
Add settings shell prototype app
lawrencecchen f28dc75
Migrate settings to native shell layout
lawrencecchen 30e443a
Align settings shell with prototype
lawrencecchen d440142
Remove settings titlebar debug hooks
lawrencecchen 187987d
Use SwiftUI scene for settings window
lawrencecchen 4349366
Improve settings search results
lawrencecchen a918a4c
Remove settings detail title
lawrencecchen 10a792d
Tune settings window default size
lawrencecchen 63e86f0
Highlight settings search results
lawrencecchen d30f8c4
Make settings search highlight persistent
lawrencecchen 59d27a3
Fade settings search highlight
lawrencecchen b84f6d7
Expose settings json in settings
lawrencecchen aaac7df
Split settings navigation helpers
lawrencecchen d4bd7a9
Limit settings highlight to search clicks
lawrencecchen ce772ae
Make settings sidebar scroll latest-wins
lawrencecchen 963e40a
Use wand icon for automation settings
lawrencecchen ec7ca8f
Move workspace colors below shortcuts
lawrencecchen da0f416
merge: resolve conflicts with main
lawrencecchen 440d5cc
Address settings window review feedback
lawrencecchen 1d697b3
Fix settings shortcut routing test cleanup
lawrencecchen 0e607d2
Fix settings window activation warning
lawrencecchen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
Prototypes/SettingsShellLab/.codex/environments/environment.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY | ||
| version = 1 | ||
| name = "SettingsShellLab" | ||
|
|
||
| [setup] | ||
| script = "" | ||
|
|
||
| [[actions]] | ||
| name = "Run" | ||
| icon = "run" | ||
| command = "./script/build_and_run.sh" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| .build/ | ||
| dist/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| // swift-tools-version: 5.9 | ||
|
|
||
| import PackageDescription | ||
|
|
||
| let package = Package( | ||
| name: "SettingsShellLab", | ||
| platforms: [ | ||
| .macOS(.v14), | ||
| ], | ||
| products: [ | ||
| .executable(name: "SettingsShellLab", targets: ["SettingsShellLab"]), | ||
| ], | ||
| targets: [ | ||
| .executableTarget( | ||
| name: "SettingsShellLab", | ||
| path: "Sources/SettingsShellLab", | ||
| resources: [.process("Resources")] | ||
| ), | ||
| ] | ||
| ) |
24 changes: 24 additions & 0 deletions
24
Prototypes/SettingsShellLab/Sources/SettingsShellLab/App/SettingsShellLabApp.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import AppKit | ||
| import SwiftUI | ||
|
|
||
| @main | ||
| struct SettingsShellLabApp: App { | ||
| @NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate | ||
|
|
||
| var body: some Scene { | ||
| WindowGroup(String(localized: "app.window.title", defaultValue: "Settings Shell Lab")) { | ||
| SettingsShellView() | ||
| } | ||
| .defaultSize(width: 980, height: 680) | ||
| .commands { | ||
| SidebarCommands() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| final class AppDelegate: NSObject, NSApplicationDelegate { | ||
| func applicationDidFinishLaunching(_ notification: Notification) { | ||
| NSApp.setActivationPolicy(.regular) | ||
| NSApp.activate(ignoringOtherApps: true) | ||
| } | ||
| } |
74 changes: 74 additions & 0 deletions
74
Prototypes/SettingsShellLab/Sources/SettingsShellLab/Models/SettingsSection.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| import SwiftUI | ||
|
|
||
| enum SettingsSection: String, CaseIterable, Identifiable { | ||
| case general | ||
| case terminal | ||
| case sidebar | ||
| case browser | ||
| case keyboard | ||
| case automation | ||
| case advanced | ||
|
|
||
| var id: Self { self } | ||
|
|
||
| var title: String { | ||
| switch self { | ||
| case .general: | ||
| return String(localized: "section.general.title", defaultValue: "General") | ||
| case .terminal: | ||
| return String(localized: "section.terminal.title", defaultValue: "Terminal") | ||
| case .sidebar: | ||
| return String(localized: "section.sidebar.title", defaultValue: "Sidebar") | ||
| case .browser: | ||
| return String(localized: "section.browser.title", defaultValue: "Browser") | ||
| case .keyboard: | ||
| return String(localized: "section.keyboard.title", defaultValue: "Keyboard") | ||
| case .automation: | ||
| return String(localized: "section.automation.title", defaultValue: "Automation") | ||
| case .advanced: | ||
| return String(localized: "section.advanced.title", defaultValue: "Advanced") | ||
| } | ||
| } | ||
|
|
||
| var symbolName: String { | ||
| switch self { | ||
| case .general: | ||
| return "gearshape" | ||
| case .terminal: | ||
| return "terminal" | ||
| case .sidebar: | ||
| return "sidebar.left" | ||
| case .browser: | ||
| return "globe" | ||
| case .keyboard: | ||
| return "keyboard" | ||
| case .automation: | ||
| return "bolt.horizontal" | ||
| case .advanced: | ||
| return "wrench.and.screwdriver" | ||
| } | ||
| } | ||
|
|
||
| var detail: String { | ||
| switch self { | ||
| case .general: | ||
| return String(localized: "section.general.detail", defaultValue: "Language, appearance, updates") | ||
| case .terminal: | ||
| return String(localized: "section.terminal.detail", defaultValue: "Font, scrollback, bell") | ||
| case .sidebar: | ||
| return String(localized: "section.sidebar.detail", defaultValue: "Layout, badges, metadata") | ||
| case .browser: | ||
| return String(localized: "section.browser.detail", defaultValue: "Search, links, history") | ||
| case .keyboard: | ||
| return String(localized: "section.keyboard.detail", defaultValue: "Shortcuts and chords") | ||
| case .automation: | ||
| return String(localized: "section.automation.detail", defaultValue: "Socket, hooks, ports") | ||
| case .advanced: | ||
| return String(localized: "section.advanced.detail", defaultValue: "Diagnostics and reset") | ||
| } | ||
| } | ||
|
|
||
| var searchText: String { | ||
| "\(title) \(detail)" | ||
| } | ||
| } |
32 changes: 32 additions & 0 deletions
32
Prototypes/SettingsShellLab/Sources/SettingsShellLab/Resources/Localizable.xcstrings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| { | ||
| "sourceLanguage": "en", | ||
| "version": "1.0", | ||
| "strings": { | ||
| "app.window.title": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Settings Shell" } }, "ja": { "stringUnit": { "state": "translated", "value": "設定シェル" } } } }, | ||
| "detail.mode": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Mode" } }, "ja": { "stringUnit": { "state": "translated", "value": "モード" } } } }, | ||
| "detail.primaryAction": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Open Related File" } }, "ja": { "stringUnit": { "state": "translated", "value": "関連ファイルを開く" } } } }, | ||
| "detail.secondaryAction": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Restore Defaults" } }, "ja": { "stringUnit": { "state": "translated", "value": "デフォルトに戻す" } } } }, | ||
| "detail.section": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Section" } }, "ja": { "stringUnit": { "state": "translated", "value": "セクション" } } } }, | ||
| "detail.slider": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Amount" } }, "ja": { "stringUnit": { "state": "translated", "value": "量" } } } }, | ||
| "detail.toggle": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Enable" } }, "ja": { "stringUnit": { "state": "translated", "value": "有効にする" } } } }, | ||
| "mode.compact": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Compact" } }, "ja": { "stringUnit": { "state": "translated", "value": "コンパクト" } } } }, | ||
| "mode.expanded": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Expanded" } }, "ja": { "stringUnit": { "state": "translated", "value": "拡張" } } } }, | ||
| "mode.system": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "System" } }, "ja": { "stringUnit": { "state": "translated", "value": "システム" } } } }, | ||
| "section.advanced.detail": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Advanced" } }, "ja": { "stringUnit": { "state": "translated", "value": "詳細" } } } }, | ||
| "section.advanced.title": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Advanced" } }, "ja": { "stringUnit": { "state": "translated", "value": "詳細" } } } }, | ||
| "section.automation.detail": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Automation" } }, "ja": { "stringUnit": { "state": "translated", "value": "自動化" } } } }, | ||
| "section.automation.title": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Automation" } }, "ja": { "stringUnit": { "state": "translated", "value": "自動化" } } } }, | ||
| "section.browser.detail": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Browser" } }, "ja": { "stringUnit": { "state": "translated", "value": "ブラウザ" } } } }, | ||
| "section.browser.title": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Browser" } }, "ja": { "stringUnit": { "state": "translated", "value": "ブラウザ" } } } }, | ||
| "section.general.detail": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "General" } }, "ja": { "stringUnit": { "state": "translated", "value": "一般" } } } }, | ||
| "section.general.title": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "General" } }, "ja": { "stringUnit": { "state": "translated", "value": "一般" } } } }, | ||
| "section.keyboard.detail": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Keyboard" } }, "ja": { "stringUnit": { "state": "translated", "value": "キーボード" } } } }, | ||
| "section.keyboard.title": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Keyboard" } }, "ja": { "stringUnit": { "state": "translated", "value": "キーボード" } } } }, | ||
| "section.sidebar.detail": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Sidebar" } }, "ja": { "stringUnit": { "state": "translated", "value": "サイドバー" } } } }, | ||
| "section.sidebar.title": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Sidebar" } }, "ja": { "stringUnit": { "state": "translated", "value": "サイドバー" } } } }, | ||
| "section.terminal.detail": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Terminal" } }, "ja": { "stringUnit": { "state": "translated", "value": "ターミナル" } } } }, | ||
| "section.terminal.title": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Terminal" } }, "ja": { "stringUnit": { "state": "translated", "value": "ターミナル" } } } }, | ||
| "settings.search.prompt": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Search" } }, "ja": { "stringUnit": { "state": "translated", "value": "検索" } } } }, | ||
| "settings.sidebar.title": { "localizations": { "en": { "stringUnit": { "state": "translated", "value": "Settings" } }, "ja": { "stringUnit": { "state": "translated", "value": "設定" } } } } | ||
| } | ||
| } |
72 changes: 72 additions & 0 deletions
72
Prototypes/SettingsShellLab/Sources/SettingsShellLab/Views/SettingsDetailView.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| import SwiftUI | ||
|
|
||
| struct SettingsDetailView: View { | ||
| let section: SettingsSection | ||
|
|
||
| @State private var isEnabled = true | ||
| @State private var selectedMode = Mode.system | ||
| @State private var numericValue = 12.0 | ||
|
|
||
| var body: some View { | ||
| Form { | ||
| Section { | ||
| LabeledContent( | ||
| String(localized: "detail.section", defaultValue: "Section"), | ||
| value: section.title | ||
| ) | ||
|
|
||
| Toggle( | ||
| String(localized: "detail.toggle", defaultValue: "Enable"), | ||
| isOn: $isEnabled | ||
| ) | ||
|
|
||
| Picker(String(localized: "detail.mode", defaultValue: "Mode"), selection: $selectedMode) { | ||
| ForEach(Mode.allCases) { mode in | ||
| Text(mode.title).tag(mode) | ||
| } | ||
| } | ||
| .pickerStyle(.segmented) | ||
|
|
||
| Slider( | ||
| value: $numericValue, | ||
| in: 0...24 | ||
| ) { | ||
| Text(String(localized: "detail.slider", defaultValue: "Amount")) | ||
| } | ||
| } header: { | ||
| Text(section.title) | ||
| } | ||
|
|
||
| Section { | ||
| Button(String(localized: "detail.primaryAction", defaultValue: "Open Related File")) { | ||
| } | ||
| .disabled(true) | ||
|
|
||
| Button(String(localized: "detail.secondaryAction", defaultValue: "Restore Defaults")) { | ||
| } | ||
| .disabled(true) | ||
| } | ||
| } | ||
| .formStyle(.grouped) | ||
| .padding() | ||
| } | ||
| } | ||
|
|
||
| private enum Mode: String, CaseIterable, Identifiable { | ||
| case system | ||
| case compact | ||
| case expanded | ||
|
|
||
| var id: Self { self } | ||
|
|
||
| var title: String { | ||
| switch self { | ||
| case .system: | ||
| return String(localized: "mode.system", defaultValue: "System") | ||
| case .compact: | ||
| return String(localized: "mode.compact", defaultValue: "Compact") | ||
| case .expanded: | ||
| return String(localized: "mode.expanded", defaultValue: "Expanded") | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
| } | ||
| } | ||
41 changes: 41 additions & 0 deletions
41
Prototypes/SettingsShellLab/Sources/SettingsShellLab/Views/SettingsShellView.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| import SwiftUI | ||
|
|
||
| struct SettingsShellView: View { | ||
| @SceneStorage("selectedSettingsSection") private var selectedSectionRaw = SettingsSection.general.rawValue | ||
| @State private var columnVisibility: NavigationSplitViewVisibility = .all | ||
| @State private var searchText = "" | ||
|
|
||
| private var selectedSection: SettingsSection { | ||
| SettingsSection(rawValue: selectedSectionRaw) ?? .general | ||
| } | ||
|
|
||
| private var filteredSections: [SettingsSection] { | ||
| let query = searchText.trimmingCharacters(in: .whitespacesAndNewlines) | ||
| guard !query.isEmpty else { return SettingsSection.allCases } | ||
| return SettingsSection.allCases.filter { section in | ||
| section.searchText.localizedStandardContains(query) | ||
| } | ||
| } | ||
|
|
||
| var body: some View { | ||
| NavigationSplitView(columnVisibility: $columnVisibility) { | ||
| List(selection: $selectedSectionRaw) { | ||
| ForEach(filteredSections) { section in | ||
| Label(section.title, systemImage: section.symbolName) | ||
| .tag(section.rawValue) | ||
| } | ||
| } | ||
| .listStyle(.sidebar) | ||
| .navigationTitle(String(localized: "settings.sidebar.title", defaultValue: "Settings")) | ||
| .searchable( | ||
| text: $searchText, | ||
| placement: .sidebar, | ||
| prompt: Text(String(localized: "settings.search.prompt", defaultValue: "Search")) | ||
| ) | ||
| .navigationSplitViewColumnWidth(210) | ||
| } detail: { | ||
| SettingsDetailView(section: selectedSection) | ||
| } | ||
| .navigationSplitViewStyle(.balanced) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.