Files
nebula/_migrate/settings.html

1636 lines
71 KiB
HTML

<!DOCTYPE html>
<!--
================================================================================
TEMPL MIGRATION GUIDE: settings.html → views/settings.templ
================================================================================
PAGE OVERVIEW:
- Multi-tab settings page with 7 sections:
1. Profile: Avatar, display name, username, bio, social links, visibility
2. Devices: Linked passkeys and security keys management
3. OAuth: Default scopes, session duration, consent prompts, authorized clients
4. Notifications: Security alerts, transaction, app, marketing preferences
5. Emails: Email address management with verification status
6. Phones: Phone number management with SMS 2FA settings
7. Developer: API keys, webhooks, OAuth application config
MAIN TEMPL COMPONENT:
templ SettingsPage(data SettingsData, activeTab string) {
@layouts.DashboardLayout("settings") {
@PageHeader("Settings", "Manage your account preferences and security")
@SettingsTabGroup(activeTab) {
@ProfileTab(data.Profile)
@DevicesTab(data.Devices)
@OAuthTab(data.OAuth)
@NotificationsTab(data.Notifications)
@EmailsTab(data.Emails)
@PhonesTab(data.Phones)
@DeveloperTab(data.Developer)
}
}
@AddEmailDialog()
@AddPhoneDialog()
@AddDeviceDialog()
@GenerateKeyDialog()
@AddWebhookDialog()
}
HTMX INTEGRATION:
- Tab switching: hx-get="/settings?tab=devices" hx-target="#tab-content" hx-push-url="true"
- Profile save: hx-post="/api/settings/profile" hx-include="[name^='profile-']"
- Avatar upload: hx-post="/api/settings/avatar" hx-encoding="multipart/form-data"
- Add device: hx-post="/api/auth/register-device" (triggers WebAuthn)
- Remove device: hx-delete="/api/devices/{id}" hx-target="closest .device-item" hx-swap="delete"
- Add email: hx-post="/api/settings/emails" hx-target="#emails-list"
- Verify email: hx-post="/api/settings/emails/{id}/resend"
- Toggle notification: hx-post="/api/settings/notifications" hx-vals='{"key":"...", "value": true}'
- Generate API key: hx-post="/api/settings/api-keys" hx-target="#api-keys-list"
- Add webhook: hx-post="/api/settings/webhooks" hx-target="#webhooks-list"
SUB-COMPONENTS TO EXTRACT:
- SettingsTabGroup(activeTab string, children templ.Component)
- ProfileTab(profile ProfileSettings)
- AvatarUpload(avatarURL string, initials string)
- SocialLinksInput(links SocialLinks)
- VisibilityRadioGroup(visibility string)
- DevicesTab(devices []Device)
- DeviceItem(device Device, isCurrent bool)
- OAuthTab(oauth OAuthSettings)
- ScopeCheckboxList(scopes []OAuthScope)
- AuthorizedClientCard(client AuthorizedClient)
- NotificationsTab(prefs NotificationPrefs)
- NotificationSection(title string, items []NotificationItem)
- NotificationRow(item NotificationItem)
- EmailsTab(emails []Email)
- EmailItem(email Email)
- PhonesTab(phones []Phone, smsSettings SMSSettings)
- PhoneItem(phone Phone)
- DeveloperTab(dev DeveloperSettings)
- APIKeyCard(key APIKey)
- WebhookCard(webhook Webhook)
- OAuthAppConfig(config OAuthAppConfig)
- AddEmailDialog()
- AddPhoneDialog()
- AddDeviceDialog()
- GenerateKeyDialog()
- AddWebhookDialog()
STATE/PROPS:
type SettingsData struct {
Profile ProfileSettings
Devices []Device
OAuth OAuthSettings
Notifications NotificationPrefs
Emails []Email
Phones []Phone
Developer DeveloperSettings
}
type ProfileSettings struct {
AvatarURL string
Initials string
DisplayName string
Username string
Bio string
Website string
SocialLinks SocialLinks
Visibility string // "public", "connections", "private"
}
type Device struct {
ID string
Name string
Type string // "laptop", "mobile", "key", "desktop"
Browser string
OS string
AuthType string // "Touch ID", "Face ID", "FIDO2", "Windows Hello"
AddedAt time.Time
LastUsed time.Time
IsCurrent bool
}
type OAuthSettings struct {
DefaultScopes []OAuthScope
SessionDuration string
ConsentPrompt string // "always", "first", "scope"
Clients []AuthorizedClient
}
type NotificationPrefs struct {
SecurityAlerts []NotificationItem
Transactions []NotificationItem
Apps []NotificationItem
Marketing []NotificationItem
}
type Email struct {
ID string
Address string
IsPrimary bool
IsVerified bool
AddedAt time.Time
}
type Phone struct {
ID string
Number string
IsPrimary bool
IsVerified bool
AddedAt time.Time
Use2FA bool
}
type DeveloperSettings struct {
APIKeys []APIKey
Webhooks []Webhook
OAuthApp OAuthAppConfig
DebugMode bool
TestMode bool
ShowRaw bool
}
HTMX PATTERNS:
// Tab switching with URL push
<wa-tab-group hx-on:wa-tab-show="
htmx.ajax('GET', '/settings?tab=' + event.detail.name, {target: '#tab-content', pushUrl: true})
">
// Profile form submission
<form hx-post="/api/settings/profile"
hx-target="#profile-status"
hx-indicator="#save-spinner">
// Device removal with confirmation
<wa-dropdown-item hx-delete="/api/devices/{device.ID}"
hx-target="closest .device-item"
hx-swap="delete"
hx-confirm="Remove this device?">
// Notification toggle
<wa-switch hx-post="/api/settings/notifications"
hx-vals='{"key": "security.new_device", "value": !this.checked}'
hx-swap="none">
// Email verification resend
<wa-dropdown-item hx-post="/api/settings/emails/{email.ID}/resend"
hx-swap="none"
hx-on::after-request="showToast('Verification sent')">
// API key generation
<form hx-post="/api/settings/api-keys"
hx-target="#new-key-display"
hx-swap="innerHTML">
// Webhook test
<wa-dropdown-item hx-post="/api/webhooks/{webhook.ID}/test"
hx-swap="none">
================================================================================
-->
<html lang="en" class="wa-cloak">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Settings - Sonr Motr Wallet</title>
<script src="https://cdn.sonr.org/wa/autoloader.js"></script>
<style>
:root {
--wa-color-primary: #17c2ff;
}
html, body {
min-height: 100%;
padding: 0;
margin: 0;
}
.dashboard-layout {
display: grid;
grid-template-columns: 240px 1fr;
min-height: 100vh;
}
@media (max-width: 768px) {
.dashboard-layout {
grid-template-columns: 1fr;
}
.sidebar {
display: none;
}
}
.sidebar {
border-right: 1px solid var(--wa-color-neutral-200);
padding: var(--wa-space-m);
background: var(--wa-color-surface);
}
.sidebar-header {
padding: var(--wa-space-s) var(--wa-space-xs);
margin-bottom: var(--wa-space-m);
}
.sidebar-nav {
list-style: none;
padding: 0;
margin: 0;
}
.sidebar-nav li {
margin-bottom: var(--wa-space-2xs);
}
.sidebar-nav a {
display: flex;
align-items: center;
gap: var(--wa-space-s);
padding: var(--wa-space-s) var(--wa-space-m);
border-radius: var(--wa-radius-m);
text-decoration: none;
color: var(--wa-color-neutral-700);
font-size: var(--wa-font-size-s);
transition: background 0.15s;
}
.sidebar-nav a:hover {
background: var(--wa-color-surface-alt);
}
.sidebar-nav a.active {
background: var(--wa-color-primary-subtle);
color: var(--wa-color-primary);
font-weight: 500;
}
.main-content {
padding: var(--wa-space-xl);
background: var(--wa-color-surface-alt);
overflow-y: auto;
}
.page-header {
margin-bottom: var(--wa-space-xl);
}
.settings-container {
background: var(--wa-color-surface);
border-radius: var(--wa-radius-l);
overflow: hidden;
}
.settings-tabs {
--indicator-color: var(--wa-color-primary);
}
.settings-tabs wa-tab-panel {
padding: var(--wa-space-xl);
}
.settings-tabs wa-tab-group::part(base) {
display: flex;
flex-direction: column;
}
.settings-tabs wa-tab-group::part(nav) {
background: var(--wa-color-surface);
border-bottom: 1px solid var(--wa-color-neutral-200);
padding: 0 var(--wa-space-m);
}
.form-section {
padding: var(--wa-space-l) 0;
border-bottom: 1px solid var(--wa-color-neutral-100);
}
.form-section:first-child {
padding-top: 0;
}
.form-section:last-child {
border-bottom: none;
padding-bottom: 0;
}
.form-row {
display: grid;
grid-template-columns: 200px 1fr;
gap: var(--wa-space-xl);
align-items: start;
}
@media (max-width: 768px) {
.form-row {
grid-template-columns: 1fr;
gap: var(--wa-space-s);
}
}
.form-label {
padding-top: var(--wa-space-xs);
}
.avatar-upload {
display: flex;
align-items: center;
gap: var(--wa-space-l);
}
.avatar-upload wa-avatar {
--size: 80px;
}
.device-item {
display: flex;
align-items: center;
gap: var(--wa-space-m);
padding: var(--wa-space-m);
background: var(--wa-color-surface-alt);
border-radius: var(--wa-radius-m);
}
.device-icon {
width: 48px;
height: 48px;
border-radius: var(--wa-radius-m);
display: flex;
align-items: center;
justify-content: center;
background: var(--wa-color-surface);
border: 1px solid var(--wa-color-neutral-200);
}
.device-info {
flex: 1;
}
.contact-item {
display: flex;
align-items: center;
gap: var(--wa-space-m);
padding: var(--wa-space-m);
background: var(--wa-color-surface-alt);
border-radius: var(--wa-radius-m);
}
.api-key-display {
display: flex;
align-items: center;
gap: var(--wa-space-s);
padding: var(--wa-space-m);
background: var(--wa-color-neutral-900);
color: var(--wa-color-neutral-100);
border-radius: var(--wa-radius-m);
font-family: var(--wa-font-mono);
font-size: var(--wa-font-size-s);
}
.api-key-display span {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
}
.webhook-item {
padding: var(--wa-space-m);
background: var(--wa-color-surface-alt);
border-radius: var(--wa-radius-m);
}
.notification-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--wa-space-m) 0;
border-bottom: 1px solid var(--wa-color-neutral-100);
}
.notification-row:last-child {
border-bottom: none;
}
.oauth-client-card {
padding: var(--wa-space-m);
background: var(--wa-color-surface-alt);
border-radius: var(--wa-radius-m);
}
</style>
</head>
<body>
<wa-page>
<div class="dashboard-layout">
<aside class="sidebar">
<div class="sidebar-header">
<div class="wa-cluster wa-gap-s">
<wa-avatar initials="S" style="--size: 32px; background: var(--wa-color-primary);"></wa-avatar>
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Sonr Wallet</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">sonr1x9f...7k2m</span>
</div>
</div>
</div>
<nav>
<ul class="sidebar-nav">
<li>
<a href="accounts.html">
<wa-icon name="wallet"></wa-icon>
Accounts
</a>
</li>
<li>
<a href="transactions.html">
<wa-icon name="arrow-right-arrow-left"></wa-icon>
Transactions
</a>
</li>
<li>
<a href="tokens.html">
<wa-icon name="coins"></wa-icon>
Tokens
</a>
</li>
<li>
<a href="nfts.html">
<wa-icon name="image"></wa-icon>
NFTs
</a>
</li>
<li>
<a href="activity.html">
<wa-icon name="chart-line"></wa-icon>
Activity
</a>
</li>
</ul>
</nav>
<wa-divider style="margin: var(--wa-space-l) 0;"></wa-divider>
<ul class="sidebar-nav">
<li>
<a href="connections.html">
<wa-icon name="plug"></wa-icon>
Connections
</a>
</li>
<li>
<a href="device.html">
<wa-icon name="mobile"></wa-icon>
Devices
</a>
</li>
<li>
<a href="service.html">
<wa-icon name="server"></wa-icon>
Services
</a>
</li>
<li>
<a href="settings.html" class="active">
<wa-icon name="gear"></wa-icon>
Settings
</a>
</li>
</ul>
</aside>
<main class="main-content">
<header class="page-header">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xl">Settings</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Manage your account preferences and security</span>
</div>
</header>
<div class="settings-container">
<wa-tab-group class="settings-tabs">
<wa-tab panel="profile">
<wa-icon name="user"></wa-icon>
Profile
</wa-tab>
<wa-tab panel="devices">
<wa-icon name="laptop"></wa-icon>
Devices
</wa-tab>
<wa-tab panel="oauth">
<wa-icon name="key"></wa-icon>
OAuth
</wa-tab>
<wa-tab panel="notifications">
<wa-icon name="bell"></wa-icon>
Notifications
</wa-tab>
<wa-tab panel="emails">
<wa-icon name="envelope"></wa-icon>
Emails
</wa-tab>
<wa-tab panel="phones">
<wa-icon name="phone"></wa-icon>
Phone Numbers
</wa-tab>
<wa-tab panel="developer">
<wa-icon name="code"></wa-icon>
Developer
</wa-tab>
<wa-tab-panel name="profile">
<div class="wa-stack wa-gap-xl">
<div class="form-section">
<div class="form-row">
<div class="form-label">
<span class="wa-heading-s">Avatar</span>
<p class="wa-caption-s" style="color: var(--wa-color-neutral-500); margin: var(--wa-space-2xs) 0 0;">Your public profile image</p>
</div>
<div class="avatar-upload">
<wa-avatar initials="JD" style="background: linear-gradient(135deg, #17c2ff, #0090ff);"></wa-avatar>
<div class="wa-stack wa-gap-s">
<div class="wa-cluster wa-gap-s">
<wa-button size="small" variant="neutral" appearance="outlined">
<wa-icon slot="start" name="upload"></wa-icon>
Upload
</wa-button>
<wa-button size="small" variant="neutral" appearance="plain">Remove</wa-button>
</div>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">JPG, PNG or GIF. Max 2MB.</span>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="form-row">
<div class="form-label">
<span class="wa-heading-s">Display Name</span>
<p class="wa-caption-s" style="color: var(--wa-color-neutral-500); margin: var(--wa-space-2xs) 0 0;">Shown on your public profile</p>
</div>
<wa-input value="John Doe" placeholder="Enter display name"></wa-input>
</div>
</div>
<div class="form-section">
<div class="form-row">
<div class="form-label">
<span class="wa-heading-s">Username</span>
<p class="wa-caption-s" style="color: var(--wa-color-neutral-500); margin: var(--wa-space-2xs) 0 0;">Your unique identifier</p>
</div>
<wa-input value="johndoe" placeholder="Enter username">
<span slot="prefix">@</span>
</wa-input>
</div>
</div>
<div class="form-section">
<div class="form-row">
<div class="form-label">
<span class="wa-heading-s">Bio</span>
<p class="wa-caption-s" style="color: var(--wa-color-neutral-500); margin: var(--wa-space-2xs) 0 0;">Brief description for your profile</p>
</div>
<wa-textarea rows="3" placeholder="Tell us about yourself..." value="Web3 enthusiast and DeFi explorer. Building on Sonr."></wa-textarea>
</div>
</div>
<div class="form-section">
<div class="form-row">
<div class="form-label">
<span class="wa-heading-s">Website</span>
<p class="wa-caption-s" style="color: var(--wa-color-neutral-500); margin: var(--wa-space-2xs) 0 0;">Your personal or project website</p>
</div>
<wa-input type="url" value="https://johndoe.dev" placeholder="https://example.com">
<wa-icon slot="prefix" name="globe"></wa-icon>
</wa-input>
</div>
</div>
<div class="form-section">
<div class="form-row">
<div class="form-label">
<span class="wa-heading-s">Social Links</span>
<p class="wa-caption-s" style="color: var(--wa-color-neutral-500); margin: var(--wa-space-2xs) 0 0;">Connect your social accounts</p>
</div>
<div class="wa-stack wa-gap-m">
<wa-input placeholder="twitter.com/username">
<wa-icon slot="prefix" name="x-twitter" variant="brand"></wa-icon>
</wa-input>
<wa-input placeholder="github.com/username">
<wa-icon slot="prefix" name="github" variant="brand"></wa-icon>
</wa-input>
<wa-input placeholder="discord.gg/invite">
<wa-icon slot="prefix" name="discord" variant="brand"></wa-icon>
</wa-input>
</div>
</div>
</div>
<div class="form-section">
<div class="form-row">
<div class="form-label">
<span class="wa-heading-s">Profile Visibility</span>
<p class="wa-caption-s" style="color: var(--wa-color-neutral-500); margin: var(--wa-space-2xs) 0 0;">Control who can see your profile</p>
</div>
<wa-radio-group value="public">
<wa-radio value="public">
<div class="wa-stack wa-gap-0">
<span>Public</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Anyone can view your profile</span>
</div>
</wa-radio>
<wa-radio value="connections">
<div class="wa-stack wa-gap-0">
<span>Connections Only</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Only connected apps and users</span>
</div>
</wa-radio>
<wa-radio value="private">
<div class="wa-stack wa-gap-0">
<span>Private</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Only you can see your profile</span>
</div>
</wa-radio>
</wa-radio-group>
</div>
</div>
<div class="wa-cluster wa-gap-s" style="justify-content: flex-end;">
<wa-button variant="neutral" appearance="outlined">Cancel</wa-button>
<wa-button variant="brand">Save Changes</wa-button>
</div>
</div>
</wa-tab-panel>
<wa-tab-panel name="devices">
<div class="wa-stack wa-gap-xl">
<div class="wa-flank">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-m">Linked Devices</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Passkeys and security keys registered with your account</span>
</div>
<wa-button size="small" variant="brand">
<wa-icon slot="start" name="plus"></wa-icon>
Add Device
</wa-button>
</div>
<div class="wa-stack wa-gap-m">
<div class="device-item">
<div class="device-icon">
<wa-icon name="laptop" style="font-size: 24px;"></wa-icon>
</div>
<div class="device-info">
<div class="wa-stack wa-gap-0">
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-s">MacBook Pro</span>
<wa-badge variant="success" pill>Current</wa-badge>
</div>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Chrome on macOS - Touch ID</span>
</div>
</div>
<div class="wa-stack wa-gap-0 wa-align-items-end">
<span class="wa-caption-s">Added Dec 15, 2025</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Last used: Just now</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item>
<wa-icon slot="icon" name="pen"></wa-icon>
Rename
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Remove
</wa-dropdown-item>
</wa-dropdown>
</div>
<div class="device-item">
<div class="device-icon">
<wa-icon name="mobile" style="font-size: 24px;"></wa-icon>
</div>
<div class="device-info">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">iPhone 15 Pro</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Safari on iOS - Face ID</span>
</div>
</div>
<div class="wa-stack wa-gap-0 wa-align-items-end">
<span class="wa-caption-s">Added Dec 10, 2025</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Last used: 2 hours ago</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item>
<wa-icon slot="icon" name="pen"></wa-icon>
Rename
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Remove
</wa-dropdown-item>
</wa-dropdown>
</div>
<div class="device-item">
<div class="device-icon">
<wa-icon name="key" style="font-size: 24px;"></wa-icon>
</div>
<div class="device-info">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">YubiKey 5C</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Security Key - FIDO2</span>
</div>
</div>
<div class="wa-stack wa-gap-0 wa-align-items-end">
<span class="wa-caption-s">Added Nov 28, 2025</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Last used: 5 days ago</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item>
<wa-icon slot="icon" name="pen"></wa-icon>
Rename
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Remove
</wa-dropdown-item>
</wa-dropdown>
</div>
<div class="device-item">
<div class="device-icon">
<wa-icon name="desktop" style="font-size: 24px;"></wa-icon>
</div>
<div class="device-info">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Windows Desktop</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Firefox on Windows - Windows Hello</span>
</div>
</div>
<div class="wa-stack wa-gap-0 wa-align-items-end">
<span class="wa-caption-s">Added Oct 15, 2025</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Last used: 2 weeks ago</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item>
<wa-icon slot="icon" name="pen"></wa-icon>
Rename
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Remove
</wa-dropdown-item>
</wa-dropdown>
</div>
</div>
<wa-callout variant="neutral">
<wa-icon slot="icon" name="shield-check"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">Security Recommendation</span>
<span class="wa-caption-s">Register at least 2 devices to ensure account recovery if one is lost.</span>
</div>
</wa-callout>
</div>
</wa-tab-panel>
<wa-tab-panel name="oauth">
<div class="wa-stack wa-gap-xl">
<div class="wa-flank">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-m">OAuth Settings</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Configure your identity provider settings</span>
</div>
</div>
<div class="form-section">
<div class="form-row">
<div class="form-label">
<span class="wa-heading-s">Default Scopes</span>
<p class="wa-caption-s" style="color: var(--wa-color-neutral-500); margin: var(--wa-space-2xs) 0 0;">Permissions granted by default</p>
</div>
<div class="wa-stack wa-gap-s">
<wa-checkbox checked>
<div class="wa-stack wa-gap-0">
<span>openid</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Basic identity information (required)</span>
</div>
</wa-checkbox>
<wa-checkbox checked>
<div class="wa-stack wa-gap-0">
<span>profile</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Display name and avatar</span>
</div>
</wa-checkbox>
<wa-checkbox>
<div class="wa-stack wa-gap-0">
<span>email</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Email address access</span>
</div>
</wa-checkbox>
<wa-checkbox>
<div class="wa-stack wa-gap-0">
<span>wallet:read</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">View wallet balances</span>
</div>
</wa-checkbox>
</div>
</div>
</div>
<div class="form-section">
<div class="form-row">
<div class="form-label">
<span class="wa-heading-s">Session Duration</span>
<p class="wa-caption-s" style="color: var(--wa-color-neutral-500); margin: var(--wa-space-2xs) 0 0;">How long OAuth sessions remain valid</p>
</div>
<wa-select value="7d">
<wa-option value="1h">1 hour</wa-option>
<wa-option value="24h">24 hours</wa-option>
<wa-option value="7d">7 days</wa-option>
<wa-option value="30d">30 days</wa-option>
<wa-option value="never">Never expire</wa-option>
</wa-select>
</div>
</div>
<div class="form-section">
<div class="form-row">
<div class="form-label">
<span class="wa-heading-s">Consent Prompt</span>
<p class="wa-caption-s" style="color: var(--wa-color-neutral-500); margin: var(--wa-space-2xs) 0 0;">When to show permission dialogs</p>
</div>
<wa-radio-group value="first">
<wa-radio value="always">Always prompt for consent</wa-radio>
<wa-radio value="first">Only on first connection</wa-radio>
<wa-radio value="scope">When new scopes requested</wa-radio>
</wa-radio-group>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-stack wa-gap-m">
<div class="wa-flank">
<span class="wa-heading-m">Authorized Clients</span>
<wa-button size="small" variant="neutral" appearance="outlined">View All</wa-button>
</div>
<div class="wa-stack wa-gap-s">
<div class="oauth-client-card">
<div class="wa-flank">
<div class="wa-cluster wa-gap-m">
<wa-avatar initials="U" style="--size: 40px; background: linear-gradient(135deg, #ff007a, #ff5ca0);"></wa-avatar>
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">Uniswap</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">app.uniswap.org</span>
</div>
</div>
<div class="wa-cluster wa-gap-s">
<wa-badge variant="success" pill>Active</wa-badge>
<wa-button size="small" variant="danger" appearance="plain">Revoke</wa-button>
</div>
</div>
</div>
<div class="oauth-client-card">
<div class="wa-flank">
<div class="wa-cluster wa-gap-m">
<wa-avatar initials="O" style="--size: 40px; background: linear-gradient(135deg, #627eea, #4c63d2);"></wa-avatar>
<div class="wa-stack wa-gap-0">
<span class="wa-heading-s">OpenSea</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">opensea.io</span>
</div>
</div>
<div class="wa-cluster wa-gap-s">
<wa-badge variant="neutral" pill>Idle</wa-badge>
<wa-button size="small" variant="danger" appearance="plain">Revoke</wa-button>
</div>
</div>
</div>
</div>
</div>
<div class="wa-cluster wa-gap-s" style="justify-content: flex-end;">
<wa-button variant="neutral" appearance="outlined">Cancel</wa-button>
<wa-button variant="brand">Save Changes</wa-button>
</div>
</div>
</wa-tab-panel>
<wa-tab-panel name="notifications">
<div class="wa-stack wa-gap-xl">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-m">Notification Preferences</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Choose how and when you receive notifications</span>
</div>
<wa-card>
<span slot="header" class="wa-heading-s">Security Alerts</span>
<div class="wa-stack">
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">New device login</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">When your account is accessed from a new device</span>
</div>
<wa-switch checked></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Suspicious activity</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Unusual login attempts or access patterns</span>
</div>
<wa-switch checked></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Password changes</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">When security credentials are modified</span>
</div>
<wa-switch checked></wa-switch>
</div>
</div>
</wa-card>
<wa-card>
<span slot="header" class="wa-heading-s">Transaction Notifications</span>
<div class="wa-stack">
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Incoming transfers</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">When you receive tokens or NFTs</span>
</div>
<wa-switch checked></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Outgoing transfers</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Confirmation of sent transactions</span>
</div>
<wa-switch checked></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Failed transactions</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">When a transaction fails or is reverted</span>
</div>
<wa-switch checked></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Large transactions</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Transactions above threshold</span>
</div>
<div class="wa-cluster wa-gap-s">
<wa-input type="number" value="1000" size="small" style="width: 100px;">
<span slot="suffix">USD</span>
</wa-input>
<wa-switch checked></wa-switch>
</div>
</div>
</div>
</wa-card>
<wa-card>
<span slot="header" class="wa-heading-s">App Notifications</span>
<div class="wa-stack">
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">New app connections</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">When a new app connects to your wallet</span>
</div>
<wa-switch checked></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Signature requests</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">When an app requests a signature</span>
</div>
<wa-switch checked></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Permission changes</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">When app permissions are modified</span>
</div>
<wa-switch></wa-switch>
</div>
</div>
</wa-card>
<wa-card>
<span slot="header" class="wa-heading-s">Marketing & Updates</span>
<div class="wa-stack">
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Product updates</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">New features and improvements</span>
</div>
<wa-switch></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Newsletter</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Weekly digest of Sonr ecosystem news</span>
</div>
<wa-switch></wa-switch>
</div>
</div>
</wa-card>
<div class="wa-cluster wa-gap-s" style="justify-content: flex-end;">
<wa-button variant="brand">Save Preferences</wa-button>
</div>
</div>
</wa-tab-panel>
<wa-tab-panel name="emails">
<div class="wa-stack wa-gap-xl">
<div class="wa-flank">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-m">Email Addresses</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Manage email addresses linked to your account</span>
</div>
<wa-button size="small" variant="brand" id="add-email-btn">
<wa-icon slot="start" name="plus"></wa-icon>
Add Email
</wa-button>
</div>
<div class="wa-stack wa-gap-m">
<div class="contact-item">
<wa-icon name="envelope" style="font-size: 20px; color: var(--wa-color-neutral-500);"></wa-icon>
<div class="wa-stack wa-gap-0" style="flex: 1;">
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-s">john.doe@example.com</span>
<wa-badge variant="success" pill>Primary</wa-badge>
<wa-badge variant="brand" pill>Verified</wa-badge>
</div>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Added Dec 15, 2025</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item disabled>
<wa-icon slot="icon" name="star"></wa-icon>
Set as Primary
</wa-dropdown-item>
<wa-dropdown-item>
<wa-icon slot="icon" name="paper-plane"></wa-icon>
Resend Verification
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item disabled style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Remove
</wa-dropdown-item>
</wa-dropdown>
</div>
<div class="contact-item">
<wa-icon name="envelope" style="font-size: 20px; color: var(--wa-color-neutral-500);"></wa-icon>
<div class="wa-stack wa-gap-0" style="flex: 1;">
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-s">johndoe.work@company.io</span>
<wa-badge variant="brand" pill>Verified</wa-badge>
</div>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Added Nov 20, 2025</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item>
<wa-icon slot="icon" name="star"></wa-icon>
Set as Primary
</wa-dropdown-item>
<wa-dropdown-item>
<wa-icon slot="icon" name="paper-plane"></wa-icon>
Resend Verification
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Remove
</wa-dropdown-item>
</wa-dropdown>
</div>
<div class="contact-item">
<wa-icon name="envelope" style="font-size: 20px; color: var(--wa-color-warning);"></wa-icon>
<div class="wa-stack wa-gap-0" style="flex: 1;">
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-s">backup@gmail.com</span>
<wa-badge variant="warning" pill>Pending</wa-badge>
</div>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Verification sent - check your inbox</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item>
<wa-icon slot="icon" name="paper-plane"></wa-icon>
Resend Verification
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Remove
</wa-dropdown-item>
</wa-dropdown>
</div>
</div>
<wa-callout variant="neutral">
<wa-icon slot="icon" name="circle-info"></wa-icon>
<span class="wa-caption-s">Your primary email is used for account recovery and important notifications. You must have at least one verified email.</span>
</wa-callout>
</div>
</wa-tab-panel>
<wa-tab-panel name="phones">
<div class="wa-stack wa-gap-xl">
<div class="wa-flank">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-m">Phone Numbers</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Manage phone numbers for 2FA and recovery</span>
</div>
<wa-button size="small" variant="brand" id="add-phone-btn">
<wa-icon slot="start" name="plus"></wa-icon>
Add Phone
</wa-button>
</div>
<div class="wa-stack wa-gap-m">
<div class="contact-item">
<wa-icon name="phone" style="font-size: 20px; color: var(--wa-color-neutral-500);"></wa-icon>
<div class="wa-stack wa-gap-0" style="flex: 1;">
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-s">+1 (555) 123-4567</span>
<wa-badge variant="success" pill>Primary</wa-badge>
<wa-badge variant="brand" pill>Verified</wa-badge>
</div>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Added Dec 15, 2025 - Used for 2FA</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item disabled>
<wa-icon slot="icon" name="star"></wa-icon>
Set as Primary
</wa-dropdown-item>
<wa-dropdown-item>
<wa-icon slot="icon" name="message"></wa-icon>
Send Test SMS
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item disabled style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Remove
</wa-dropdown-item>
</wa-dropdown>
</div>
<div class="contact-item">
<wa-icon name="phone" style="font-size: 20px; color: var(--wa-color-neutral-500);"></wa-icon>
<div class="wa-stack wa-gap-0" style="flex: 1;">
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-s">+44 7700 900123</span>
<wa-badge variant="brand" pill>Verified</wa-badge>
</div>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Added Oct 5, 2025 - Backup number</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item>
<wa-icon slot="icon" name="star"></wa-icon>
Set as Primary
</wa-dropdown-item>
<wa-dropdown-item>
<wa-icon slot="icon" name="message"></wa-icon>
Send Test SMS
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Remove
</wa-dropdown-item>
</wa-dropdown>
</div>
</div>
<wa-card>
<span slot="header" class="wa-heading-s">SMS Authentication</span>
<div class="wa-stack">
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Enable SMS 2FA</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Receive codes via SMS for high-risk actions</span>
</div>
<wa-switch checked></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">SMS recovery codes</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Allow account recovery via SMS</span>
</div>
<wa-switch></wa-switch>
</div>
</div>
</wa-card>
<wa-callout variant="warning">
<wa-icon slot="icon" name="triangle-alert"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">SMS Security Notice</span>
<span class="wa-caption-s">SMS-based authentication is less secure than passkeys. We recommend using passkeys as your primary authentication method.</span>
</div>
</wa-callout>
</div>
</wa-tab-panel>
<wa-tab-panel name="developer">
<div class="wa-stack wa-gap-xl">
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-m">Developer Settings</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">API access and integration options</span>
</div>
<wa-card>
<div slot="header" class="wa-flank">
<span class="wa-heading-s">API Keys</span>
<wa-button size="small" variant="neutral" appearance="outlined" id="generate-key-btn">
<wa-icon slot="start" name="plus"></wa-icon>
Generate Key
</wa-button>
</div>
<div class="wa-stack wa-gap-m">
<div class="wa-stack wa-gap-s">
<div class="wa-flank">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Production Key</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Created Dec 1, 2025</span>
</div>
<wa-badge variant="success" pill>Active</wa-badge>
</div>
<div class="api-key-display">
<span>sk_live_••••••••••••••••••••••••3f8b</span>
<wa-copy-button value="sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f23f8b"></wa-copy-button>
<wa-tooltip content="Reveal key">
<wa-icon-button name="eye" label="Reveal"></wa-icon-button>
</wa-tooltip>
</div>
</div>
<div class="wa-stack wa-gap-s">
<div class="wa-flank">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Test Key</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Created Dec 1, 2025</span>
</div>
<wa-badge variant="neutral" pill>Test Mode</wa-badge>
</div>
<div class="api-key-display">
<span>sk_test_••••••••••••••••••••••••9a2c</span>
<wa-copy-button value="sk_test_z9y8x7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e8d7c6b5a4z3y2x1w0v9u89a2c"></wa-copy-button>
<wa-tooltip content="Reveal key">
<wa-icon-button name="eye" label="Reveal"></wa-icon-button>
</wa-tooltip>
</div>
</div>
</div>
</wa-card>
<wa-card>
<div slot="header" class="wa-flank">
<span class="wa-heading-s">Webhooks</span>
<wa-button size="small" variant="neutral" appearance="outlined" id="add-webhook-btn">
<wa-icon slot="start" name="plus"></wa-icon>
Add Endpoint
</wa-button>
</div>
<div class="wa-stack wa-gap-m">
<div class="webhook-item">
<div class="wa-flank">
<div class="wa-stack wa-gap-0">
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-xs">https://api.myapp.com/webhooks/sonr</span>
<wa-badge variant="success" pill>Active</wa-badge>
</div>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">All events - Last triggered 2 hours ago</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item>
<wa-icon slot="icon" name="pen"></wa-icon>
Edit
</wa-dropdown-item>
<wa-dropdown-item>
<wa-icon slot="icon" name="paper-plane"></wa-icon>
Send Test
</wa-dropdown-item>
<wa-dropdown-item>
<wa-icon slot="icon" name="clock-rotate-left"></wa-icon>
View Logs
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Delete
</wa-dropdown-item>
</wa-dropdown>
</div>
</div>
<div class="webhook-item">
<div class="wa-flank">
<div class="wa-stack wa-gap-0">
<div class="wa-cluster wa-gap-xs">
<span class="wa-heading-xs">https://hooks.slack.com/services/...</span>
<wa-badge variant="warning" pill>Failing</wa-badge>
</div>
<span class="wa-caption-xs" style="color: var(--wa-color-danger);">transaction.* events - 3 failures in last hour</span>
</div>
<wa-dropdown>
<wa-icon-button slot="trigger" name="ellipsis-vertical" label="Options"></wa-icon-button>
<wa-dropdown-item>
<wa-icon slot="icon" name="pen"></wa-icon>
Edit
</wa-dropdown-item>
<wa-dropdown-item>
<wa-icon slot="icon" name="arrow-rotate-right"></wa-icon>
Retry Failed
</wa-dropdown-item>
<wa-dropdown-item>
<wa-icon slot="icon" name="clock-rotate-left"></wa-icon>
View Logs
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-dropdown-item style="color: var(--wa-color-danger);">
<wa-icon slot="icon" name="trash"></wa-icon>
Delete
</wa-dropdown-item>
</wa-dropdown>
</div>
</div>
</div>
</wa-card>
<wa-card>
<span slot="header" class="wa-heading-s">OAuth Application</span>
<div class="wa-stack wa-gap-l">
<div class="form-row" style="grid-template-columns: 140px 1fr;">
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Client ID</span>
<div class="wa-cluster wa-gap-s">
<code style="font-family: var(--wa-font-mono); font-size: var(--wa-font-size-s);">sonr_client_a1b2c3d4e5f6</code>
<wa-copy-button value="sonr_client_a1b2c3d4e5f6"></wa-copy-button>
</div>
</div>
<div class="form-row" style="grid-template-columns: 140px 1fr;">
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Client Secret</span>
<div class="wa-cluster wa-gap-s">
<code style="font-family: var(--wa-font-mono); font-size: var(--wa-font-size-s);">••••••••••••••••</code>
<wa-copy-button value="sonr_secret_x9y8z7w6v5u4t3s2r1"></wa-copy-button>
<wa-button size="small" appearance="plain">Regenerate</wa-button>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-stack wa-gap-s">
<span class="wa-heading-xs">Redirect URIs</span>
<wa-input value="https://myapp.com/auth/callback" placeholder="https://example.com/callback">
<wa-icon-button slot="suffix" name="trash" label="Remove"></wa-icon-button>
</wa-input>
<wa-input value="http://localhost:3000/auth/callback" placeholder="https://example.com/callback">
<wa-icon-button slot="suffix" name="trash" label="Remove"></wa-icon-button>
</wa-input>
<wa-button size="small" appearance="plain">
<wa-icon slot="start" name="plus"></wa-icon>
Add URI
</wa-button>
</div>
</div>
</wa-card>
<wa-card>
<span slot="header" class="wa-heading-s">Developer Mode</span>
<div class="wa-stack">
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Enable debug logging</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Log detailed API requests and responses</span>
</div>
<wa-switch></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Test mode</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Use testnet for all transactions</span>
</div>
<wa-switch checked></wa-switch>
</div>
<div class="notification-row">
<div class="wa-stack wa-gap-0">
<span class="wa-heading-xs">Show raw responses</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">Display JSON in UI for debugging</span>
</div>
<wa-switch></wa-switch>
</div>
</div>
</wa-card>
<wa-callout variant="neutral">
<wa-icon slot="icon" name="book"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">API Documentation</span>
<span class="wa-caption-s">
View our <a href="#" style="color: var(--wa-color-primary);">API reference</a> and
<a href="#" style="color: var(--wa-color-primary);">integration guides</a> to get started.
</span>
</div>
</wa-callout>
<div class="wa-cluster wa-gap-s" style="justify-content: flex-end;">
<wa-button variant="neutral" appearance="outlined">Cancel</wa-button>
<wa-button variant="brand">Save Changes</wa-button>
</div>
</div>
</wa-tab-panel>
</wa-tab-group>
</div>
</main>
</div>
<wa-dialog label="Add Email Address" id="add-email-dialog" style="--width: 420px;">
<div class="wa-stack wa-gap-l">
<wa-input type="email" label="Email Address" placeholder="you@example.com" autofocus>
<wa-icon slot="prefix" name="envelope"></wa-icon>
</wa-input>
<wa-callout variant="neutral">
<wa-icon slot="icon" name="circle-info"></wa-icon>
<span class="wa-caption-s">We'll send a verification link to this address.</span>
</wa-callout>
</div>
<div slot="footer" class="wa-cluster wa-gap-s" style="justify-content: flex-end; width: 100%;">
<wa-button variant="neutral" appearance="outlined" data-dialog="close">Cancel</wa-button>
<wa-button variant="brand">Send Verification</wa-button>
</div>
</wa-dialog>
<wa-dialog label="Add Phone Number" id="add-phone-dialog" style="--width: 420px;">
<div class="wa-stack wa-gap-l">
<div class="wa-cluster wa-gap-s">
<wa-select value="+1" style="width: 100px;">
<wa-option value="+1">+1</wa-option>
<wa-option value="+44">+44</wa-option>
<wa-option value="+49">+49</wa-option>
<wa-option value="+33">+33</wa-option>
<wa-option value="+81">+81</wa-option>
</wa-select>
<wa-input type="tel" label="Phone Number" placeholder="(555) 123-4567" style="flex: 1;">
<wa-icon slot="prefix" name="phone"></wa-icon>
</wa-input>
</div>
<wa-callout variant="neutral">
<wa-icon slot="icon" name="circle-info"></wa-icon>
<span class="wa-caption-s">We'll send a verification code via SMS.</span>
</wa-callout>
</div>
<div slot="footer" class="wa-cluster wa-gap-s" style="justify-content: flex-end; width: 100%;">
<wa-button variant="neutral" appearance="outlined" data-dialog="close">Cancel</wa-button>
<wa-button variant="brand">Send Code</wa-button>
</div>
</wa-dialog>
<wa-dialog label="Add Device" id="add-device-dialog" style="--width: 480px;">
<div class="wa-stack wa-gap-l" style="text-align: center;">
<wa-icon name="fingerprint" style="font-size: 64px; color: var(--wa-color-primary);"></wa-icon>
<div class="wa-stack wa-gap-xs">
<span class="wa-heading-m">Register a Passkey</span>
<span class="wa-caption-m" style="color: var(--wa-color-neutral-500);">
Use your device's built-in authenticator (Face ID, Touch ID, Windows Hello) or a security key.
</span>
</div>
<wa-button variant="brand" size="large" style="width: 100%;">
<wa-icon slot="start" name="plus"></wa-icon>
Register Device
</wa-button>
<wa-divider>or</wa-divider>
<wa-button variant="neutral" appearance="outlined" style="width: 100%;">
<wa-icon slot="start" name="key"></wa-icon>
Use Security Key
</wa-button>
</div>
<div slot="footer" class="wa-cluster" style="justify-content: center; width: 100%;">
<wa-button variant="neutral" appearance="plain" data-dialog="close">Cancel</wa-button>
</div>
</wa-dialog>
<wa-dialog label="Generate API Key" id="generate-key-dialog" style="--width: 420px;">
<div class="wa-stack wa-gap-l">
<wa-input label="Key Name" placeholder="e.g., Production Server" autofocus>
<wa-icon slot="prefix" name="tag"></wa-icon>
</wa-input>
<wa-select label="Environment" value="test">
<wa-option value="test">Test Mode</wa-option>
<wa-option value="live">Production</wa-option>
</wa-select>
<wa-select label="Permissions" value="full">
<wa-option value="full">Full Access</wa-option>
<wa-option value="read">Read Only</wa-option>
<wa-option value="write">Write Only</wa-option>
</wa-select>
<wa-callout variant="warning">
<wa-icon slot="icon" name="triangle-alert"></wa-icon>
<span class="wa-caption-s">Your secret key will only be shown once. Store it securely.</span>
</wa-callout>
</div>
<div slot="footer" class="wa-cluster wa-gap-s" style="justify-content: flex-end; width: 100%;">
<wa-button variant="neutral" appearance="outlined" data-dialog="close">Cancel</wa-button>
<wa-button variant="brand">Generate Key</wa-button>
</div>
</wa-dialog>
<wa-dialog label="Add Webhook Endpoint" id="add-webhook-dialog" style="--width: 480px;">
<div class="wa-stack wa-gap-l">
<wa-input label="Endpoint URL" placeholder="https://api.example.com/webhooks" type="url">
<wa-icon slot="prefix" name="globe"></wa-icon>
</wa-input>
<wa-input label="Description" placeholder="Optional description">
<wa-icon slot="prefix" name="align-left"></wa-icon>
</wa-input>
<div class="wa-stack wa-gap-s">
<span class="wa-heading-xs">Events to Subscribe</span>
<wa-checkbox checked>
<div class="wa-stack wa-gap-0">
<span>transaction.*</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">All transaction events</span>
</div>
</wa-checkbox>
<wa-checkbox checked>
<div class="wa-stack wa-gap-0">
<span>connection.*</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">App connection events</span>
</div>
</wa-checkbox>
<wa-checkbox>
<div class="wa-stack wa-gap-0">
<span>signature.*</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Signature request events</span>
</div>
</wa-checkbox>
<wa-checkbox>
<div class="wa-stack wa-gap-0">
<span>account.*</span>
<span class="wa-caption-xs" style="color: var(--wa-color-neutral-500);">Account update events</span>
</div>
</wa-checkbox>
</div>
</div>
<div slot="footer" class="wa-cluster wa-gap-s" style="justify-content: flex-end; width: 100%;">
<wa-button variant="neutral" appearance="outlined" data-dialog="close">Cancel</wa-button>
<wa-button variant="brand">Create Webhook</wa-button>
</div>
</wa-dialog>
</wa-page>
<script>
const addEmailDialog = document.getElementById('add-email-dialog');
const addPhoneDialog = document.getElementById('add-phone-dialog');
const addDeviceDialog = document.getElementById('add-device-dialog');
const generateKeyDialog = document.getElementById('generate-key-dialog');
const addWebhookDialog = document.getElementById('add-webhook-dialog');
document.getElementById('add-email-btn')?.addEventListener('click', () => {
addEmailDialog.open = true;
});
document.getElementById('add-phone-btn')?.addEventListener('click', () => {
addPhoneDialog.open = true;
});
document.querySelectorAll('wa-button').forEach(btn => {
if (btn.textContent.includes('Add Device')) {
btn.addEventListener('click', () => {
addDeviceDialog.open = true;
});
}
});
document.getElementById('generate-key-btn')?.addEventListener('click', () => {
generateKeyDialog.open = true;
});
document.getElementById('add-webhook-btn')?.addEventListener('click', () => {
addWebhookDialog.open = true;
});
document.querySelectorAll('.sidebar-nav a').forEach(link => {
link.addEventListener('click', function(e) {
if (this.getAttribute('href') === '#') {
e.preventDefault();
}
document.querySelectorAll('.sidebar-nav a').forEach(l => l.classList.remove('active'));
this.classList.add('active');
});
});
</script>
</body>
</html>