+++ title = "Flat Navigation" description = "A navigation pattern for views of equal importance." date = 2024-11-16 [taxonomies] tags = ["Aparoksha", "Windows", "Linux", "macOS"] +++ In a flat navigation structure, each page is equivalent in importance and can be opened form any of the others. Different platforms offer different solutions for flat navigation, such as a top bar or a sidebar. This view will select the most appropriate based on number of elements and available space. Label views with capitalized nouns with a similar length. Order the elements according to what is most useful for the user. The icons should clearly communicate a page's function even without the label. Note that this view should be used exclusively as a direct child of a window. ## Sidebar Design The sidebar design will be used if there are more than five items or the developer chooses to force the sidebar design (see below).
{{ image(url="sidebarGNOME.png", alt="A navigation view with a sidebar on GNOME" transparent=true) }} {{ image(url="sidebarWindows.png", alt="A navigation view with a sidebar on Windows") }}
## Top Bar Design The top bar design will be used for five items or less if the sidebar design is not forced.
{{ image(url="topGNOME.png", alt="A navigation view with a top bar on GNOME" transparent=true) }} {{ image(url="topWindows.png", alt="A navigation view with a top bar on GNOME") }}
## Equatable Items A flat navigation view can be initialized either with identifiable or with equatable items. The initializer for equatable items is useful for a fixed number of items. ```swift struct ContentView: View { @State private var selectedItem: Page = .navigation var view: Body { FlatNavigation(Page.allCases, selection: $selectedItem) { // The content. Text(selectedItem.description) } } } enum Page: FlatNavigationItem, CaseIterable { // The pages. case navigation case alert // The title of the page. var description: String { switch self { case .navigation: Loc.navigation case .alert: Loc.alert } } // The icon of the page. var icon: Icon { switch self { case .navigation: .navigation case .alert: .warning } } } ``` ## Identifiable Items The initializer for identifiable items should be used for a dynamic list of items. It will automatically force the sidebar design (more information below). ```swift struct ContentView: View { @State private var selectedItem: UUID? @State private var items: [Item] = [.init(title: "Item 1"), .init(title: "Item 2")] var view: Body { FlatNavigation(items, selection: $selectedItem) { // The content. Text("Content") } } } struct Item: DynamicFlatNavigationItem, Identifiable { let id: UUID = .init() var title: String // The title of the page. var description: String { title } // The icon of the page. var icon: Icon { .document } } ``` ## Force the Sidebar Design Force the sidebar design with the [`forceSplitView(_:)`](https://aparoksha.aparoksha.dev/documentation/aparoksha/flatnavigation/forcesplitview(_:)) modifier. ```swift FlatNavigation(Page.allCases, selection: $selectedItem) { // The content. Text(selectedItem.description) } .forceSplitView() ``` ## Primary Action The primary action usually modifies the navigation items or triggers an important action.
{{ image(url="primaryGNOME.png", alt="A navigation view with a sidebar and a primary action on GNOME" transparent=true) }} {{ image(url="primaryWindows.png", alt="A navigation view with a sidebar and a primary action on Windows") }} {{ image(url="primaryGNOMETop.png", alt="A navigation view with a sidebar on GNOME" transparent=true) }} {{ image(url="primaryWindowsTop.png", alt="A navigation view with a sidebar on Windows") }}
```swift FlatNavigation(items, selection: $selectedItem) { // The content. Text(selectedItem.description) } .primaryAction(Loc.addItem, icon: .plus) { // The action. items.append(.init(title: Loc.newItem)) } ``` ## Guidelines - GNOME - Windows ## Documentation - Reference Documentation - Native GNOME Implementation (Sidebar) - Native GNOME Implementation (Top Bar) - Native Windows Implementation