feat(web): SEO/social cards, security headers, PWA icons, FAQ, status, get-involved, captions
|
|
@ -196,3 +196,59 @@ h2 { font-size: clamp(1.4rem, 3vw, 1.9rem); color: var(--green-dark); }
|
||||||
.hero-shot { order: -1; }
|
.hero-shot { order: -1; }
|
||||||
.pillars { grid-template-columns: 1fr; }
|
.pillars { grid-template-columns: 1fr; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- About link + text links --- */
|
||||||
|
.text-link { font-weight: 600; text-decoration: none; }
|
||||||
|
.text-link:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
/* --- Status / beta --- */
|
||||||
|
.status {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--outline);
|
||||||
|
border-inline-start: 4px solid var(--green);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 1.2rem 1.4rem;
|
||||||
|
}
|
||||||
|
.status h2 { font-size: 1.2rem; margin: 0 0 .3rem; }
|
||||||
|
.status p { margin: 0; color: #2c3826; }
|
||||||
|
.badge-beta {
|
||||||
|
background: var(--green); color: #fff; font-weight: 700; font-size: .8rem;
|
||||||
|
padding: .25rem .7rem; border-radius: 999px; flex-shrink: 0; margin-top: .15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Screenshot captions + RTL note --- */
|
||||||
|
.phone-fig { margin: 0; text-align: center; max-width: 232px; }
|
||||||
|
.phone-fig figcaption { margin-top: .7rem; font-size: .9rem; color: var(--muted); }
|
||||||
|
.rtl-note {
|
||||||
|
display: flex; gap: 1.4rem; align-items: center; justify-content: center;
|
||||||
|
margin-top: 2rem; background: var(--container); border-radius: var(--radius);
|
||||||
|
padding: 1.4rem clamp(1rem, 4vw, 2rem);
|
||||||
|
}
|
||||||
|
.phone-sm { width: 150px; max-width: 40vw; flex-shrink: 0; }
|
||||||
|
.rtl-note h3 { margin: 0 0 .3rem; color: var(--green-dark); }
|
||||||
|
.rtl-note p { margin: 0; }
|
||||||
|
|
||||||
|
/* --- FAQ --- */
|
||||||
|
.faq dl { margin: 0; }
|
||||||
|
.faq dt { font-weight: 700; margin-top: 1rem; color: var(--title); }
|
||||||
|
.faq dd { margin: .2rem 0 0; color: #2c3826; }
|
||||||
|
|
||||||
|
/* --- Get involved --- */
|
||||||
|
.collab-grid {
|
||||||
|
display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.2rem; margin: 1rem 0 1.4rem;
|
||||||
|
}
|
||||||
|
.collab-grid article {
|
||||||
|
background: var(--white); border: 1px solid var(--outline);
|
||||||
|
border-radius: var(--radius); padding: 1.2rem;
|
||||||
|
}
|
||||||
|
.collab-grid h3 { margin: 0 0 .4rem; font-size: 1.1rem; color: var(--green-dark); }
|
||||||
|
.collab-grid p { margin: 0; color: #2c3826; }
|
||||||
|
.collab-grid a { text-decoration: none; }
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.collab-grid { grid-template-columns: 1fr; }
|
||||||
|
.rtl-note { flex-direction: column; text-align: center; }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,20 +14,25 @@ enableGitInfo = false
|
||||||
publisher = "Asociación Comunes"
|
publisher = "Asociación Comunes"
|
||||||
publisherURL = "https://comunes.org"
|
publisherURL = "https://comunes.org"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
# Store links are empty until the app is published; the badges partial renders
|
# Links rendered only when set, so nothing broken shows before they exist:
|
||||||
# a link only when its URL is set here, so nothing broken shows before launch.
|
playStoreURL = "" # Google Play, once published
|
||||||
playStoreURL = ""
|
fdroidURL = "" # F-Droid, once published
|
||||||
fdroidURL = ""
|
sourceURL = "" # public source repository (AGPL) — set when available
|
||||||
|
weblateURL = "" # translation platform — set when hosting is ready
|
||||||
|
|
||||||
[languages]
|
[languages]
|
||||||
[languages.en]
|
[languages.en]
|
||||||
languageName = "English"
|
languageName = "English"
|
||||||
languageCode = "en"
|
languageCode = "en"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
[languages.en.params]
|
||||||
|
description = "A local-first, decentralized app for keeping and sharing traditional seeds. Offline, encrypted, no account."
|
||||||
[languages.es]
|
[languages.es]
|
||||||
languageName = "Español"
|
languageName = "Español"
|
||||||
languageCode = "es"
|
languageCode = "es"
|
||||||
weight = 2
|
weight = 2
|
||||||
|
[languages.es.params]
|
||||||
|
description = "Una app local-first y descentralizada para guardar y compartir semillas tradicionales. Sin conexión, cifrada, sin cuenta."
|
||||||
|
|
||||||
[markup.goldmark.renderer]
|
[markup.goldmark.renderer]
|
||||||
unsafe = false
|
unsafe = false
|
||||||
|
|
|
||||||
|
|
@ -33,3 +33,81 @@ other = "Contact"
|
||||||
|
|
||||||
[backToHome]
|
[backToHome]
|
||||||
other = "Back to home"
|
other = "Back to home"
|
||||||
|
|
||||||
|
# --- Status ---
|
||||||
|
[statusBadge]
|
||||||
|
other = "Beta"
|
||||||
|
[statusTitle]
|
||||||
|
other = "Where Tane is right now"
|
||||||
|
[statusBody]
|
||||||
|
other = "The inventory works today: keep your seeds offline, encrypted, with no account. The neighbourly sharing layer (offers, messaging, trust) is being built now. Everything already works with zero network."
|
||||||
|
|
||||||
|
# --- Screenshots ---
|
||||||
|
[screenCapHome]
|
||||||
|
other = "Home — your bank and the market, one tap away"
|
||||||
|
[screenCapInventory]
|
||||||
|
other = "Inventory — your seeds, grouped by family"
|
||||||
|
[screenCapMarket]
|
||||||
|
other = "Market — give, swap or sell with people nearby"
|
||||||
|
[screenCapCalendar]
|
||||||
|
other = "Calendar — what to sow this month"
|
||||||
|
[screenCapDetail]
|
||||||
|
other = "Variety — years, quantities, origin, germination"
|
||||||
|
[rtlNoteTitle]
|
||||||
|
other = "International by design"
|
||||||
|
[rtlNoteBody]
|
||||||
|
other = "Right-to-left and non-Latin scripts are first-class. Here is the inventory mirrored for RTL."
|
||||||
|
|
||||||
|
# --- Get involved ---
|
||||||
|
[collabTitle]
|
||||||
|
other = "Get involved"
|
||||||
|
[collabIntro]
|
||||||
|
other = "Tane has no business model — it lives on volunteers, communities and public tech grants. You can help:"
|
||||||
|
[collabTranslateT]
|
||||||
|
other = "Translate"
|
||||||
|
[collabTranslateB]
|
||||||
|
other = "Bring Tane to your language. Translation files are simple; patches are welcome."
|
||||||
|
[collabTestT]
|
||||||
|
other = "Try it with a seed group"
|
||||||
|
[collabTestB]
|
||||||
|
other = "Use it in a real seed network or fair and tell us what breaks or what's missing."
|
||||||
|
[collabCodeT]
|
||||||
|
other = "Contribute code"
|
||||||
|
[collabCodeB]
|
||||||
|
other = "Flutter/Dart, free software. Design docs and tests included."
|
||||||
|
[collabFundT]
|
||||||
|
other = "Support it"
|
||||||
|
[collabFundB]
|
||||||
|
other = "No ads, no commissions. Help fund the work or point us to grants for the commons."
|
||||||
|
[collabContact]
|
||||||
|
other = "Write to us"
|
||||||
|
|
||||||
|
# --- FAQ ---
|
||||||
|
[faqTitle]
|
||||||
|
other = "Questions"
|
||||||
|
[faqFreeQ]
|
||||||
|
other = "Is it free?"
|
||||||
|
[faqFreeA]
|
||||||
|
other = "Yes. Free software (AGPL-3.0), no ads, no commissions, no data selling."
|
||||||
|
[faqAccountQ]
|
||||||
|
other = "Do I need an account?"
|
||||||
|
[faqAccountA]
|
||||||
|
other = "No account, no sign-up, no server. Your data stays on your device."
|
||||||
|
[faqOfflineQ]
|
||||||
|
other = "Does it work offline?"
|
||||||
|
[faqOfflineA]
|
||||||
|
other = "Fully. The internet only enriches it; everything essential works with no connection."
|
||||||
|
[faqLegalQ]
|
||||||
|
other = "Is it legal to share seeds?"
|
||||||
|
[faqLegalA]
|
||||||
|
other = "Giving and swapping between growers is broadly allowed; selling can be regulated. You are responsible for what you share — see the notice on seed legality."
|
||||||
|
[faqDataQ]
|
||||||
|
other = "What about my privacy?"
|
||||||
|
[faqDataA]
|
||||||
|
other = "Data is encrypted on your device and only what you explicitly share ever leaves it. See the privacy policy."
|
||||||
|
|
||||||
|
# --- misc ---
|
||||||
|
[aboutCta]
|
||||||
|
other = "Learn what Tane is"
|
||||||
|
[footerSource]
|
||||||
|
other = "Source code"
|
||||||
|
|
|
||||||
|
|
@ -33,3 +33,81 @@ other = "Contacto"
|
||||||
|
|
||||||
[backToHome]
|
[backToHome]
|
||||||
other = "Volver al inicio"
|
other = "Volver al inicio"
|
||||||
|
|
||||||
|
# --- Estado ---
|
||||||
|
[statusBadge]
|
||||||
|
other = "Beta"
|
||||||
|
[statusTitle]
|
||||||
|
other = "En qué punto está Tane"
|
||||||
|
[statusBody]
|
||||||
|
other = "El inventario ya funciona: guarda tus semillas sin conexión, cifradas y sin cuenta. La capa de intercambio vecinal (ofertas, mensajería, confianza) se está construyendo ahora. Todo funciona ya sin ninguna red."
|
||||||
|
|
||||||
|
# --- Capturas ---
|
||||||
|
[screenCapHome]
|
||||||
|
other = "Inicio — tu banco y el mercado a un toque"
|
||||||
|
[screenCapInventory]
|
||||||
|
other = "Inventario — tus semillas, agrupadas por familia"
|
||||||
|
[screenCapMarket]
|
||||||
|
other = "Mercado — regala, intercambia o vende con gente cerca"
|
||||||
|
[screenCapCalendar]
|
||||||
|
other = "Calendario — qué sembrar este mes"
|
||||||
|
[screenCapDetail]
|
||||||
|
other = "Variedad — años, cantidades, procedencia, germinación"
|
||||||
|
[rtlNoteTitle]
|
||||||
|
other = "Internacional por diseño"
|
||||||
|
[rtlNoteBody]
|
||||||
|
other = "Los idiomas de derecha a izquierda y las escrituras no latinas son de primera clase. Aquí, el inventario reflejado para RTL."
|
||||||
|
|
||||||
|
# --- Colabora ---
|
||||||
|
[collabTitle]
|
||||||
|
other = "Colabora"
|
||||||
|
[collabIntro]
|
||||||
|
other = "Tane no tiene modelo de negocio: se sostiene con voluntariado, comunidades y ayudas públicas. Puedes ayudar:"
|
||||||
|
[collabTranslateT]
|
||||||
|
other = "Traduce"
|
||||||
|
[collabTranslateB]
|
||||||
|
other = "Lleva Tane a tu idioma. Los ficheros de traducción son sencillos; los parches son bienvenidos."
|
||||||
|
[collabTestT]
|
||||||
|
other = "Pruébala con un grupo de semillas"
|
||||||
|
[collabTestB]
|
||||||
|
other = "Úsala en una red o feria de semillas real y cuéntanos qué falla o qué falta."
|
||||||
|
[collabCodeT]
|
||||||
|
other = "Programa"
|
||||||
|
[collabCodeB]
|
||||||
|
other = "Flutter/Dart, software libre. Con documentación de diseño y tests."
|
||||||
|
[collabFundT]
|
||||||
|
other = "Apóyala"
|
||||||
|
[collabFundB]
|
||||||
|
other = "Sin anuncios ni comisiones. Ayuda a financiar el trabajo o señálanos ayudas para el común."
|
||||||
|
[collabContact]
|
||||||
|
other = "Escríbenos"
|
||||||
|
|
||||||
|
# --- Preguntas ---
|
||||||
|
[faqTitle]
|
||||||
|
other = "Preguntas"
|
||||||
|
[faqFreeQ]
|
||||||
|
other = "¿Es gratis?"
|
||||||
|
[faqFreeA]
|
||||||
|
other = "Sí. Software libre (AGPL-3.0), sin anuncios, sin comisiones, sin venta de datos."
|
||||||
|
[faqAccountQ]
|
||||||
|
other = "¿Necesito cuenta?"
|
||||||
|
[faqAccountA]
|
||||||
|
other = "Sin cuenta, sin registro, sin servidor. Tus datos se quedan en tu dispositivo."
|
||||||
|
[faqOfflineQ]
|
||||||
|
other = "¿Funciona sin conexión?"
|
||||||
|
[faqOfflineA]
|
||||||
|
other = "Totalmente. Internet solo la enriquece; todo lo esencial funciona sin conexión."
|
||||||
|
[faqLegalQ]
|
||||||
|
other = "¿Es legal compartir semillas?"
|
||||||
|
[faqLegalA]
|
||||||
|
other = "Regalar e intercambiar entre cultivadoras suele estar permitido; vender puede estar regulado. Eres responsable de lo que compartes: mira el aviso sobre semillas."
|
||||||
|
[faqDataQ]
|
||||||
|
other = "¿Y mi privacidad?"
|
||||||
|
[faqDataA]
|
||||||
|
other = "Los datos van cifrados en tu dispositivo y solo sale lo que compartes a propósito. Mira la política de privacidad."
|
||||||
|
|
||||||
|
# --- varios ---
|
||||||
|
[aboutCta]
|
||||||
|
other = "Descubre qué es Tane"
|
||||||
|
[footerSource]
|
||||||
|
other = "Código fuente"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
{{ define "main" }}
|
{{ define "main" }}
|
||||||
<section class="doc">
|
<section class="doc notfound">
|
||||||
<h1>404</h1>
|
<h1>404</h1>
|
||||||
<p class="lead">This page could not be found.</p>
|
<p class="lead">This page could not be found. · No se encontró esta página.</p>
|
||||||
<p class="crumb"><a href="{{ "/" | relLangURL }}">← {{ T "backToHome" }}</a></p>
|
<p class="crumb">
|
||||||
|
<a href="/">← Home</a> · <a href="/es/">← Inicio</a>
|
||||||
|
</p>
|
||||||
</section>
|
</section>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,27 @@
|
||||||
<p class="tagline">{{ .Params.hero.tagline }}</p>
|
<p class="tagline">{{ .Params.hero.tagline }}</p>
|
||||||
<p class="lead">{{ .Params.hero.lead }}</p>
|
<p class="lead">{{ .Params.hero.lead }}</p>
|
||||||
{{ .Content }}
|
{{ .Content }}
|
||||||
|
{{ with .Site.GetPage "/about" }}
|
||||||
|
<p><a class="text-link" href="{{ .RelPermalink }}">{{ T "aboutCta" }} →</a></p>
|
||||||
|
{{ end }}
|
||||||
{{ partial "store-badges.html" . }}
|
{{ partial "store-badges.html" . }}
|
||||||
</div>
|
</div>
|
||||||
{{ $shot := resources.Get (printf "screenshots/%s/inventory.png" $lang) }}
|
{{ $shot := resources.Get (printf "screenshots/%s/home.png" $lang) }}
|
||||||
{{ with $shot }}
|
{{ with $shot }}
|
||||||
<div class="hero-shot">
|
<div class="hero-shot">
|
||||||
<div class="phone"><img src="{{ .RelPermalink }}" alt="Tane inventory" loading="eager" /></div>
|
<div class="phone"><img src="{{ .RelPermalink }}" alt="Tane" loading="eager" /></div>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="status">
|
||||||
|
<span class="badge-beta">{{ T "statusBadge" }}</span>
|
||||||
|
<div>
|
||||||
|
<h2>{{ T "statusTitle" }}</h2>
|
||||||
|
<p>{{ T "statusBody" }}</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="pillars">
|
<section class="pillars">
|
||||||
{{ range .Params.pillars }}
|
{{ range .Params.pillars }}
|
||||||
<article class="pillar">
|
<article class="pillar">
|
||||||
|
|
@ -33,10 +44,23 @@
|
||||||
{{ range $s := $screens }}
|
{{ range $s := $screens }}
|
||||||
{{ $img := resources.Get (printf "screenshots/%s/%s.png" $lang $s) }}
|
{{ $img := resources.Get (printf "screenshots/%s/%s.png" $lang $s) }}
|
||||||
{{ with $img }}
|
{{ with $img }}
|
||||||
<div class="phone"><img src="{{ .RelPermalink }}" alt="Tane {{ $s }}" loading="lazy" /></div>
|
<figure class="phone-fig">
|
||||||
|
<div class="phone"><img src="{{ .RelPermalink }}" alt="Tane {{ $s }}" loading="lazy" /></div>
|
||||||
|
<figcaption>{{ T (printf "screenCap%s" (title $s)) }}</figcaption>
|
||||||
|
</figure>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
{{ $rtl := resources.Get "screenshots/rtl/inventory.png" }}
|
||||||
|
{{ with $rtl }}
|
||||||
|
<div class="rtl-note">
|
||||||
|
<div class="phone phone-sm"><img src="{{ .RelPermalink }}" alt="Tane RTL" loading="lazy" dir="rtl" /></div>
|
||||||
|
<div>
|
||||||
|
<h3>{{ T "rtlNoteTitle" }}</h3>
|
||||||
|
<p>{{ T "rtlNoteBody" }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="values">
|
<section class="values">
|
||||||
|
|
@ -46,6 +70,41 @@
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="faq">
|
||||||
|
<h2>{{ T "faqTitle" }}</h2>
|
||||||
|
<dl>
|
||||||
|
<dt>{{ T "faqFreeQ" }}</dt><dd>{{ T "faqFreeA" }}</dd>
|
||||||
|
<dt>{{ T "faqAccountQ" }}</dt><dd>{{ T "faqAccountA" }}</dd>
|
||||||
|
<dt>{{ T "faqOfflineQ" }}</dt><dd>{{ T "faqOfflineA" }}</dd>
|
||||||
|
<dt>{{ T "faqLegalQ" }}</dt><dd>{{ T "faqLegalA" }} <a href="{{ "/legal/seeds/" | relLangURL }}">→</a></dd>
|
||||||
|
<dt>{{ T "faqDataQ" }}</dt><dd>{{ T "faqDataA" }} <a href="{{ "/legal/privacy/" | relLangURL }}">→</a></dd>
|
||||||
|
</dl>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="collab">
|
||||||
|
<h2>{{ T "collabTitle" }}</h2>
|
||||||
|
<p class="lead">{{ T "collabIntro" }}</p>
|
||||||
|
<div class="collab-grid">
|
||||||
|
<article>
|
||||||
|
<h3>{{ with .Site.Params.weblateURL }}<a href="{{ . }}">{{ T "collabTranslateT" }}</a>{{ else }}{{ T "collabTranslateT" }}{{ end }}</h3>
|
||||||
|
<p>{{ T "collabTranslateB" }}</p>
|
||||||
|
</article>
|
||||||
|
<article>
|
||||||
|
<h3>{{ T "collabTestT" }}</h3>
|
||||||
|
<p>{{ T "collabTestB" }}</p>
|
||||||
|
</article>
|
||||||
|
<article>
|
||||||
|
<h3>{{ with .Site.Params.sourceURL }}<a href="{{ . }}">{{ T "collabCodeT" }}</a>{{ else }}{{ T "collabCodeT" }}{{ end }}</h3>
|
||||||
|
<p>{{ T "collabCodeB" }}</p>
|
||||||
|
</article>
|
||||||
|
<article>
|
||||||
|
<h3>{{ T "collabFundT" }}</h3>
|
||||||
|
<p>{{ T "collabFundB" }}</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
<p><a class="badge" href="mailto:{{ .Site.Params.email }}">{{ T "collabContact" }}</a></p>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="get-it" id="get">
|
<section class="get-it" id="get">
|
||||||
<h2>{{ T "getItTitle" }}</h2>
|
<h2>{{ T "getItTitle" }}</h2>
|
||||||
{{ partial "store-badges.html" . }}
|
{{ partial "store-badges.html" . }}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
{{ if .IsPage }}<a href="{{ .RelPermalink }}">{{ .Title }}</a>{{ end }}
|
{{ if .IsPage }}<a href="{{ .RelPermalink }}">{{ .Title }}</a>{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</nav>
|
</nav>
|
||||||
<p class="foot-note">{{ T "footerFreeSoftware" }}</p>
|
<p class="foot-note">{{ T "footerFreeSoftware" }}{{ with .Site.Params.sourceURL }} · <a href="{{ . }}">{{ T "footerSource" }}</a>{{ end }}</p>
|
||||||
<p class="foot-note">
|
<p class="foot-note">
|
||||||
{{ T "footerPublishedBy" }}
|
{{ T "footerPublishedBy" }}
|
||||||
<a href="{{ .Site.Params.publisherURL }}">{{ .Site.Params.publisher }}</a>
|
<a href="{{ .Site.Params.publisherURL }}">{{ .Site.Params.publisher }}</a>
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,56 @@
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>{{ .Title }} · {{ .Site.Title }}</title>
|
<title>{{ .Title }} · {{ .Site.Title }}</title>
|
||||||
<meta name="description" content="{{ with .Description }}{{ . }}{{ else }}{{ .Site.Params.description }}{{ end }}" />
|
{{ $desc := or .Description .Site.Params.description }}
|
||||||
|
<meta name="description" content="{{ $desc }}" />
|
||||||
<meta name="theme-color" content="#2F7D34" />
|
<meta name="theme-color" content="#2F7D34" />
|
||||||
<link rel="icon" href="/favicon.png" type="image/png" />
|
<link rel="canonical" href="{{ .Permalink }}" />
|
||||||
|
|
||||||
|
<link rel="icon" href="/favicon.ico" sizes="any" />
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" />
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png" />
|
||||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||||
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
|
|
||||||
{{ range .AllTranslations }}
|
{{ range .AllTranslations }}
|
||||||
<link rel="alternate" hreflang="{{ .Language.LanguageCode }}" href="{{ .Permalink }}" />
|
<link rel="alternate" hreflang="{{ .Language.LanguageCode }}" href="{{ .Permalink }}" />
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<meta property="og:title" content="{{ .Title }}" />
|
|
||||||
<meta property="og:description" content="{{ with .Description }}{{ . }}{{ else }}{{ .Site.Params.description }}{{ end }}" />
|
{{ $og := printf "og-%s.png" .Site.Language.Lang | absURL }}
|
||||||
|
<meta property="og:site_name" content="{{ .Site.Title }}" />
|
||||||
|
<meta property="og:title" content="{{ if .IsHome }}{{ .Site.Title }} — {{ .Title }}{{ else }}{{ .Title }}{{ end }}" />
|
||||||
|
<meta property="og:description" content="{{ $desc }}" />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:image" content="/apple-touch-icon.png" />
|
<meta property="og:url" content="{{ .Permalink }}" />
|
||||||
|
<meta property="og:image" content="{{ $og }}" />
|
||||||
|
<meta property="og:image:width" content="1200" />
|
||||||
|
<meta property="og:image:height" content="630" />
|
||||||
|
<meta property="og:locale" content="{{ .Site.Language.LanguageCode }}" />
|
||||||
|
{{ range .AllTranslations }}<meta property="og:locale:alternate" content="{{ .Language.LanguageCode }}" />
|
||||||
|
{{ end }}
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content="{{ .Title }}" />
|
||||||
|
<meta name="twitter:description" content="{{ $desc }}" />
|
||||||
|
<meta name="twitter:image" content="{{ $og }}" />
|
||||||
|
|
||||||
|
{{ if .IsHome }}
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{{ dict
|
||||||
|
"@context" "https://schema.org"
|
||||||
|
"@type" "SoftwareApplication"
|
||||||
|
"name" "Tane"
|
||||||
|
"applicationCategory" "LifestyleApplication"
|
||||||
|
"operatingSystem" "Android, iOS, Linux, Windows, macOS"
|
||||||
|
"description" $desc
|
||||||
|
"url" .Site.BaseURL
|
||||||
|
"image" $og
|
||||||
|
"license" "https://www.gnu.org/licenses/agpl-3.0.html"
|
||||||
|
"isAccessibleForFree" true
|
||||||
|
"offers" (dict "@type" "Offer" "price" "0" "priceCurrency" "EUR")
|
||||||
|
"publisher" (dict "@type" "Organization" "name" .Site.Params.publisher "url" .Site.Params.publisherURL)
|
||||||
|
| jsonify }}
|
||||||
|
</script>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
{{ $css := resources.Get "css/main.css" | minify | fingerprint }}
|
{{ $css := resources.Get "css/main.css" | minify | fingerprint }}
|
||||||
<style>{{ $css.Content | safeCSS }}</style>
|
<style>{{ $css.Content | safeCSS }}</style>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,17 @@ server {
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
|
# Security headers. The page is fully static and self-contained: inline CSS
|
||||||
|
# (needs style-src 'unsafe-inline'), same-origin images (+ data: URIs), no
|
||||||
|
# third-party scripts. HSTS is host-scoped (no includeSubDomains) so it can't
|
||||||
|
# affect sibling *.comunes.org sites. TLS is terminated upstream (assange).
|
||||||
|
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'; font-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||||
|
add_header X-Frame-Options "DENY" always;
|
||||||
|
add_header Permissions-Policy "geolocation=(), camera=(), microphone=(), interest-cohort=()" always;
|
||||||
|
add_header Strict-Transport-Security "max-age=15768000" always;
|
||||||
|
|
||||||
# Hugo emits directory-style URLs (/legal/privacy/index.html).
|
# Hugo emits directory-style URLs (/legal/privacy/index.html).
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ =404;
|
try_files $uri $uri/ =404;
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 5.1 KiB |
BIN
site/static/favicon-16.png
Normal file
|
After Width: | Height: | Size: 572 B |
BIN
site/static/favicon-32.png
Normal file
|
After Width: | Height: | Size: 897 B |
BIN
site/static/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 30 KiB |
BIN
site/static/icon-192.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
site/static/icon-512.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
site/static/og-en.png
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
site/static/og-es.png
Normal file
|
After Width: | Height: | Size: 318 KiB |
13
site/static/site.webmanifest
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"name": "Tane",
|
||||||
|
"short_name": "Tane",
|
||||||
|
"description": "Keep and share traditional seeds — offline, encrypted, no account.",
|
||||||
|
"start_url": "/",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#e7f1e0",
|
||||||
|
"theme_color": "#2f7d34",
|
||||||
|
"icons": [
|
||||||
|
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
|
||||||
|
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" }
|
||||||
|
]
|
||||||
|
}
|
||||||