PasskeyToast.tsx

2.5 KB · raw

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}