1import { createSignal, onMount, onCleanup } from 'solid-js';23interface PasskeyToastProps {4 site: string;5 displayName: string;6 username: string;7 requestId: string;8 onSignIn: () => void;9 onDeny: () => void;10}1112const TIMEOUT_MS = 30_000;1314export function PasskeyToast(props: PasskeyToastProps) {15 const [visible, setVisible] = createSignal(false);16 const [exiting, setExiting] = createSignal(false);17 let timeoutId: number;1819 onMount(() => {20 requestAnimationFrame(() => setVisible(true));2122 timeoutId = window.setTimeout(() => {23 handleDeny();24 }, TIMEOUT_MS);25 });2627 onCleanup(() => {28 clearTimeout(timeoutId);29 });3031 function handleSignIn() {32 clearTimeout(timeoutId);33 exit(props.onSignIn);34 }3536 function handleDeny() {37 clearTimeout(timeoutId);38 exit(props.onDeny);39 }4041 function exit(callback: () => void) {42 setExiting(true);43 setTimeout(callback, 220);44 }4546 return (47 <div48 class={[49 'peach-passkey-toast',50 visible() ? 'is-visible' : '',51 exiting() ? 'is-exiting' : '',52 ].join(' ')}53 >54 <div class="peach-passkey-toast-site">55 <div class="peach-passkey-toast-icon">56 <KeyIcon />57 </div>58 <span class="peach-passkey-toast-domain">{props.site}</span>59 </div>6061 <p class="peach-passkey-toast-headline">62 sign in with passkey?63 </p>6465 <div class="peach-passkey-toast-account">66 <span class="peach-passkey-toast-display-name">67 {props.displayName}68 </span>69 <span class="peach-passkey-toast-username">70 {props.username}71 </span>72 </div>7374 <div class="peach-passkey-toast-countdown">75 <div76 class="peach-passkey-toast-countdown-bar"77 style={{ 'animation-duration': `${TIMEOUT_MS}ms` }}78 />79 </div>8081 <div class="peach-passkey-toast-actions">82 <button83 class="peach-passkey-toast-btn peach-passkey-toast-btn--deny"84 onClick={handleDeny}85 >86 deny87 </button>88 <button89 class="peach-passkey-toast-btn peach-passkey-toast-btn--signin"90 onClick={handleSignIn}91 >92 sign in →93 </button>94 </div>95 </div>96 );97}9899function KeyIcon() {100 return (101 <svg width="16" height="16" viewBox="0 0 16 16" fill="none">102 <circle cx="5.5" cy="7.5" r="3" stroke="currentColor" stroke-width="1.5"/>103 <path d="M8 7.5h5.5M11 7.5v2" stroke="currentColor"104 stroke-width="1.5" stroke-linecap="round"/>105 </svg>106 );107}