Removed the Integrations & Installation category and its lone Installation section entirely — Outline's server version now shows in the settings sidebar footer instead, alongside Outpost's own version (installation.info, fetched once when the sidebar appears). About stays where it was, unaffected.
138 lines
5.2 KiB
Swift
138 lines
5.2 KiB
Swift
import Observation
|
|
|
|
/// Top-level groupings shown as section headers in `SettingsSidebarList`.
|
|
/// `general` holds everything that's ours, not Outline's own settings
|
|
/// categories — labeled "Outpost" so it reads as clearly distinct from the
|
|
/// Outline-sourced groups below it.
|
|
enum SettingsCategory: String, CaseIterable, Identifiable {
|
|
case general
|
|
case account
|
|
case workspace
|
|
|
|
var id: String { rawValue }
|
|
|
|
var title: String? {
|
|
switch self {
|
|
case .general: return "Outpost"
|
|
case .account: return "Account"
|
|
case .workspace: return "Workspace"
|
|
}
|
|
}
|
|
}
|
|
|
|
/// One entry in the Settings sidebar. Mirrors Outline's own settings
|
|
/// categories (Account/Workspace) so this app's settings read as a native
|
|
/// counterpart to the web app's, plus a `general` group for things that are
|
|
/// ours and don't map onto Outline's structure (offline/sync, advanced,
|
|
/// about, appearance). Outline's own version info moved to the sidebar
|
|
/// footer (`SettingsSidebarList`) instead of a standalone
|
|
/// Integrations & Installation section.
|
|
///
|
|
/// Most of the Account/Workspace cases are navigation-only for now —
|
|
/// `SettingsView` renders a "Coming Soon" placeholder for anything not
|
|
/// explicitly built yet. Content lands section by section.
|
|
enum SettingsSection: String, CaseIterable, Identifiable, Hashable {
|
|
// General (ours)
|
|
case appearance, offlineSync, advanced, about
|
|
|
|
// Account
|
|
case profile, preferences, notifications, passkeys, apiAccess
|
|
|
|
// Workspace
|
|
case details, authentication, security, ai, members, groups, templates, emojis, applications, shared, links, webhooks, importData, exportData
|
|
|
|
var id: String { rawValue }
|
|
|
|
var category: SettingsCategory {
|
|
switch self {
|
|
case .appearance, .offlineSync, .advanced, .about:
|
|
return .general
|
|
case .profile, .preferences, .notifications, .passkeys, .apiAccess:
|
|
return .account
|
|
case .details, .authentication, .security, .ai, .members, .groups, .templates, .emojis, .applications, .shared, .links, .webhooks, .importData, .exportData:
|
|
return .workspace
|
|
}
|
|
}
|
|
|
|
var title: String {
|
|
switch self {
|
|
case .appearance: return "Appearance"
|
|
case .offlineSync: return "Offline & Sync"
|
|
case .advanced: return "Advanced"
|
|
case .about: return "About"
|
|
case .profile: return "Profile"
|
|
case .preferences: return "Preferences"
|
|
case .notifications: return "Notifications"
|
|
case .passkeys: return "Passkeys"
|
|
case .apiAccess: return "API & Access"
|
|
case .details: return "Details"
|
|
case .authentication: return "Authentication"
|
|
case .security: return "Security"
|
|
case .ai: return "AI"
|
|
case .members: return "Members"
|
|
case .groups: return "Groups"
|
|
case .templates: return "Templates"
|
|
case .emojis: return "Emojis"
|
|
case .applications: return "Applications"
|
|
case .shared: return "Shared"
|
|
case .links: return "Links"
|
|
case .webhooks: return "Webhooks"
|
|
case .importData: return "Import"
|
|
case .exportData: return "Export"
|
|
}
|
|
}
|
|
|
|
var icon: String {
|
|
switch self {
|
|
case .appearance: return "paintbrush"
|
|
case .offlineSync: return "arrow.triangle.2.circlepath"
|
|
case .advanced: return "wrench.and.screwdriver"
|
|
case .about: return "info.circle"
|
|
case .profile: return "person.crop.circle"
|
|
case .preferences: return "gearshape"
|
|
case .notifications: return "bell"
|
|
case .passkeys: return "key"
|
|
case .apiAccess: return "chevron.left.forwardslash.chevron.right"
|
|
case .details: return "building.2"
|
|
case .authentication: return "lock"
|
|
case .security: return "shield"
|
|
case .ai: return "sparkles"
|
|
case .members: return "person.2"
|
|
case .groups: return "person.3"
|
|
case .templates: return "doc.on.doc"
|
|
case .emojis: return "face.smiling"
|
|
case .applications: return "app.badge"
|
|
case .shared: return "square.and.arrow.up.on.square"
|
|
case .links: return "link"
|
|
case .webhooks: return "bolt.horizontal"
|
|
case .importData: return "square.and.arrow.down"
|
|
case .exportData: return "square.and.arrow.up"
|
|
}
|
|
}
|
|
|
|
/// Everything actually built so far — everything else in Account/
|
|
/// Workspace renders a "Coming Soon" placeholder until its content is
|
|
/// specified and built.
|
|
var isImplemented: Bool {
|
|
switch self {
|
|
case .appearance, .offlineSync, .advanced, .about, .profile, .preferences, .notifications, .passkeys, .apiAccess:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Cross-cutting UI state that doesn't belong to any one screen. Lives at
|
|
/// `OutpostApp` (so both `RootView`'s content and its `⌘,` command can reach
|
|
/// it) and is read wherever something needs to open Settings (the profile
|
|
/// menu) or render it — as a swap of the *existing* sidebar/detail panes in
|
|
/// `ContentView_macOS`, not a separate popup window or an overlay that hides
|
|
/// the sidebar.
|
|
@Observable
|
|
@MainActor
|
|
final class AppNavigation {
|
|
var isShowingSettings = false
|
|
var selectedSettingsSection: SettingsSection? = .appearance
|
|
}
|