feat: add SEO meta, OG image, favicons and sitemap
- Full meta suite in index.html: description, canonical, robots, Open Graph + Twitter cards, theme-color and JSON-LD structured data - 1200x630 OG share card matching the homepage Plan-B wordmark - Favicon set generated from the intro storm icon (svg + png + apple touch + 192/512 PWA icons) and a web manifest - robots.txt + sitemap.xml with hreflang alternates - setLang() now syncs title/description/og tags on EN/DE toggle Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
76
index.html
@@ -3,10 +3,84 @@
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
|
||||
<title>Plan-B — Survival Preparedness Advisor</title>
|
||||
|
||||
<!-- ── Primary meta ─────────────────────────────────────────────── -->
|
||||
<title>Plan-B — AI-Assisted Crisis Preparedness Advisor</title>
|
||||
<meta name="description" content="Free AI-assisted crisis-preparedness advisor for urban households. Assess your readiness across 9 collapse scenarios and get a personalised survival plan in minutes."/>
|
||||
<meta name="author" content="Plan-B"/>
|
||||
<meta name="theme-color" content="#5A9A78"/>
|
||||
<meta name="color-scheme" content="light"/>
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1"/>
|
||||
<link rel="canonical" href="https://plan-b.now/"/>
|
||||
|
||||
<!-- ── Open Graph (Facebook, LinkedIn, WhatsApp, Signal, Telegram…) ─ -->
|
||||
<meta property="og:type" content="website"/>
|
||||
<meta property="og:site_name" content="Plan-B"/>
|
||||
<meta property="og:title" content="Plan-B — AI-Assisted Crisis Preparedness Advisor"/>
|
||||
<meta property="og:description" content="Assess your household's readiness across 9 collapse scenarios and get a personalised survival plan — water, food, energy, medical and budget. Built for city apartments."/>
|
||||
<meta property="og:url" content="https://plan-b.now/"/>
|
||||
<meta property="og:image" content="https://plan-b.now/images/og-image.png"/>
|
||||
<meta property="og:image:secure_url" content="https://plan-b.now/images/og-image.png"/>
|
||||
<meta property="og:image:type" content="image/png"/>
|
||||
<meta property="og:image:width" content="1200"/>
|
||||
<meta property="og:image:height" content="630"/>
|
||||
<meta property="og:image:alt" content="Plan-B — AI-Assisted Preparedness for Urban Households"/>
|
||||
<meta property="og:locale" content="en_US"/>
|
||||
<meta property="og:locale:alternate" content="de_DE"/>
|
||||
|
||||
<!-- ── Twitter / X ─────────────────────────────────────────────── -->
|
||||
<meta name="twitter:card" content="summary_large_image"/>
|
||||
<meta name="twitter:title" content="Plan-B — AI-Assisted Crisis Preparedness Advisor"/>
|
||||
<meta name="twitter:description" content="Assess your household's readiness across 9 collapse scenarios and get a personalised survival plan. Built for city apartments."/>
|
||||
<meta name="twitter:image" content="https://plan-b.now/images/og-image.png"/>
|
||||
<meta name="twitter:image:alt" content="Plan-B — AI-Assisted Preparedness for Urban Households"/>
|
||||
|
||||
<!-- ── Icons / PWA ─────────────────────────────────────────────── -->
|
||||
<link rel="icon" href="/images/favicon.svg" type="image/svg+xml"/>
|
||||
<link rel="icon" href="/images/favicon-32.png" sizes="32x32" type="image/png"/>
|
||||
<link rel="icon" href="/images/favicon-16.png" sizes="16x16" type="image/png"/>
|
||||
<link rel="apple-touch-icon" href="/images/apple-touch-icon.png"/>
|
||||
<link rel="manifest" href="/site.webmanifest"/>
|
||||
|
||||
<!-- ── Fonts ───────────────────────────────────────────────────── -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=DM+Serif+Display&family=Barlow:wght@300;400;500;600&display=swap" rel="stylesheet"/>
|
||||
|
||||
<!-- ── Structured data (Google rich results) ───────────────────── -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "WebSite",
|
||||
"@id": "https://plan-b.now/#website",
|
||||
"url": "https://plan-b.now/",
|
||||
"name": "Plan-B",
|
||||
"description": "AI-assisted crisis-preparedness advisor for urban households.",
|
||||
"inLanguage": ["en", "de"],
|
||||
"publisher": { "@id": "https://plan-b.now/#org" }
|
||||
},
|
||||
{
|
||||
"@type": "Organization",
|
||||
"@id": "https://plan-b.now/#org",
|
||||
"name": "Plan-B",
|
||||
"url": "https://plan-b.now/",
|
||||
"logo": "https://plan-b.now/images/icon-512.png"
|
||||
},
|
||||
{
|
||||
"@type": "WebApplication",
|
||||
"name": "Plan-B Preparedness Advisor",
|
||||
"url": "https://plan-b.now/",
|
||||
"applicationCategory": "LifestyleApplication",
|
||||
"operatingSystem": "Web",
|
||||
"browserRequirements": "Requires JavaScript.",
|
||||
"inLanguage": ["en", "de"],
|
||||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "EUR" }
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
BIN
public/images/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
public/images/favicon-16.png
Normal file
|
After Width: | Height: | Size: 661 B |
BIN
public/images/favicon-32.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
7
public/images/favicon.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg width="96" height="96" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Plan-B">
|
||||
<circle cx="48" cy="48" r="44" fill="#2a3010"/>
|
||||
<g transform="translate(19.75 21.15) scale(0.46)" fill="#f4ecd8">
|
||||
<path d="M44.2,71.76 c2.03,0,3.68,1.65,3.68,3.68c0,2.03-1.65,3.68-3.68,3.68H23.38l-0.46-0.04c-2.67-0.34-5.09-0.97-7.29-1.88 c-2.25-0.93-4.26-2.14-6.04-3.63H9.58c-1.68-1.4-3.15-2.99-4.4-4.72C1.84,64.25,0.04,58.63,0,53.03 c-0.04-5.66,1.72-11.29,5.52-15.85c1.23-1.48,2.68-2.84,4.34-4.04c1.93-1.4,4.14-2.58,6.64-3.55c1.72-0.67,3.56-1.23,5.5-1.68 c2.2-8.74,6.89-15.47,12.92-20.14c5.64-4.37,12.43-6.92,19.42-7.59c6.96-0.67,14.12,0.51,20.55,3.6 c7.37,3.54,13.43,9.56,17.11,16.87c1.6-0.25,3.2-0.38,4.79-0.36c6.72,0.05,13.2,2.45,18.3,7.95c5.31,5.72,7.88,14.14,7.79,21.82 c-0.07,6.31-1.77,12.59-5.25,17.22c-2.27,3.02-5.18,5.47-8.67,7.42c-3.36,1.88-7.28,3.31-11.68,4.33c-1.98,0.45-3.95-0.78-4.4-2.76 c-0.45-1.98,0.78-3.95,2.76-4.4c3.71-0.86,6.97-2.04,9.72-3.58c2.63-1.47,4.78-3.26,6.39-5.41c2.5-3.33,3.73-8.04,3.78-12.87 c0.06-5.07-1.18-10.16-3.59-13.86c-0.69-1.07-1.44-2.03-2.25-2.89c-3.61-3.89-8.19-5.59-12.95-5.62 c-3.46-0.02-7.02,0.81-10.41,2.31c-0.75,0.37-1.51,0.78-2.25,1.21c-2.25,1.32-4.48,2.93-6.74,4.78l-4.84-5.54 c1.67-1.55,3.48-2.96,5.4-4.21c1.53-1,3.13-1.88,4.77-2.65c0.66-0.33,1.33-0.64,2-0.93c-3.19-5.65-7.78-9.7-12.98-12.2 c-5.2-2.49-11.02-3.45-16.69-2.9c-5.63,0.54-11.1,2.59-15.62,6.1c-5.23,4.06-9.2,10.11-10.73,18.14l-0.48,2.51l-2.5,0.44 c-2.45,0.43-4.64,1.02-6.56,1.77c-1.86,0.72-3.52,1.61-4.97,2.66c-1.16,0.84-2.16,1.78-3.01,2.8c-2.63,3.15-3.85,7.1-3.82,11.1 c0.03,4.06,1.35,8.16,3.79,11.53c0.91,1.25,1.96,2.4,3.16,3.4l-0.01,0.01c1.2,1,2.58,1.83,4.13,2.47c1.53,0.63,3.22,1.08,5.09,1.34 H44.2L44.2,71.76z"/>
|
||||
</g>
|
||||
<path d="M47.2 49.5 L57.6 49.5 L54 56.5 L60.2 56.6 L45.2 74.9 L48.1 62.9 L43.2 62.9 Z" fill="#fff8dc"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/images/icon-192.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
public/images/icon-512.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
42
public/images/og-card.svg
Normal file
@@ -0,0 +1,42 @@
|
||||
<svg width="1200" height="630" viewBox="0 0 1200 630" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<!-- Glossy paint sheen on the wordmark, matching the hero's
|
||||
#2a2a26 → #1A1A18 → #060604 vertical gradient. -->
|
||||
<linearGradient id="paint" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#2a2a26"/>
|
||||
<stop offset="0.45" stop-color="#1A1A18"/>
|
||||
<stop offset="1" stop-color="#060604"/>
|
||||
</linearGradient>
|
||||
<filter id="ds" x="-20%" y="-20%" width="140%" height="160%">
|
||||
<feGaussianBlur in="SourceAlpha" stdDeviation="6"/>
|
||||
<feOffset dx="0" dy="7" result="o"/>
|
||||
<feComponentTransfer in="o" result="s"><feFuncA type="linear" slope="0.28"/></feComponentTransfer>
|
||||
<feMerge><feMergeNode in="s"/><feMergeNode in="SourceGraphic"/></feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- Flat hero background -->
|
||||
<rect width="1200" height="630" fill="#F0F0F0"/>
|
||||
|
||||
<!-- Embossed multilingual "Plan B" pattern (the homepage page-bg),
|
||||
tilted ~-5deg and held very faint behind the wordmark. -->
|
||||
<g transform="rotate(-5 600 315)" fill="#1A1A18" opacity="0.04"
|
||||
font-family="Georgia, 'Times New Roman', serif" font-style="italic" font-weight="700" font-size="64" letter-spacing="6">
|
||||
<text x="-60" y="70">Plan B Piano B Plano B План Б プランB Plan B</text>
|
||||
<text x="-160" y="190">Phương án B 备用计划 Plan B 플랜 B Piano B योजना बी</text>
|
||||
<text x="-90" y="310">Piano B Plan B Σχέδιο Β Plano B خطة ب プランB</text>
|
||||
<text x="-200" y="430">Plan B תוכנית ב プランB План Б Plan B Piano B</text>
|
||||
<text x="-60" y="550">备用计划 Plan B योजना बी Plano B Plan B Σχέδιο Β</text>
|
||||
<text x="-150" y="670">Plan B Piano B План Б Plan B プランB Plano B</text>
|
||||
</g>
|
||||
|
||||
<!-- Hero wordmark — centred, glossy dark paint, like the homepage. -->
|
||||
<text x="600" y="372" text-anchor="middle" filter="url(#ds)"
|
||||
font-family="Georgia, 'Times New Roman', serif" font-weight="700"
|
||||
font-size="190" letter-spacing="9" fill="url(#paint)">Plan-B</text>
|
||||
|
||||
<!-- Tagline -->
|
||||
<text x="600" y="460" text-anchor="middle"
|
||||
font-family="'Helvetica Neue', Arial, sans-serif" font-weight="500"
|
||||
font-size="23" letter-spacing="7" fill="#0a0a0a">AI-ASSISTED PREPAREDNESS FOR URBAN HOUSEHOLDS</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
BIN
public/images/og-image.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
4
public/robots.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: https://plan-b.now/sitemap.xml
|
||||
16
public/site.webmanifest
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Plan-B — Crisis Preparedness Advisor",
|
||||
"short_name": "Plan-B",
|
||||
"description": "AI-assisted crisis-preparedness advisor for urban households.",
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#FAFAFA",
|
||||
"theme_color": "#5A9A78",
|
||||
"lang": "en",
|
||||
"icons": [
|
||||
{ "src": "/images/icon-192.png", "sizes": "192x192", "type": "image/png" },
|
||||
{ "src": "/images/icon-512.png", "sizes": "512x512", "type": "image/png" },
|
||||
{ "src": "/images/favicon.svg", "sizes": "any", "type": "image/svg+xml", "purpose": "any" }
|
||||
]
|
||||
}
|
||||
12
public/sitemap.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<url>
|
||||
<loc>https://plan-b.now/</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
<xhtml:link rel="alternate" hreflang="en" href="https://plan-b.now/"/>
|
||||
<xhtml:link rel="alternate" hreflang="de" href="https://plan-b.now/"/>
|
||||
<xhtml:link rel="alternate" hreflang="x-default" href="https://plan-b.now/"/>
|
||||
</url>
|
||||
</urlset>
|
||||
34
src/App.vue
@@ -639,7 +639,9 @@ import { onMounted } from 'vue'
|
||||
const T = {
|
||||
en: {
|
||||
brand: "Plan-B",
|
||||
page_title: "Plan-B — Survival Preparedness Advisor",
|
||||
page_title: "Plan-B — AI-Assisted Crisis Preparedness Advisor",
|
||||
meta_description: "Free AI-assisted crisis-preparedness advisor for urban households. Assess your readiness across 9 collapse scenarios and get a personalised survival plan in minutes.",
|
||||
og_locale: "en_US",
|
||||
hero_eyebrow: "Crisis Preparedness Advisor",
|
||||
hero_sub: "AI-Assisted Preparedness for Urban Households",
|
||||
hero_cta: "Begin",
|
||||
@@ -761,7 +763,9 @@ const T = {
|
||||
},
|
||||
de: {
|
||||
brand: "Plan-B",
|
||||
page_title: "Plan-B — Krisenvorsorge-Berater",
|
||||
page_title: "Plan-B — KI-gestützter Krisenvorsorge-Berater",
|
||||
meta_description: "Kostenloser KI-gestützter Krisenvorsorge-Berater für urbane Haushalte. Bewerte deine Vorsorge über 9 Krisenszenarien und erhalte in Minuten einen personalisierten Survival-Plan.",
|
||||
og_locale: "de_DE",
|
||||
hero_eyebrow: "⚡ Krisenvorsorge-Berater",
|
||||
hero_sub: "KI-gestützte Vorsorge für urbane Haushalte",
|
||||
hero_cta: "Beginnen",
|
||||
@@ -899,6 +903,7 @@ function setLang(lang) {
|
||||
if (T[lang][key]) el.textContent = T[lang][key]
|
||||
})
|
||||
if (T[lang].page_title) document.title = T[lang].page_title
|
||||
syncMeta(lang)
|
||||
document.querySelectorAll('[data-ph-' + lang + ']').forEach(el => {
|
||||
el.placeholder = el.getAttribute('data-ph-' + lang)
|
||||
})
|
||||
@@ -913,6 +918,31 @@ function setLang(lang) {
|
||||
|
||||
function t(key) { return T[currentLang][key] || T['en'][key] || key }
|
||||
|
||||
// Keep SEO-relevant <head> tags in sync with the active language. The static
|
||||
// tags in index.html are the English defaults (what non-JS social scrapers
|
||||
// read); this updates them for the browser tab and JS-executing crawlers
|
||||
// (e.g. Googlebot) when the user toggles EN/DE on the single-URL SPA.
|
||||
function syncMeta(lang) {
|
||||
const tr = T[lang] || T.en
|
||||
const setAttr = (selector, attr, val) => {
|
||||
const el = document.head.querySelector(selector)
|
||||
if (el && val) el.setAttribute(attr, val)
|
||||
}
|
||||
if (tr.meta_description) {
|
||||
setAttr('meta[name="description"]', 'content', tr.meta_description)
|
||||
setAttr('meta[property="og:description"]', 'content', tr.meta_description)
|
||||
setAttr('meta[name="twitter:description"]', 'content', tr.meta_description)
|
||||
}
|
||||
if (tr.page_title) {
|
||||
setAttr('meta[property="og:title"]', 'content', tr.page_title)
|
||||
setAttr('meta[name="twitter:title"]', 'content', tr.page_title)
|
||||
}
|
||||
if (tr.og_locale) {
|
||||
setAttr('meta[property="og:locale"]', 'content', tr.og_locale)
|
||||
setAttr('meta[property="og:locale:alternate"]', 'content', lang === 'de' ? 'en_US' : 'de_DE')
|
||||
}
|
||||
}
|
||||
|
||||
function syncPreferredLanguageField() {
|
||||
const field = document.getElementById('f_pref_lang')
|
||||
if (field) field.value = currentLang
|
||||
|
||||