import Elementary import Foundation import Infrastructure /// The first sign-in: shown once, to a new account, for the one thing sign-up never asked — a display name. Drawn bare, like the sign-in. struct WelcomePage { // MARK: Properties let analytics: Analytics? let assetVersion: String? let locale: Locale /// The name the field is filled with. let displayName: String /// What is wrong with the name, or `nil` when nothing is. let problem: String? /// The path the visitor continues to. let returnPath: String // MARK: Initializers /// Creates the first-sign-in screen. /// - Parameters: /// - displayName: the name the field is filled with. /// - returnPath: the path the visitor continues to. /// - problem: what is wrong with the name, or `nil` (the default) when nothing is. /// - assetVersion: the version token appended to the page's asset URLs, or `nil` (the default) to leave them unversioned. /// - analytics: the analytics tracker embedded in the document head, or `nil` (the default) to omit it. init( displayName: String, returnPath: String, problem: String? = nil, assetVersion: String? = nil, analytics: Analytics? = nil ) { self.analytics = analytics self.assetVersion = assetVersion self.displayName = displayName self.locale = .init(identifier: "en") self.problem = problem self.returnPath = returnPath } } // MARK: - Page extension WelcomePage: Page { // MARK: Computed var content: some HTML { div(.class("gate")) { header(.class("gate__bar")) { span(.class("gate__wordmark")) { "CCN" } } main(.class("gate__main")) { div(.class("gate__intro")) { p(.class("type-eyebrow")) { "Shown once, on first sign-in" } h1(.class("type-h1")) { "You're in." } p(.class("gate__lead")) { "One thing before sellers and buyers see you." } } form( .class("gate__form"), .action(.Route.welcome), .method(.post) ) { input( .type(.hidden), .name("return"), .value(returnPath) ) div(.class("field")) { label( .class("field__label"), .for("name") ) { "Display name" } input( .class("input input--lg"), .id("name"), .type(.text), .name("name"), .value(displayName), .required, .placeholder("How sellers and buyers will see you"), .custom(name: "autocomplete", value: "nickname"), .custom(name: "maxlength", value: "40") ) FieldNote( name: "name", hint: "You can open a shop later from your account — no need to decide now.", problem: problem ) } div(.class("gate__nudge")) { Icon(.key, size: 20) div { p(.class("gate__nudge-title")) { "Keep a second way in" } p { "A passkey lives on the device that made it. Add a backup from another device on your account page, so a lost phone doesn't lock you out of open orders." } } } button( .class("button button--primary button--xl button--block"), .type(.submit) ) { "Continue" } } } } } @HTMLBuilder var metadata: some HTML { meta( .name("robots"), .content("noindex") ) siteMetadata } var scripts: [any Asset] { [StaticFile.shared] } var stylesheets: [any Asset] { [StaticFile.shared, StaticFile.signIn] } var title: String { "Welcome — CCN" } }