Files
nebula/_migrate/welcome.html

537 lines
17 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<!--
================================================================================
TEMPL MIGRATION GUIDE: welcome.html → views/welcome.templ
================================================================================
PAGE OVERVIEW:
- Onboarding landing page with 3-step stepper (Welcome → Learn → Get Started)
- Routes users to register.html or login.html
- Network status indicator in footer
- VIEWPORT: Optimized for popup/webview (360×540 to 480×680)
VIEWPORT CONSTRAINTS (Auth Popup/Webview):
- Target sizes: 360×540 (small), 420×600 (medium), 480×680 (large)
- Card max-width: 48ch (~384px) fits all viewport sizes
- Padding scales down on smaller viewports via media queries
- Touch targets minimum 44×44px for mobile accessibility
- Footer should remain visible without scrolling on step 1/3
- Scrollable content area for step 2 (feature list)
MAIN TEMPL COMPONENT:
templ WelcomePage() {
@layouts.CenteredCard("Welcome - Sonr Motr Wallet") {
@OnboardingStepper(1)
@WelcomeStep1()
}
}
HTMX INTEGRATION:
- Replace onclick="goToStep(N)" with hx-get="/welcome/step/N" hx-target="#step-content"
- Stepper state managed server-side via URL params or session
- Navigation buttons trigger HTMX partial updates
STATE MANAGEMENT:
- Current step passed as prop: currentStep int
- Step completion status tracked server-side
================================================================================
-->
<html lang="en" class="wa-cloak">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Welcome - 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;
}
.main-centered {
display: flex;
justify-content: center;
align-items: center;
min-height: 100%;
padding: var(--wa-space-l);
box-sizing: border-box;
}
.main-centered wa-card {
width: 100%;
max-width: 48ch;
}
.step {
display: none;
}
.step.active {
display: block;
}
.onboarding-stepper {
display: flex;
justify-content: center;
align-items: center;
gap: var(--wa-space-s);
padding: var(--wa-space-m) 0;
}
.stepper-item {
display: flex;
align-items: center;
gap: var(--wa-space-xs);
}
.stepper-number {
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: var(--wa-font-size-s);
font-weight: 600;
background: var(--wa-color-neutral-200);
color: var(--wa-color-neutral-600);
transition: all 0.3s;
}
.stepper-item.active .stepper-number {
background: var(--wa-color-primary);
color: white;
box-shadow: 0 0 0 4px var(--wa-color-primary-subtle);
}
.stepper-item.completed .stepper-number {
background: var(--wa-color-success);
color: white;
}
.stepper-label {
font-size: var(--wa-font-size-xs);
color: var(--wa-color-neutral-500);
display: none;
}
@media (min-width: 480px) {
.stepper-label {
display: block;
}
}
/* Viewport constraints for popup/webview (360-480px width) */
@media (max-width: 400px) {
.main-centered {
padding: var(--wa-space-m);
}
.main-centered wa-card {
max-width: 100%;
}
.hero-icon {
width: 64px;
height: 64px;
}
.hero-icon wa-icon {
font-size: 32px;
}
.feature-item {
padding: var(--wa-space-s);
}
.feature-icon {
width: 32px;
height: 32px;
}
.action-card {
padding: var(--wa-space-m);
}
.action-card wa-icon {
font-size: 2rem;
}
}
@media (max-height: 600px) {
.hero-icon {
width: 56px;
height: 56px;
margin-bottom: var(--wa-space-m);
}
.hero-icon wa-icon {
font-size: 28px;
}
.onboarding-stepper {
padding: var(--wa-space-s) 0;
}
}
.stepper-item.active .stepper-label {
color: var(--wa-color-primary);
font-weight: 500;
}
.stepper-line {
width: 40px;
height: 2px;
background: var(--wa-color-neutral-200);
transition: background 0.3s;
}
.stepper-line.completed {
background: var(--wa-color-success);
}
.hero-icon {
width: 80px;
height: 80px;
border-radius: var(--wa-radius-l);
background: linear-gradient(135deg, var(--wa-color-primary), #0090ff);
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto var(--wa-space-l);
box-shadow: 0 8px 32px rgba(23, 194, 255, 0.3);
}
.hero-icon wa-icon {
font-size: 40px;
color: white;
}
.feature-item {
display: flex;
align-items: flex-start;
gap: var(--wa-space-m);
padding: var(--wa-space-m);
background: var(--wa-color-surface-alt);
border-radius: var(--wa-radius-m);
}
.feature-icon {
width: 40px;
height: 40px;
border-radius: var(--wa-radius-s);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.feature-icon.security {
background: var(--wa-color-success-subtle);
color: var(--wa-color-success);
}
.feature-icon.speed {
background: var(--wa-color-primary-subtle);
color: var(--wa-color-primary);
}
.feature-icon.privacy {
background: var(--wa-color-warning-subtle);
color: var(--wa-color-warning);
}
.action-card {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--wa-space-m);
padding: var(--wa-space-xl);
background: var(--wa-color-surface-alt);
border-radius: var(--wa-radius-l);
border: 2px solid transparent;
cursor: pointer;
transition: all 0.2s;
text-align: center;
}
.action-card:hover {
border-color: var(--wa-color-primary);
background: var(--wa-color-primary-subtle);
}
.action-card wa-icon {
font-size: 2.5rem;
color: var(--wa-color-primary);
}
.network-status {
display: flex;
align-items: center;
justify-content: center;
gap: var(--wa-space-xs);
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--wa-color-success);
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
</style>
</head>
<body>
<wa-page>
<main class="main-centered">
<wa-card>
<div slot="header">
<div class="onboarding-stepper">
<div class="stepper-item active" data-step="1">
<div class="stepper-number">1</div>
<span class="stepper-label">Welcome</span>
</div>
<div class="stepper-line"></div>
<div class="stepper-item" data-step="2">
<div class="stepper-number">2</div>
<span class="stepper-label">Learn</span>
</div>
<div class="stepper-line"></div>
<div class="stepper-item" data-step="3">
<div class="stepper-number">3</div>
<span class="stepper-label">Get Started</span>
</div>
</div>
</div>
<div class="step active" data-step="1">
<div class="wa-stack wa-gap-l">
<div class="hero-icon">
<wa-icon name="wallet" family="duotone"></wa-icon>
</div>
<div class="wa-stack wa-gap-xs" style="text-align: center;">
<h1 class="wa-heading-xl">Welcome to Sonr</h1>
<p class="wa-caption-m" style="color: var(--wa-color-neutral-600);">
Your self-sovereign identity wallet powered by WebAssembly
</p>
</div>
<wa-divider></wa-divider>
<div class="wa-stack wa-gap-s">
<div class="feature-item">
<div class="feature-icon security">
<wa-icon name="shield-check"></wa-icon>
</div>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">Passwordless Security</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">
Authenticate with biometrics or hardware keys - no passwords to remember or steal
</span>
</div>
</div>
<div class="feature-item">
<div class="feature-icon speed">
<wa-icon name="bolt"></wa-icon>
</div>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">WASM-Powered</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">
Wallet runs entirely in your browser - fast, secure, and always available
</span>
</div>
</div>
<div class="feature-item">
<div class="feature-icon privacy">
<wa-icon name="user-shield"></wa-icon>
</div>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">You Own Your Data</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">
Self-sovereign identity means your keys never leave your device
</span>
</div>
</div>
</div>
<wa-button variant="brand" size="large" style="width: 100%;" onclick="goToStep(2)">
Learn More
<wa-icon slot="end" name="arrow-right"></wa-icon>
</wa-button>
</div>
</div>
<div class="step" data-step="2">
<div class="wa-stack wa-gap-l">
<div class="wa-stack wa-gap-xs" style="text-align: center;">
<h2 class="wa-heading-l">How Motr Works</h2>
<p class="wa-caption-m" style="color: var(--wa-color-neutral-600);">
A next-generation wallet built on WebAuthn and WASM
</p>
</div>
<wa-divider></wa-divider>
<div class="wa-stack wa-gap-m">
<wa-callout variant="neutral">
<wa-icon slot="icon" name="microchip"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">WebAssembly Runtime</span>
<span class="wa-caption-s">Your wallet logic runs as compiled Go code in a secure WASM sandbox, directly in your browser.</span>
</div>
</wa-callout>
<wa-callout variant="neutral">
<wa-icon slot="icon" name="fingerprint"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">Passkey Authentication</span>
<span class="wa-caption-s">Use Face ID, Touch ID, or hardware security keys. Your biometrics stay on your device.</span>
</div>
</wa-callout>
<wa-callout variant="neutral">
<wa-icon slot="icon" name="network-wired"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">Decentralized Identity</span>
<span class="wa-caption-s">Connect to any app with OpenID Connect - you control what data to share.</span>
</div>
</wa-callout>
<wa-callout variant="neutral">
<wa-icon slot="icon" name="key"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-xs">Multi-Chain Support</span>
<span class="wa-caption-s">One wallet for Sonr, Ethereum, Cosmos, Bitcoin and more via IBC.</span>
</div>
</wa-callout>
</div>
<div class="wa-cluster wa-gap-s" style="justify-content: space-between;">
<wa-button variant="neutral" appearance="outlined" onclick="goToStep(1)">
<wa-icon slot="start" name="arrow-left"></wa-icon>
Back
</wa-button>
<wa-button variant="brand" onclick="goToStep(3)">
Get Started
<wa-icon slot="end" name="arrow-right"></wa-icon>
</wa-button>
</div>
</div>
</div>
<div class="step" data-step="3">
<div class="wa-stack wa-gap-l">
<div class="wa-stack wa-gap-xs" style="text-align: center;">
<h2 class="wa-heading-l">Ready to Begin?</h2>
<p class="wa-caption-m" style="color: var(--wa-color-neutral-600);">
Create a new wallet or sign in to an existing one
</p>
</div>
<wa-divider></wa-divider>
<div class="wa-grid" style="--min-column-size: 180px; gap: var(--wa-space-m);">
<div class="action-card" onclick="window.location.href='register.html'">
<wa-icon name="user-plus" family="duotone"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-m">Create Wallet</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">
New to Sonr? Set up your wallet in minutes
</span>
</div>
</div>
<div class="action-card" onclick="window.location.href='login.html'">
<wa-icon name="right-to-bracket" family="duotone"></wa-icon>
<div class="wa-stack wa-gap-2xs">
<span class="wa-heading-m">Sign In</span>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-500);">
Access your existing wallet
</span>
</div>
</div>
</div>
<wa-divider>or</wa-divider>
<wa-button variant="neutral" appearance="outlined" style="width: 100%;" onclick="scanQR()">
<wa-icon slot="start" name="qrcode"></wa-icon>
Scan QR Code
</wa-button>
<wa-callout variant="brand" appearance="filled">
<wa-icon slot="icon" name="circle-info"></wa-icon>
<span class="wa-caption-s">
Already have a passkey registered on another device? Use QR code to sync your wallet.
</span>
</wa-callout>
<wa-button variant="neutral" appearance="plain" onclick="goToStep(2)" style="width: 100%;">
<wa-icon slot="start" name="arrow-left"></wa-icon>
Back to How It Works
</wa-button>
</div>
</div>
<footer slot="footer">
<div class="wa-stack wa-gap-m wa-align-items-center">
<div class="network-status">
<div class="status-dot"></div>
<span class="wa-caption-s" style="color: var(--wa-color-neutral-600);">
Sonr Network: <strong style="color: var(--wa-color-success);">Operational</strong>
</span>
</div>
<div class="wa-cluster wa-justify-content-center wa-gap-m">
<wa-button appearance="plain" size="small" onclick="window.open('https://sonr.io', '_blank')">
Learn about Sonr
</wa-button>
<span style="color: var(--wa-color-neutral-300);">|</span>
<wa-button appearance="plain" size="small" onclick="window.open('https://docs.sonr.io', '_blank')">
Documentation
</wa-button>
</div>
</div>
</footer>
</wa-card>
</main>
</wa-page>
<script>
let currentStep = 1;
function goToStep(step) {
document.querySelectorAll('.step').forEach(el => el.classList.remove('active'));
document.querySelectorAll('.stepper-item').forEach(item => {
const itemStep = parseInt(item.dataset.step);
item.classList.remove('active', 'completed');
if (itemStep < step) {
item.classList.add('completed');
} else if (itemStep === step) {
item.classList.add('active');
}
});
document.querySelectorAll('.stepper-line').forEach((line, index) => {
line.classList.toggle('completed', index < step - 1);
});
const targetStep = document.querySelector(`.step[data-step="${step}"]`);
if (targetStep) {
targetStep.classList.add('active');
}
currentStep = step;
}
function scanQR() {
alert('QR Scanner would open here - scan a code from another device to sync your wallet.');
}
</script>
</body>
</html>