diff --git a/site/assets/css/main.css b/site/assets/css/main.css index 4d6614e..041ddd3 100644 --- a/site/assets/css/main.css +++ b/site/assets/css/main.css @@ -196,3 +196,59 @@ h2 { font-size: clamp(1.4rem, 3vw, 1.9rem); color: var(--green-dark); } .hero-shot { order: -1; } .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; } +} diff --git a/site/config.toml b/site/config.toml index 917ebdd..99a9450 100644 --- a/site/config.toml +++ b/site/config.toml @@ -14,20 +14,25 @@ enableGitInfo = false publisher = "Asociación Comunes" publisherURL = "https://comunes.org" license = "AGPL-3.0" - # Store links are empty until the app is published; the badges partial renders - # a link only when its URL is set here, so nothing broken shows before launch. - playStoreURL = "" - fdroidURL = "" + # Links rendered only when set, so nothing broken shows before they exist: + playStoreURL = "" # Google Play, once published + fdroidURL = "" # F-Droid, once published + sourceURL = "" # public source repository (AGPL) — set when available + weblateURL = "" # translation platform — set when hosting is ready [languages] [languages.en] languageName = "English" languageCode = "en" weight = 1 + [languages.en.params] + description = "A local-first, decentralized app for keeping and sharing traditional seeds. Offline, encrypted, no account." [languages.es] languageName = "Español" languageCode = "es" 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] unsafe = false diff --git a/site/i18n/en.toml b/site/i18n/en.toml index 1293a73..0c6f815 100644 --- a/site/i18n/en.toml +++ b/site/i18n/en.toml @@ -33,3 +33,81 @@ other = "Contact" [backToHome] 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" diff --git a/site/i18n/es.toml b/site/i18n/es.toml index c8e795b..1ebc6bf 100644 --- a/site/i18n/es.toml +++ b/site/i18n/es.toml @@ -33,3 +33,81 @@ other = "Contacto" [backToHome] 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" diff --git a/site/layouts/404.html b/site/layouts/404.html index 872ebf1..ab63f41 100644 --- a/site/layouts/404.html +++ b/site/layouts/404.html @@ -1,7 +1,9 @@ {{ define "main" }} -
+

404

-

This page could not be found.

-

← {{ T "backToHome" }}

+

This page could not be found. · No se encontró esta página.

+

+ ← Home · ← Inicio +

{{ end }} diff --git a/site/layouts/index.html b/site/layouts/index.html index 28d77a1..34e709d 100644 --- a/site/layouts/index.html +++ b/site/layouts/index.html @@ -6,16 +6,27 @@

{{ .Params.hero.tagline }}

{{ .Params.hero.lead }}

{{ .Content }} + {{ with .Site.GetPage "/about" }} +

{{ T "aboutCta" }} →

+ {{ end }} {{ partial "store-badges.html" . }} - {{ $shot := resources.Get (printf "screenshots/%s/inventory.png" $lang) }} + {{ $shot := resources.Get (printf "screenshots/%s/home.png" $lang) }} {{ with $shot }}
-
Tane inventory
+
Tane
{{ end }}
+
+ {{ T "statusBadge" }} +
+

{{ T "statusTitle" }}

+

{{ T "statusBody" }}

+
+
+
{{ range .Params.pillars }}
@@ -33,10 +44,23 @@ {{ range $s := $screens }} {{ $img := resources.Get (printf "screenshots/%s/%s.png" $lang $s) }} {{ with $img }} -
Tane {{ $s }}
+
+
Tane {{ $s }}
+
{{ T (printf "screenCap%s" (title $s)) }}
+
{{ end }} {{ end }} + {{ $rtl := resources.Get "screenshots/rtl/inventory.png" }} + {{ with $rtl }} +
+
Tane RTL
+
+

{{ T "rtlNoteTitle" }}

+

{{ T "rtlNoteBody" }}

+
+
+ {{ end }}
@@ -46,6 +70,41 @@
+
+

{{ T "faqTitle" }}

+
+
{{ T "faqFreeQ" }}
{{ T "faqFreeA" }}
+
{{ T "faqAccountQ" }}
{{ T "faqAccountA" }}
+
{{ T "faqOfflineQ" }}
{{ T "faqOfflineA" }}
+
{{ T "faqLegalQ" }}
{{ T "faqLegalA" }}
+
{{ T "faqDataQ" }}
{{ T "faqDataA" }}
+
+
+ +
+

