clavitor/clavitor.com/account/templates/regions.tmpl

264 lines
12 KiB
Cheetah

{{define "page"}}
<header class="topbar">
<div class="container">
<div class="topbar-inner">
<a href="{{.Base}}/dashboard" class="topbar-brand">clavitor <span class="port">account</span></a>
<nav class="topbar-nav">
<a href="{{.Base}}/dashboard">Vaults</a>
<a href="{{.Base}}/settings">Settings</a>
</nav>
</div>
</div>
</header>
<main class="container" style="flex:1">
<section class="section fade-in">
<span class="label accent">New vault</span>
<h1 style="margin-top:0.5rem">Choose your region</h1>
<p class="text-secondary" style="margin-top:0.5rem;max-width:480px">
Your vault lives in one region. All data stays there. Pick the closest location for the best performance.
</p>
</section>
<section class="fade-in fade-in-delay-1" style="padding-bottom:1.5rem">
<div class="label gold" style="margin-bottom:0.75rem">Headquarters</div>
<div class="region-grid">
<div class="card card-interactive card-gold region-card" data-region="zurich" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1E8;&#x1F1ED;</span>
<span class="region-name">Zürich</span>
<span class="region-location">Switzerland</span>
<span class="label gold">HQ &middot; Swiss jurisdiction</span>
</div>
</div>
</section>
<section class="fade-in fade-in-delay-2" style="padding-bottom:1.5rem">
<div class="label" style="margin-bottom:0.75rem">Americas</div>
<div class="region-grid">
<div class="card card-interactive region-card" data-region="virginia" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1FA;&#x1F1F8;</span>
<span class="region-name">Virginia</span>
<span class="region-location">US East</span>
</div>
<div class="card card-interactive region-card" data-region="sanfrancisco" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1FA;&#x1F1F8;</span>
<span class="region-name">San Francisco</span>
<span class="region-location">US West</span>
</div>
<div class="card card-interactive region-card" data-region="montreal" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1E8;&#x1F1E6;</span>
<span class="region-name">Montréal</span>
<span class="region-location">Canada</span>
</div>
<div class="card card-interactive region-card" data-region="mexico" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1F2;&#x1F1FD;</span>
<span class="region-name">Mexico City</span>
<span class="region-location">Mexico</span>
</div>
<div class="card card-interactive region-card" data-region="bogota" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1E8;&#x1F1F4;</span>
<span class="region-name">Bogotá</span>
<span class="region-location">Colombia</span>
</div>
<div class="card card-interactive region-card" data-region="saopaulo" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1E7;&#x1F1F7;</span>
<span class="region-name">São Paulo</span>
<span class="region-location">Brazil</span>
</div>
<div class="card card-interactive region-card" data-region="santiago" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1E8;&#x1F1F1;</span>
<span class="region-name">Santiago</span>
<span class="region-location">Chile</span>
</div>
<div class="card card-interactive region-card" data-region="buenosaires" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1E6;&#x1F1F7;</span>
<span class="region-name">Buenos Aires</span>
<span class="region-location">Argentina</span>
</div>
</div>
</section>
<section class="fade-in fade-in-delay-3" style="padding-bottom:1.5rem">
<div class="label" style="margin-bottom:0.75rem">Europe</div>
<div class="region-grid">
<div class="card card-interactive region-card" data-region="london" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1EC;&#x1F1E7;</span>
<span class="region-name">London</span>
<span class="region-location">United Kingdom</span>
</div>
<div class="card card-interactive region-card" data-region="madrid" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1EA;&#x1F1F8;</span>
<span class="region-name">Madrid</span>
<span class="region-location">Spain</span>
</div>
</div>
</section>
<section class="fade-in fade-in-delay-3" style="padding-bottom:1.5rem">
<div class="label" style="margin-bottom:0.75rem">Middle East &amp; Africa</div>
<div class="region-grid">
<div class="card card-interactive region-card" data-region="istanbul" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1F9;&#x1F1F7;</span>
<span class="region-name">Istanbul</span>
<span class="region-location">Turkey</span>
</div>
<div class="card card-interactive region-card" data-region="dubai" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1E6;&#x1F1EA;</span>
<span class="region-name">Dubai</span>
<span class="region-location">UAE</span>
</div>
<div class="card card-interactive region-card" data-region="capetown" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1FF;&#x1F1E6;</span>
<span class="region-name">Cape Town</span>
<span class="region-location">South Africa</span>
</div>
</div>
</section>
<section class="fade-in fade-in-delay-3" style="padding-bottom:3rem">
<div class="label" style="margin-bottom:0.75rem">Asia Pacific</div>
<div class="region-grid">
<div class="card card-interactive region-card" data-region="mumbai" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1EE;&#x1F1F3;</span>
<span class="region-name">Mumbai</span>
<span class="region-location">India</span>
</div>
<div class="card card-interactive region-card" data-region="singapore" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1F8;&#x1F1EC;</span>
<span class="region-name">Singapore</span>
<span class="region-location">Singapore</span>
</div>
<div class="card card-interactive region-card" data-region="hongkong" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1ED;&#x1F1F0;</span>
<span class="region-name">Hong Kong</span>
<span class="region-location">China</span>
</div>
<div class="card card-interactive region-card" data-region="seoul" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1F0;&#x1F1F7;</span>
<span class="region-name">Seoul</span>
<span class="region-location">South Korea</span>
</div>
<div class="card card-interactive region-card" data-region="tokyo" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1EF;&#x1F1F5;</span>
<span class="region-name">Tokyo</span>
<span class="region-location">Japan</span>
</div>
<div class="card card-interactive region-card" data-region="sydney" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1E6;&#x1F1FA;</span>
<span class="region-name">Sydney</span>
<span class="region-location">Australia</span>
</div>
<div class="card card-interactive region-card" data-region="almaty" onclick="selectRegion(this)">
<span class="region-flag">&#x1F1F0;&#x1F1FF;</span>
<span class="region-name">Almaty</span>
<span class="region-location">Kazakhstan</span>
</div>
</div>
</section>
<!-- Sticky bottom bar -->
<div id="region-confirm" style="position:fixed;bottom:0;left:0;right:0;transform:translateY(100%);transition:transform 0.35s cubic-bezier(0.16,1,0.3,1);z-index:50">
<div style="background:rgba(6,10,16,0.9);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border-top:1px solid var(--glass-border);padding:1rem 0">
<div class="container" style="display:flex;align-items:center;justify-content:space-between;gap:1rem;max-width:960px">
<div>
<span id="selected-name" style="font-weight:600"></span>
<span id="selected-location" class="text-secondary" style="font-size:0.875rem;margin-left:0.5rem"></span>
</div>
<button class="btn btn-primary" onclick="confirmRegion()">
Create vault here
</button>
</div>
</div>
</div>
</main>
{{end}}
{{define "scripts"}}
<script>
let selectedRegion = null;
function selectRegion(el) {
document.querySelectorAll('.region-card.selected').forEach(c => c.classList.remove('selected'));
el.classList.add('selected');
selectedRegion = el.dataset.region;
const name = el.querySelector('.region-name').textContent;
const loc = el.querySelector('.region-location').textContent;
document.getElementById('selected-name').textContent = name;
document.getElementById('selected-location').textContent = loc;
document.getElementById('region-confirm').style.transform = 'translateY(0)';
}
async function confirmRegion() {
if (!selectedRegion) return;
const btn = document.querySelector('#region-confirm .btn');
btn.disabled = true;
btn.textContent = 'Creating vault…';
try {
const resp = await fetch('{{.Base}}/api/vault/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ region: selectedRegion })
});
if (resp.status === 401) { window.location.href = '{{.Base}}/login'; return; }
if (resp.status === 409) throw new Error('Vault limit reached');
if (!resp.ok) throw new Error('Could not create vault');
window.location.href = '{{.Base}}/dashboard';
} catch (err) {
showToast(err.message || 'Could not create vault', 'error');
btn.disabled = false;
btn.textContent = 'Create vault here';
}
}
function showToast(msg, type) {
let t = document.querySelector('.toast');
if (!t) {
t = document.createElement('div');
t.className = 'toast';
document.body.appendChild(t);
}
t.textContent = msg;
t.className = 'toast ' + type;
requestAnimationFrame(() => t.classList.add('show'));
setTimeout(() => t.classList.remove('show'), type === 'error' ? 6000 : 3000);
}
// Auto-detect closest region
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(pos => {
const lat = pos.coords.latitude;
const lon = pos.coords.longitude;
const regions = {
zurich: [47.37, 8.54], virginia: [38.95, -77.45], sanfrancisco: [37.77, -122.42],
montreal: [45.50, -73.57], mexico: [19.43, -99.13], bogota: [4.71, -74.07],
saopaulo: [-23.55, -46.63], santiago: [-33.45, -70.65], buenosaires: [-34.60, -58.38],
london: [51.51, -0.13], madrid: [40.42, -3.70],
istanbul: [41.01, 28.98], dubai: [25.20, 55.27], capetown: [-33.92, 18.42],
mumbai: [19.08, 72.88], singapore: [1.35, 103.82], hongkong: [22.32, 114.17],
seoul: [37.57, 126.98], tokyo: [35.68, 139.69], sydney: [-33.87, 151.21],
almaty: [43.24, 76.95]
};
let closest = null, minDist = Infinity;
for (const [id, [rlat, rlon]] of Object.entries(regions)) {
const d = Math.hypot(lat - rlat, lon - rlon);
if (d < minDist) { minDist = d; closest = id; }
}
if (closest) {
const el = document.querySelector(`[data-region="${closest}"]`);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.style.boxShadow = '0 0 0 2px var(--accent-dim)';
const hint = document.createElement('span');
hint.className = 'label accent';
hint.textContent = 'Nearest to you';
hint.style.marginTop = '0.25rem';
el.appendChild(hint);
}
}
}, () => {}, { timeout: 5000 });
}
</script>
{{end}}