Implemented phase 4 for the POC prototype in the Website service.

This commit is contained in:
javier committed 2026-09-21 12:55:35 +02:00
1 parent 95e0a455e8
commit 9403931109
42 files changed
+3407 -36

No files matched your search

@@ -5,7 +5,8 @@ import Persistence
/// The one passkey screen, which both signs in and joins. Drawn bare, without the site's navigation: its only way out is back.
///
/// The prototype stubs the passkey ceremony — see ``SessionController``.
/// A real passkey creates an account, or signs in one created with a passkey — see ``PasskeyController``. The demo accounts have none, so
/// the stubbed demo sign-in stays beside it — see ``SessionController``.
struct SignInPage {
// MARK: Properties
@@ -86,20 +87,29 @@ extension SignInPage: Page {
form(
.class("gate__form"),
.action(.Route.signIn),
.method(.post)
.method(.post),
.custom(name: "data-passkey-form", value: "")
) {
input(
.type(.hidden),
.name("return"),
.value(returnPath)
)
// Shown by `js/passkey.js` once the browser is known to do WebAuthn.
button(
.class("button button--primary button--xl button--block"),
.type(.submit)
.type(.button),
.hidden,
.custom(name: "data-passkey", value: "")
) {
Icon(.key, size: 18)
"Continue with passkey"
}
p(
.class("field__error"),
.custom(name: "role", value: "alert"),
.custom(name: "data-passkey-status", value: "")
) {}
div(.class("field")) {
label(
.class("field__label"),
@@ -128,24 +138,21 @@ extension SignInPage: Page {
error
}
}
div(.class("gate__saved")) {
Icon(.key, size: 16)
span {
strong {
AccountRepository.demoEmail
}
span(.class("gate__saved-note")) {
" · saved passkey"
}
}
}
p(.class("field__hint")) {
"Unknown email? We create your account and passkey in the same step — nothing else to fill in."
}
}
}
p(.class("notice notice--warn")) {
"Prototype: passkeys are stubbed. Continue signs you in as the saved demo buyer; an email signs in as that account, or creates it. To sell, use joost@kestrelrow.example."
div(.class("notice notice--warn gate__demo")) {
p {
"Prototype: the demo accounts have no passkey. The demo sign-in trusts the email above — or signs in the demo buyer, \(AccountRepository.demoEmail), without one. To sell, use joost@kestrelrow.example."
}
button(
.class("button button--outline button--block"),
.type(.submit)
) {
"Demo sign-in, without a passkey"
}
}
}
p(.class("gate__recover")) {
a(.href(.Route.recover)) {
@@ -167,7 +174,7 @@ extension SignInPage: Page {
}
var scripts: [any Asset] {
[StaticFile.shared]
[StaticFile.shared, StaticFile.passkey]
}
var stylesheets: [any Asset] {