clavitor/clavitor.ai/templates/base.tmpl

314 lines
14 KiB
Cheetah

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.Title}}</title>
{{if .Desc}}<meta name="description" content="{{.Desc}}">{{end}}
<meta property="og:site_name" content="clavitor">
<meta property="og:title" content="{{.Title}}">
{{if .Desc}}<meta property="og:description" content="{{.Desc}}">{{end}}
<meta property="og:type" content="website">
<meta property="og:url" content="https://clavitor.ai{{if ne .Page "index"}}/{{.Page}}{{end}}">
<meta name="twitter:card" content="summary">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="preload" href="/fonts/ibm-plex-sans-latin.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/jetbrains-mono-latin.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/clavitor.css">
{{if eq .Page "install"}}{{template "install-head"}}{{end}}
{{if eq .Page "styleguide"}}{{template "styleguide-head"}}{{end}}
{{if eq .Page "index"}}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "clavitor",
"url": "https://clavitor.ai",
"description": "AI-native password manager with field-level encryption. Your AI gets what it needs. Your secrets stay yours.",
"potentialAction": {
"@type": "SearchAction",
"target": "https://clavitor.ai?q={search_term_string}",
"query-input": "required name=search_term_string"
}
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "clavitor",
"url": "https://clavitor.ai",
"logo": "https://clavitor.ai/favicon.svg",
"sameAs": []
}
</script>
{{end}}
{{if or (eq .Page "hosted") (eq .Page "pricing")}}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "clavitor",
"applicationCategory": "SecurityApplication",
"operatingSystem": "Any",
"offers": {
"@type": "Offer",
"price": "12",
"priceCurrency": "USD",
"priceValidUntil": "2026-12-31",
"description": "$12/year hosted (launch price)"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.8",
"ratingCount": "1"
},
"featureList": "Field-level encryption, WebAuthn PRF, Scoped agent tokens, AI-powered 2FA, LLM field mapping"
}
</script>
{{end}}
</head>
<body>
<nav class="nav">
<div class="container nav-inner">
<a href="/" class="nav-logo"><span class="logo-lockup logo-lockup-nav"><span class="logo-lockup-square"></span><span class="logo-lockup-text"><span class="logo-lockup-wordmark">CLAVITOR</span><span class="logo-lockup-tagline">Black-box credential issuance</span></span></span></a>
<button class="nav-hamburger" onclick="document.querySelector('.nav-links').classList.toggle('open')"><span></span><span></span><span></span></button>
<div class="nav-links">
<a href="/hosted" class="nav-link{{if eq .ActiveNav "hosted"}} active{{end}}">Hosted</a>
<div class="nav-dropdown">
<span class="nav-link nav-dropdown-trigger{{if or (eq .ActiveNav "install") (eq .ActiveNav "integrations") (eq .ActiveNav "upgrade") (eq .ActiveNav "developers")}} active{{end}}">Product</span>
<div class="nav-dropdown-menu">
<a href="/upgrade" class="nav-dropdown-item">Upgrade</a>
<a href="/developers" class="nav-dropdown-item">Developers</a>
<a href="/install" class="nav-dropdown-item">Self-host</a>
<a href="/integrations/claude-code" class="nav-dropdown-item">Claude Code</a>
<a href="/integrations/codex" class="nav-dropdown-item">Codex</a>
<a href="/integrations/openclaw" class="nav-dropdown-item">OpenClaw</a>
</div>
</div>
<div class="nav-dropdown">
<span class="nav-link nav-dropdown-trigger{{if or (eq .ActiveNav "status") (eq .ActiveNav "glass")}} active{{end}}">Network</span>
<div class="nav-dropdown-menu">
<a href="/status" class="nav-dropdown-item">Status</a>
<a href="/glass" class="nav-dropdown-item">Looking Glass</a>
</div>
</div>
<div class="nav-dropdown">
<span class="nav-link nav-dropdown-trigger{{if or (eq .ActiveNav "for-consumer") (eq .ActiveNav "for-smb") (eq .ActiveNav "for-mme") (eq .ActiveNav "for-enterprise") (eq .ActiveNav "for-msp")}} active{{end}}">Solutions</span>
<div class="nav-dropdown-menu">
<a href="/for/consumer" class="nav-dropdown-item">Consumer</a>
<a href="/for/smb" class="nav-dropdown-item">SMB</a>
<a href="/for/enterprise" class="nav-dropdown-item">Enterprise</a>
<a href="/for/msp" class="nav-dropdown-item">MSP</a>
</div>
</div>
<a href="/pricing" class="nav-link{{if eq .ActiveNav "pricing"}} active{{end}}">Pricing</a>
<div class="nav-dropdown nav-dropdown--language">
<span class="nav-link nav-dropdown-trigger" id="languageTrigger">🇺🇸 EN</span>
<div class="nav-dropdown-menu nav-dropdown-menu--right">
<a href="/" class="nav-dropdown-item active" data-lang="en">🇺🇸 English</a>
<a href="/de" class="nav-dropdown-item" data-lang="de">🇩🇪 Deutsch</a>
<a href="/fr" class="nav-dropdown-item" data-lang="fr">🇫🇷 Français</a>
</div>
</div>
<div class="nav-dropdown nav-dropdown--currency">
<span class="nav-link nav-dropdown-trigger" id="currencyTrigger">$ USD</span>
<div class="nav-dropdown-menu nav-dropdown-menu--right" id="currencyMenu">
<!-- Currency options loaded dynamically from /api/currencies -->
<a href="#" class="nav-dropdown-item active" data-currency="USD">$ USD</a>
<a href="#" class="nav-dropdown-item" data-currency="EUR">€ EUR</a>
</div>
</div>
<a href="#" class="nav-link btn btn-ghost">Sign in</a>
<a href="/hosted" class="btn btn-primary">Get hosted &mdash; $12/yr</a>
</div>
</div>
</nav>
{{if eq .Page "index"}}{{template "index" .}}
{{else if eq .Page "hosted"}}{{template "hosted" .}}
{{else if eq .Page "install"}}{{template "install" .}}
{{else if eq .Page "pricing"}}{{template "pricing" .}}
{{else if eq .Page "privacy"}}{{template "privacy" .}}
{{else if eq .Page "terms"}}{{template "terms" .}}
{{else if eq .Page "cookies"}}{{template "cookies" .}}
{{else if eq .Page "sources"}}{{template "sources" .}}
{{else if eq .Page "upgrade"}}{{template "upgrade" .}}
{{else if eq .Page "developers"}}{{template "developers" .}}
{{else if eq .Page "styleguide"}}{{template "styleguide" .}}
{{else if eq .Page "glass"}}{{template "glass" .}}
{{else if eq .Page "noc"}}{{template "noc" .}}
{{else if eq .Page "status"}}{{template "status" .}}
{{else if eq .Page "signup"}}{{template "signup" .}}
{{else if eq .Page "claude-code"}}{{template "claude-code" .}}
{{else if eq .Page "codex"}}{{template "codex" .}}
{{else if eq .Page "openclaw"}}{{template "openclaw" .}}
{{else if eq .Page "openclaw-cn"}}{{template "openclaw-cn" .}}
{{else if eq .Page "install-new"}}{{template "install-new" .}}
{{else if eq .Page "for-consumer"}}{{template "for-consumer" .}}
{{else if eq .Page "for-smb"}}{{template "for-smb" .}}
{{else if eq .Page "for-mme"}}{{template "for-mme" .}}
{{else if eq .Page "for-enterprise"}}{{template "for-enterprise" .}}
{{else if eq .Page "for-msp"}}{{template "for-msp" .}}
{{else if eq .Page "onboarding-profile"}}{{template "onboarding-profile" .}}
{{else if eq .Page "onboarding-plan"}}{{template "onboarding-plan" .}}
{{else if eq .Page "onboarding-done"}}{{template "onboarding-done" .}}
{{else if eq .Page "onboarding-login"}}{{template "onboarding-login" .}}
{{else if eq .Page "onboarding-details"}}{{template "onboarding-details" .}}
{{else if eq .Page "onboarding-product"}}{{template "onboarding-product" .}}
{{else if eq .Page "onboarding-terms"}}{{template "onboarding-terms" .}}
{{else if eq .Page "onboarding-checkout"}}{{template "onboarding-checkout" .}}
{{end}}
{{if ne .Page "styleguide"}}{{template "footer"}}{{end}}
{{if eq .Page "hosted" "glass"}}{{template "ping-script"}}{{end}}
{{if eq .Page "index"}}{{template "index-script"}}
{{else if eq .Page "hosted"}}{{template "hosted-script" .}}
{{else if eq .Page "glass"}}{{template "glass-script"}}
{{else if eq .Page "noc"}}{{template "noc-script"}}
{{else if eq .Page "status"}}{{template "status-script"}}
{{else if eq .Page "signup"}}{{template "signup-script"}}
{{else if eq .Page "install"}}{{template "install-script"}}
{{else if eq .Page "onboarding-profile"}}{{template "onboarding-profile-script"}}
{{else if eq .Page "onboarding-plan"}}{{template "onboarding-plan-script"}}
{{end}}
<script>
document.querySelectorAll('.nav-dropdown-trigger').forEach(t=>t.addEventListener('click',()=>t.parentElement.classList.toggle('open')));
// Language selector state management
(function() {
const langTrigger = document.getElementById('languageTrigger');
if (!langTrigger) return;
const dropdown = langTrigger.closest('.nav-dropdown--language');
const langItems = dropdown.querySelectorAll('[data-lang]');
// Load saved preference
const savedLang = localStorage.getItem('preferredLanguage') || 'en';
const langFlags = { en: '🇺🇸', de: '🇩🇪', fr: '🇫🇷' };
// Set initial active state
langItems.forEach(el => {
if (el.dataset.lang === savedLang) {
el.classList.add('active');
langTrigger.textContent = langFlags[savedLang] + ' ' + savedLang.toUpperCase();
} else {
el.classList.remove('active');
}
});
// Handle language selection
langItems.forEach(el => el.addEventListener('click', (e) => {
e.preventDefault();
const lang = el.dataset.lang;
const flag = el.textContent.trim().split(' ')[0];
langTrigger.textContent = flag + ' ' + lang.toUpperCase();
langItems.forEach(i => i.classList.remove('active'));
el.classList.add('active');
localStorage.setItem('preferredLanguage', lang);
// Navigate to language path
if (lang === 'en') window.location.href = '/';
else window.location.href = '/' + lang;
}));
})();
// Currency selector - fetch from API and render with sections
(function() {
const currencyTrigger = document.getElementById('currencyTrigger');
if (!currencyTrigger) return;
async function loadCurrencies() {
const menu = document.getElementById('currencyMenu');
if (!menu) return;
try {
const response = await fetch('/api/currencies');
if (!response.ok) throw new Error('ERR-CURRENCY-001: Failed to load currencies');
const data = await response.json();
// Clear existing content
menu.innerHTML = '';
// Render "Popular" section
if (data.top && data.top.length > 0) {
const popularHeader = document.createElement('div');
popularHeader.className = 'dropdown-section';
popularHeader.textContent = 'Popular';
menu.appendChild(popularHeader);
data.top.forEach(currency => {
const item = createCurrencyItem(currency, currencyTrigger);
menu.appendChild(item);
});
}
// Divider between sections
if (data.all && data.all.length > 0 && data.top && data.top.length > 0) {
const divider = document.createElement('div');
divider.className = 'dropdown-divider';
menu.appendChild(divider);
}
// Render "All Currencies" section
if (data.all && data.all.length > 0) {
const allHeader = document.createElement('div');
allHeader.className = 'dropdown-section';
allHeader.textContent = 'All Currencies';
menu.appendChild(allHeader);
data.all.forEach(currency => {
const item = createCurrencyItem(currency, currencyTrigger);
menu.appendChild(item);
});
}
} catch (err) {
// ERR-CURRENCY-002: API unavailable - keep default fallback options
console.error('ERR-CURRENCY-002: Currency API unavailable, using defaults');
}
}
function createCurrencyItem(currency, trigger) {
const item = document.createElement('a');
item.href = '#';
item.className = 'nav-dropdown-item';
item.setAttribute('data-currency', currency.code);
item.textContent = (currency.symbol || '$') + ' ' + currency.code;
// Set active state based on current selection or saved preference
const savedCurrency = localStorage.getItem('preferredCurrency') || 'USD';
const currentText = trigger.textContent.trim();
if (currentText.includes(currency.code) || savedCurrency === currency.code) {
item.classList.add('active');
if (savedCurrency === currency.code) {
trigger.textContent = (currency.symbol || '$') + ' ' + currency.code;
}
}
item.addEventListener('click', (e) => {
e.preventDefault();
const code = item.getAttribute('data-currency');
const symbol = currency.symbol || '$';
trigger.textContent = symbol + ' ' + code;
// Update active state
document.querySelectorAll('.nav-dropdown--currency .nav-dropdown-item').forEach(i => i.classList.remove('active'));
item.classList.add('active');
// Store preference
localStorage.setItem('preferredCurrency', code);
// Refresh page to apply currency (or fetch rates via JS)
window.location.reload();
});
return item;
}
// Load currencies on page load
loadCurrencies();
})();
</script>
</body>
</html>