import Foundation extension String { /// A namespace for the paths of the site's screens. /// /// Screens not built yet are listed too, and answer with the not-found page until they are. enum Route { /// The account screen. static let account = "/account" /// The collection tracker. static let collection = "/collection" /// The events screen. static let events = "/events" /// The public grading guide. static let gradingGuide = "/grading-guide" /// The browse / home screen. static let home = "/" /// The message threads. static let messages = "/messages" /// The open-a-shop onboarding. static let openShop = "/sell/open-a-shop" /// The privacy statement. static let privacy = "/privacy" /// The passkey recovery screen. static let recover = "/recover" /// The search results screen. static let search = "/search" /// The seller dashboard. static let sellerDashboard = "/sell" /// The rules sellers agree to. static let sellerRules = "/seller-rules" /// The series index. static let series = "/series" /// The passkey sign-in screen. static let signIn = "/sign-in" /// The terms of service. static let terms = "/terms" /// The want list. static let wants = "/wants" /// The path of a listing's detail screen. /// - Parameter slug: the listing's URL slug. static func listing( _ slug: String ) -> String { "/listing/\(slug)" } /// The path of a shop's public screen. /// - Parameter slug: the shop's URL slug. static func shop( _ slug: String ) -> String { "/shop/\(slug)" } /// The path of the sign-in screen, returning to the given path afterwards. /// - Parameter path: the path the visitor's gated action started from. static func signIn( returningTo path: String ) -> String { "\(signIn)?return=\(path.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? "")" } } } // MARK: - Constants private extension CharacterSet { /// The characters a query value carries unescaped. static let urlQueryValueAllowed = CharacterSet.urlQueryAllowed.subtracting(.init(charactersIn: "&=+?#")) }