{{ T "collabTitle" }}

+

{{ T "collabIntro" }}

+
+
+

{{ with .Site.Params.weblateURL }}{{ T "collabTranslateT" }}{{ else }}{{ T "collabTranslateT" }}{{ end }}

+

{{ T "collabTranslateB" }}

+
+
+

{{ T "collabTestT" }}

+

{{ T "collabTestB" }}

+
+
+

{{ with .Site.Params.sourceURL }}{{ T "collabCodeT" }}{{ else }}{{ T "collabCodeT" }}{{ end }}

+

{{ T "collabCodeB" }}

+
+
+

{{ T "collabFundT" }}

+

{{ T "collabFundB" }}

+
+
+

{{ T "collabContact" }}

+
+

{{ T "getItTitle" }}

{{ partial "store-badges.html" . }} diff --git a/site/layouts/partials/footer.html b/site/layouts/partials/footer.html index 0eb06d9..fc720fc 100644 --- a/site/layouts/partials/footer.html +++ b/site/layouts/partials/footer.html @@ -5,7 +5,7 @@ {{ if .IsPage }}{{ .Title }}{{ end }} {{ end }} -

{{ T "footerFreeSoftware" }}

+

{{ T "footerFreeSoftware" }}{{ with .Site.Params.sourceURL }} · {{ T "footerSource" }}{{ end }}

{{ T "footerPublishedBy" }} {{ .Site.Params.publisher }} diff --git a/site/layouts/partials/head.html b/site/layouts/partials/head.html index 40a6c58..e86ba99 100644 --- a/site/layouts/partials/head.html +++ b/site/layouts/partials/head.html @@ -1,16 +1,56 @@ {{ .Title }} · {{ .Site.Title }} - +{{ $desc := or .Description .Site.Params.description }} + - + + + + + + + {{ range .AllTranslations }} {{ end }} - - + +{{ $og := printf "og-%s.png" .Site.Language.Lang | absURL }} + + + - + + + + + +{{ range .AllTranslations }} +{{ end }} + + + + + +{{ if .IsHome }} + +{{ end }} + {{ $css := resources.Get "css/main.css" | minify | fingerprint }} diff --git a/site/nginx.conf b/site/nginx.conf index a655aad..9dce0bb 100644 --- a/site/nginx.conf +++ b/site/nginx.conf @@ -4,6 +4,17 @@ server { root /usr/share/nginx/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). location / { try_files $uri $uri/ =404; diff --git a/site/static/apple-touch-icon.png b/site/static/apple-touch-icon.png index a2db482..9db37f7 100644 Binary files a/site/static/apple-touch-icon.png and b/site/static/apple-touch-icon.png differ diff --git a/site/static/favicon-16.png b/site/static/favicon-16.png new file mode 100644 index 0000000..f6c75da Binary files /dev/null and b/site/static/favicon-16.png differ diff --git a/site/static/favicon-32.png b/site/static/favicon-32.png new file mode 100644 index 0000000..1fc50c9 Binary files /dev/null and b/site/static/favicon-32.png differ diff --git a/site/static/favicon.ico b/site/static/favicon.ico new file mode 100644 index 0000000..b111541 Binary files /dev/null and b/site/static/favicon.ico differ diff --git a/site/static/favicon.png b/site/static/favicon.png deleted file mode 100644 index 91f8e59..0000000 Binary files a/site/static/favicon.png and /dev/null differ diff --git a/site/static/icon-192.png b/site/static/icon-192.png new file mode 100644 index 0000000..10019b6 Binary files /dev/null and b/site/static/icon-192.png differ diff --git a/site/static/icon-512.png b/site/static/icon-512.png new file mode 100644 index 0000000..37d0ddf Binary files /dev/null and b/site/static/icon-512.png differ diff --git a/site/static/og-en.png b/site/static/og-en.png new file mode 100644 index 0000000..deadf99 Binary files /dev/null and b/site/static/og-en.png differ diff --git a/site/static/og-es.png b/site/static/og-es.png new file mode 100644 index 0000000..4bc91a2 Binary files /dev/null and b/site/static/og-es.png differ diff --git a/site/static/site.webmanifest b/site/static/site.webmanifest new file mode 100644 index 0000000..d60117c --- /dev/null +++ b/site/static/site.webmanifest @@ -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" } + ] +}