feat(sidebar): add Settings and About as inline detail routes

Move Settings and About from standalone windows to sidebar entries
that display in the detail panel like other tabs. Remove redundant
Settings scene and About window from AtlasApp. Skip searchable
modifier for these routes and fix empty accessibility hint for About.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
zhukang
2026-03-10 21:54:09 +08:00
parent c435b5e301
commit 977ab9c047
2 changed files with 52 additions and 56 deletions

View File

@@ -14,9 +14,22 @@ struct AppShellView: View {
var body: some View { var body: some View {
NavigationSplitView { NavigationSplitView {
List(AtlasRoute.allCases, selection: $model.selection) { route in List(selection: $model.selection) {
SidebarRouteRow(route: route) ForEach(AtlasRoute.SidebarSection.allCases) { section in
.tag(route) Section(section.title) {
ForEach(section.routes) { route in
SidebarRouteRow(route: route)
.tag(route)
}
}
}
Section {
SidebarRouteRow(route: .settings)
.tag(AtlasRoute.settings)
SidebarRouteRow(route: .about)
.tag(AtlasRoute.about)
}
} }
.navigationTitle(AtlasL10n.string("app.name")) .navigationTitle(AtlasL10n.string("app.name"))
.navigationSplitViewColumnWidth(min: AtlasLayout.sidebarMinWidth, ideal: AtlasLayout.sidebarIdealWidth) .navigationSplitViewColumnWidth(min: AtlasLayout.sidebarMinWidth, ideal: AtlasLayout.sidebarIdealWidth)
@@ -25,17 +38,7 @@ struct AppShellView: View {
} detail: { } detail: {
let route = model.selection ?? .overview let route = model.selection ?? .overview
detailView(for: route) detailContent(for: route)
.id(route)
.transition(.opacity)
.searchable(
text: Binding(
get: { model.searchText(for: route) },
set: { model.setSearchText($0, for: route) }
),
prompt: AtlasL10n.string("app.search.prompt.route", route.searchPromptLabel)
)
.accessibilityHint(AtlasL10n.string("app.search.hint.route", route.searchPromptLabel))
.toolbar { .toolbar {
ToolbarItemGroup { ToolbarItemGroup {
Button { Button {
@@ -64,39 +67,6 @@ struct AppShellView: View {
.accessibilityIdentifier("toolbar.taskCenter") .accessibilityIdentifier("toolbar.taskCenter")
.accessibilityLabel(AtlasL10n.string("toolbar.taskcenter.accessibilityLabel")) .accessibilityLabel(AtlasL10n.string("toolbar.taskcenter.accessibilityLabel"))
.accessibilityHint(AtlasL10n.string("toolbar.taskcenter.accessibilityHint")) .accessibilityHint(AtlasL10n.string("toolbar.taskcenter.accessibilityHint"))
Button {
model.navigate(to: .permissions)
Task {
await model.inspectPermissions()
}
} label: {
Label {
Text(AtlasL10n.string("toolbar.permissions"))
} icon: {
Image(systemName: AtlasIcon.permissions)
.symbolRenderingMode(.hierarchical)
}
}
.help(AtlasL10n.string("toolbar.permissions.help"))
.accessibilityIdentifier("toolbar.permissions")
.accessibilityLabel(AtlasL10n.string("toolbar.permissions.accessibilityLabel"))
.accessibilityHint(AtlasL10n.string("toolbar.permissions.accessibilityHint"))
Button {
model.navigate(to: .settings)
} label: {
Label {
Text(AtlasL10n.string("toolbar.settings"))
} icon: {
Image(systemName: AtlasIcon.settings)
.symbolRenderingMode(.hierarchical)
}
}
.help(AtlasL10n.string("toolbar.settings.help"))
.accessibilityIdentifier("toolbar.settings")
.accessibilityLabel(AtlasL10n.string("toolbar.settings.accessibilityLabel"))
.accessibilityHint(AtlasL10n.string("toolbar.settings.accessibilityHint"))
} }
} }
.animation(AtlasMotion.slow, value: model.selection) .animation(AtlasMotion.slow, value: model.selection)
@@ -128,6 +98,28 @@ struct AppShellView: View {
} }
} }
@ViewBuilder
private func detailContent(for route: AtlasRoute) -> some View {
switch route {
case .settings, .about:
detailView(for: route)
.id(route)
.transition(.opacity)
default:
detailView(for: route)
.id(route)
.transition(.opacity)
.searchable(
text: Binding(
get: { model.searchText(for: route) },
set: { model.setSearchText($0, for: route) }
),
prompt: AtlasL10n.string("app.search.prompt.route", route.searchPromptLabel)
)
.accessibilityHint(AtlasL10n.string("app.search.hint.route", route.searchPromptLabel))
}
}
@ViewBuilder @ViewBuilder
private func detailView(for route: AtlasRoute) -> some View { private func detailView(for route: AtlasRoute) -> some View {
switch route { switch route {
@@ -269,7 +261,7 @@ private struct SidebarRouteRow: View {
.accessibilityElement(children: .combine) .accessibilityElement(children: .combine)
.accessibilityIdentifier("route.\(route.id)") .accessibilityIdentifier("route.\(route.id)")
.accessibilityLabel("\(route.title). \(route.subtitle)") .accessibilityLabel("\(route.title). \(route.subtitle)")
.accessibilityHint(AtlasL10n.string("sidebar.route.hint", route.shortcutNumber)) .accessibilityHint(route.shortcutNumber.isEmpty ? "" : AtlasL10n.string("sidebar.route.hint", route.shortcutNumber))
} }
} }
@@ -291,9 +283,9 @@ private extension AtlasRoute {
case .permissions: case .permissions:
return "5" return "5"
case .settings: case .settings:
return "6" return ","
case .about: case .about:
return "7" return ""
} }
} }
} }

View File

@@ -5,8 +5,14 @@ struct AtlasAppCommands: Commands {
@ObservedObject var model: AtlasAppModel @ObservedObject var model: AtlasAppModel
var body: some Commands { var body: some Commands {
CommandGroup(replacing: .appInfo) {
Button(AtlasL10n.string("commands.about")) {
model.navigate(to: .about)
}
}
CommandMenu(AtlasL10n.string("commands.navigate.menu")) { CommandMenu(AtlasL10n.string("commands.navigate.menu")) {
ForEach(AtlasRoute.allCases) { route in ForEach(AtlasRoute.sidebarRoutes) { route in
Button(route.title) { Button(route.title) {
model.navigate(to: route) model.navigate(to: route)
} }
@@ -18,7 +24,7 @@ struct AtlasAppCommands: Commands {
Button(model.isTaskCenterPresented ? AtlasL10n.string("commands.taskcenter.close") : AtlasL10n.string("commands.taskcenter.open")) { Button(model.isTaskCenterPresented ? AtlasL10n.string("commands.taskcenter.close") : AtlasL10n.string("commands.taskcenter.open")) {
model.toggleTaskCenter() model.toggleTaskCenter()
} }
.keyboardShortcut("7", modifiers: .command) .keyboardShortcut("6", modifiers: .command)
} }
CommandMenu(AtlasL10n.string("commands.actions.menu")) { CommandMenu(AtlasL10n.string("commands.actions.menu")) {
@@ -80,10 +86,8 @@ private extension AtlasRoute {
return "4" return "4"
case .permissions: case .permissions:
return "5" return "5"
case .settings: case .settings, .about:
return "6" preconditionFailure("Non-sidebar routes have no shortcut key")
case .about:
return "7"
} }
} }
} }