feat(web): tane.comunes.org landing + localized app screenshots
- Hugo site (site/): EN/ES intro + legal (generated from docs/legal), an
ES/EN About page from docs/{que-es-tane,what-is-tane}.md, seed-green theme,
responsive header, store-badge placeholders, multi-stage Hugo->nginx image.
- Golden screenshot harness (test/screenshots/): en,es,fr,de,pt,ja + RTL demo,
real fonts via DejaVu Sans + FontManifest; skip-by-default tag so CI stays
green. collect_screenshots.sh feeds site/ and fastlane phoneScreenshots.
- Drop editorial notes from the public explainer.
|
|
@ -11,3 +11,13 @@
|
|||
#
|
||||
# A genuinely slower (but finite) test can opt out with @Timeout(Duration(...)).
|
||||
timeout: 90s
|
||||
|
||||
tags:
|
||||
# Localized store/landing screenshots (test/screenshots/). These are asset
|
||||
# GENERATION, not a correctness gate, and golden pixel-matching is sensitive
|
||||
# to OS/font/Flutter version — so they must NOT run in the normal suite (incl.
|
||||
# CI's `flutter test --coverage`). Run them explicitly:
|
||||
# flutter test --run-skipped --tags screenshots test/screenshots/
|
||||
# add --update-goldens to (re)write the PNGs.
|
||||
screenshots:
|
||||
skip: "asset generation; run with --run-skipped --tags screenshots"
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 175 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 179 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 184 KiB |
43
apps/app_seeds/test/screenshots/README.md
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Localized app screenshots
|
||||
|
||||
Golden-based harness that renders key screens as PNGs in several languages, for
|
||||
the landing site (`tane.comunes.org`) and the app-store listings. No emulator —
|
||||
it runs under `flutter test`, so it's deterministic and CI-friendly.
|
||||
|
||||
## Regenerate
|
||||
|
||||
```sh
|
||||
cd apps/app_seeds
|
||||
flutter test --update-goldens --run-skipped --tags screenshots test/screenshots/screenshots_test.dart
|
||||
tool/collect_screenshots.sh # copy PNGs into site/ and fastlane/
|
||||
```
|
||||
|
||||
Drop `--update-goldens` to *verify* the committed PNGs still match. The
|
||||
`screenshots` tag is **skipped by default** (`dart_test.yaml`) — so it never
|
||||
runs in the normal suite or CI's `flutter test --coverage`, where golden pixel
|
||||
differences across OS/font versions would cause false failures. `--run-skipped`
|
||||
opts it back in.
|
||||
|
||||
## What it produces
|
||||
|
||||
`goldens/<locale>/<screen>.png` for **en, es, fr, de, pt, ja**, screens
|
||||
**home · inventory · market · calendar · detail**, plus `goldens/rtl/inventory.png`.
|
||||
The market is rendered populated via a seeded `OffersCubit` with a no-op transport
|
||||
(no network); home/calendar/detail/inventory render from the repository alone.
|
||||
|
||||
- Fonts: real glyphs come from `loadScreenshotFonts()` — every family in
|
||||
`FontManifest.json` (MaterialIcons + bundled Noto/seedks) plus the bundled
|
||||
**DejaVu Sans** as the Latin text face. No Roboto needed.
|
||||
- `rtl/` is a **layout demo**, not a locale: English strings forced
|
||||
right-to-left to prove the design is RTL-safe. The app ships no Arabic
|
||||
translation yet, so there is deliberately no `ar/` with Arabic copy.
|
||||
- Partial locales (e.g. `ja`) fall back to English for untranslated strings —
|
||||
that's the app's real runtime behavior, shown honestly.
|
||||
- These are raw device-canvas frames (no marketing captions or device bezels).
|
||||
Add those downstream only if a store rejects plain screenshots.
|
||||
|
||||
## Adding a screen or locale
|
||||
|
||||
Edit `screenshotLocales` / the `screens` map in `screenshots_test.dart`. Screens
|
||||
must render from the repository + cubits alone (no live Nostr/network stack), so
|
||||
inventory/detail/calendar are the safe, self-contained set.
|
||||
BIN
apps/app_seeds/test/screenshots/goldens/de/calendar.png
Normal file
|
After Width: | Height: | Size: 146 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/de/detail.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/de/home.png
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/de/inventory.png
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/de/market.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/en/calendar.png
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/en/detail.png
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/en/home.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/en/inventory.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/en/market.png
Normal file
|
After Width: | Height: | Size: 175 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/es/calendar.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/es/detail.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/es/home.png
Normal file
|
After Width: | Height: | Size: 125 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/es/inventory.png
Normal file
|
After Width: | Height: | Size: 165 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/es/market.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/fr/calendar.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/fr/detail.png
Normal file
|
After Width: | Height: | Size: 181 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/fr/home.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/fr/inventory.png
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/fr/market.png
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/ja/calendar.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/ja/detail.png
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/ja/home.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/ja/inventory.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/ja/market.png
Normal file
|
After Width: | Height: | Size: 175 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/pt/calendar.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/pt/detail.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/pt/home.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/pt/inventory.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/pt/market.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
apps/app_seeds/test/screenshots/goldens/rtl/inventory.png
Normal file
|
After Width: | Height: | Size: 165 KiB |
188
apps/app_seeds/test/screenshots/screenshot_support.dart
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:commons_core/commons_core.dart';
|
||||
import 'package:drift/drift.dart' show Value;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show FontLoader, rootBundle;
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tane/app.dart' show materialLocaleFor;
|
||||
import 'package:tane/data/species_repository.dart';
|
||||
import 'package:tane/data/variety_repository.dart';
|
||||
import 'package:tane/db/database.dart';
|
||||
import 'package:tane/db/enums.dart';
|
||||
import 'package:tane/domain/crop_calendar.dart' show monthsToMask;
|
||||
import 'package:tane/i18n/strings.g.dart';
|
||||
import 'package:tane/state/inventory_cubit.dart';
|
||||
import 'package:tane/ui/theme.dart';
|
||||
|
||||
/// Marketing screenshot canvas: a tall phone at 3x. Logical 360x760.
|
||||
const screenshotSize = Size(1080, 2280);
|
||||
const screenshotPixelRatio = 3.0;
|
||||
|
||||
/// Locales we render real, translated screenshots for. Asturian (`ast`) is
|
||||
/// omitted from store assets; the RTL demo is handled separately (the app has
|
||||
/// no Arabic strings yet — see [ScreenshotLocale.rtlDemo]).
|
||||
const screenshotLocales = <AppLocale>[
|
||||
AppLocale.en,
|
||||
AppLocale.es,
|
||||
AppLocale.fr,
|
||||
AppLocale.de,
|
||||
AppLocale.pt,
|
||||
AppLocale.ja,
|
||||
];
|
||||
|
||||
bool _fontsLoaded = false;
|
||||
|
||||
/// Registers real glyph-bearing fonts so golden screenshots show text and icons
|
||||
/// rather than the Ahem/tofu boxes flutter_test uses by default. Loads every
|
||||
/// family declared in the test bundle's FontManifest.json (MaterialIcons, the
|
||||
/// bundled Noto Sans JP/Arabic and seedks glyphs), then adds DejaVu Sans — a
|
||||
/// bundled asset, not a font *family* — as the Latin text face so en/es/fr/de/pt
|
||||
/// render legibly without needing Roboto.
|
||||
Future<void> loadScreenshotFonts() async {
|
||||
if (_fontsLoaded) return;
|
||||
|
||||
Future<void> family(String name, List<String> assets) async {
|
||||
final loader = FontLoader(name);
|
||||
for (final asset in assets) {
|
||||
loader.addFont(rootBundle.load(asset));
|
||||
}
|
||||
await loader.load();
|
||||
}
|
||||
|
||||
final manifest =
|
||||
json.decode(await rootBundle.loadString('FontManifest.json'))
|
||||
as List<dynamic>;
|
||||
for (final entry in manifest.cast<Map<String, dynamic>>()) {
|
||||
await family(
|
||||
entry['family'] as String,
|
||||
[for (final f in entry['fonts'] as List) f['asset'] as String],
|
||||
);
|
||||
}
|
||||
|
||||
await family('DejaVu Sans', [
|
||||
'assets/fonts/DejaVuSans.ttf',
|
||||
'assets/fonts/DejaVuSans-Bold.ttf',
|
||||
]);
|
||||
_fontsLoaded = true;
|
||||
}
|
||||
|
||||
const _fontFallbacks = <String>['Noto Sans JP', 'Noto Sans Arabic'];
|
||||
|
||||
/// The real app theme, but with every text style pinned to the bundled
|
||||
/// [DejaVu Sans] so screenshots render legible glyphs (see [loadScreenshotFonts]).
|
||||
ThemeData screenshotTheme() {
|
||||
final base = buildTaneTheme();
|
||||
return base.copyWith(
|
||||
textTheme: base.textTheme.apply(
|
||||
fontFamily: 'DejaVu Sans',
|
||||
fontFamilyFallback: _fontFallbacks,
|
||||
),
|
||||
primaryTextTheme: base.primaryTextTheme.apply(
|
||||
fontFamily: 'DejaVu Sans',
|
||||
fontFamilyFallback: _fontFallbacks,
|
||||
),
|
||||
appBarTheme: base.appBarTheme.copyWith(
|
||||
titleTextStyle: base.appBarTheme.titleTextStyle?.copyWith(
|
||||
fontFamily: 'DejaVu Sans',
|
||||
fontFamilyFallback: _fontFallbacks,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Wraps [child] as a full screen for capture: the real green theme with
|
||||
/// screenshot fonts, the given [locale], repositories and an [InventoryCubit].
|
||||
/// Pass [textDirection] to force RTL for the layout demo.
|
||||
Widget screenshotApp({
|
||||
required VarietyRepository repository,
|
||||
required SpeciesRepository species,
|
||||
required Widget child,
|
||||
AppLocale locale = AppLocale.en,
|
||||
TextDirection? textDirection,
|
||||
}) {
|
||||
LocaleSettings.setLocaleSync(locale);
|
||||
return TranslationProvider(
|
||||
child: MultiRepositoryProvider(
|
||||
providers: [
|
||||
RepositoryProvider.value(value: repository),
|
||||
RepositoryProvider.value(value: species),
|
||||
],
|
||||
child: BlocProvider(
|
||||
create: (_) => InventoryCubit(repository),
|
||||
child: MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: screenshotTheme(),
|
||||
locale: materialLocaleFor(locale.flutterLocale),
|
||||
supportedLocales: AppLocaleUtils.supportedLocales,
|
||||
localizationsDelegates: const [
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
home: textDirection == null
|
||||
? child
|
||||
: Directionality(textDirection: textDirection, child: child),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// One seeded variety plus the id of a "hero" variety used for the detail shot.
|
||||
class SeededInventory {
|
||||
const SeededInventory(this.heroVarietyId);
|
||||
final String heroVarietyId;
|
||||
}
|
||||
|
||||
/// Seeds an attractive, internationally-neutral inventory: a spread of
|
||||
/// colour-coded botanical families, lots with years/quantities/origins, photo
|
||||
/// avatars, and crop-calendar month masks so the calendar screen is populated.
|
||||
/// Returns the hero variety (a cherry tomato with several lots) for detail.
|
||||
Future<SeededInventory> seedShowcase(
|
||||
AppDatabase db,
|
||||
VarietyRepository repo,
|
||||
) async {
|
||||
// Sow in spring, harvest seed in late summer — visible in the calendar.
|
||||
final sow = monthsToMask(const [3, 4, 5]);
|
||||
final harvest = monthsToMask(const [8, 9]);
|
||||
|
||||
// Varieties render with the app's default coloured-initial disc avatar —
|
||||
// the on-brand default when no photo is set — so no image decoding is needed.
|
||||
Future<String> add(String label, String family) async {
|
||||
final id = await repo.addQuickVariety(label: label, category: family);
|
||||
await (db.update(db.varieties)..where((v) => v.id.equals(id))).write(
|
||||
VarietiesCompanion(
|
||||
sowMonths: Value(sow),
|
||||
seedHarvestMonths: Value(harvest),
|
||||
),
|
||||
);
|
||||
return id;
|
||||
}
|
||||
|
||||
final tomato = await add('Cherry tomato', 'Solanaceae');
|
||||
await repo.addLot(
|
||||
varietyId: tomato,
|
||||
harvestYear: 2024,
|
||||
quantity: const Quantity(kind: QuantityKind.handful),
|
||||
originName: 'Community seed swap',
|
||||
abundance: Abundance.plentyToShare,
|
||||
offerStatus: OfferStatus.shared,
|
||||
);
|
||||
await repo.addLot(
|
||||
varietyId: tomato,
|
||||
harvestYear: 2023,
|
||||
quantity: const Quantity(kind: QuantityKind.packet, count: 1),
|
||||
offerStatus: OfferStatus.exchange,
|
||||
);
|
||||
|
||||
await add('Climbing bean', 'Fabaceae');
|
||||
await add('Sunflower', 'Asteraceae');
|
||||
await add('Sweet basil', 'Lamiaceae');
|
||||
await add('Rainbow chard', 'Amaranthaceae');
|
||||
await add('Purple carrot', 'Apiaceae');
|
||||
|
||||
return SeededInventory(tomato);
|
||||
}
|
||||
161
apps/app_seeds/test/screenshots/screenshots_test.dart
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
@Tags(['screenshots'])
|
||||
library;
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:commons_core/commons_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tane/data/species_repository.dart';
|
||||
import 'package:tane/data/variety_repository.dart';
|
||||
import 'package:tane/db/database.dart';
|
||||
import 'package:tane/i18n/strings.g.dart';
|
||||
import 'package:tane/state/offers_cubit.dart';
|
||||
import 'package:tane/state/variety_detail_cubit.dart';
|
||||
import 'package:tane/ui/calendar_screen.dart';
|
||||
import 'package:tane/ui/home_screen.dart';
|
||||
import 'package:tane/ui/inventory_list_screen.dart';
|
||||
import 'package:tane/ui/market_screen.dart';
|
||||
import 'package:tane/ui/variety_detail_screen.dart';
|
||||
|
||||
import '../support/test_support.dart';
|
||||
import 'screenshot_support.dart';
|
||||
|
||||
/// Generates localized marketing/store screenshots as golden PNGs.
|
||||
///
|
||||
/// Run (writes the PNGs) — the `screenshots` tag is skipped by default
|
||||
/// (dart_test.yaml), so `--run-skipped` is required:
|
||||
/// flutter test --update-goldens --run-skipped --tags screenshots test/screenshots/screenshots_test.dart
|
||||
///
|
||||
/// Output: test/screenshots/goldens/`<locale>`/`<screen>`.png for en/es/fr/de/pt/ja,
|
||||
/// plus goldens/rtl/ — a right-to-left *layout* demo (English strings mirrored;
|
||||
/// the app ships no Arabic translation yet, so this proves the design is RTL-safe
|
||||
/// rather than claiming an Arabic locale). These are raw device-canvas frames
|
||||
/// with no marketing chrome; add captions/device frames downstream if a store
|
||||
/// requires them. `tool/collect_screenshots.sh` copies them into site/ and fastlane/.
|
||||
void main() {
|
||||
setUpAll(() async {
|
||||
await loadScreenshotFonts();
|
||||
// Touch mode never draws focus rings, so no highlight frames the FAB/fields.
|
||||
FocusManager.instance.highlightStrategy =
|
||||
FocusHighlightStrategy.alwaysTouch;
|
||||
});
|
||||
|
||||
late AppDatabase db;
|
||||
late VarietyRepository repo;
|
||||
late SpeciesRepository species;
|
||||
late SeededInventory seeded;
|
||||
|
||||
setUp(() async {
|
||||
db = newTestDatabase();
|
||||
repo = newTestRepository(db);
|
||||
species = newTestSpeciesRepository(db);
|
||||
seeded = await seedShowcase(db, repo);
|
||||
});
|
||||
tearDown(() => db.close());
|
||||
|
||||
Future<void> capture(WidgetTester tester, String dir, String name) async {
|
||||
tester.view.physicalSize = screenshotSize;
|
||||
tester.view.devicePixelRatio = screenshotPixelRatio;
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
await tester.pumpAndSettle();
|
||||
await expectLater(
|
||||
find.byType(MaterialApp),
|
||||
matchesGoldenFile('goldens/$dir/$name.png'),
|
||||
);
|
||||
await disposeTree(tester);
|
||||
}
|
||||
|
||||
// A POPULATED market: a seeded OffersCubit (no transport) feeding MarketBody,
|
||||
// so the offer list renders with no live discovery stream to hang
|
||||
// pumpAndSettle. (Live discovery is exercised by offers_cubit_test.dart; see
|
||||
// the note in market_screen_test.dart on why we don't drive it via widgets.)
|
||||
Future<Widget> market() async => Builder(
|
||||
builder: (context) => Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(context.t.market.title),
|
||||
actions: [IconButton(icon: const Icon(Icons.tune), onPressed: () {})],
|
||||
),
|
||||
body: BlocProvider<OffersCubit>(
|
||||
create: (_) => _SeededOffersCubit(_sampleOffers()),
|
||||
child: MarketBody(onConfigure: () {}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/// Each entry renders one screen; the runner re-seeds and re-locales per shot.
|
||||
final screens = <String, Future<Widget> Function()>{
|
||||
'home': () async => const HomeScreen(marketEnabled: true),
|
||||
'inventory': () async => const InventoryListScreen(),
|
||||
'market': market,
|
||||
'calendar': () async => const CalendarScreen(initialMonth: 4),
|
||||
'detail': () async => BlocProvider(
|
||||
create: (_) => VarietyDetailCubit(repo, seeded.heroVarietyId),
|
||||
child: const VarietyDetailScreen(),
|
||||
),
|
||||
};
|
||||
|
||||
for (final locale in screenshotLocales) {
|
||||
for (final entry in screens.entries) {
|
||||
testWidgets('${locale.languageCode}/${entry.key}', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
screenshotApp(
|
||||
repository: repo,
|
||||
species: species,
|
||||
locale: locale,
|
||||
child: await entry.value(),
|
||||
),
|
||||
);
|
||||
await capture(tester, locale.languageCode, entry.key);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// RTL layout demo: base (English) strings, forced right-to-left, so the
|
||||
// mirrored inventory proves the design is RTL-safe. Not a translated locale.
|
||||
testWidgets('rtl/inventory', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
screenshotApp(
|
||||
repository: repo,
|
||||
species: species,
|
||||
locale: AppLocale.en,
|
||||
textDirection: TextDirection.rtl,
|
||||
child: const InventoryListScreen(),
|
||||
),
|
||||
);
|
||||
await capture(tester, 'rtl', 'inventory');
|
||||
});
|
||||
}
|
||||
|
||||
/// An [OffersCubit] pre-loaded with a fixed offer list. It carries a no-op
|
||||
/// transport (never called — offers are pre-seeded) purely so `isOnline` is
|
||||
/// true and MarketBody renders the list instead of the "can't reach" state.
|
||||
class _SeededOffersCubit extends OffersCubit {
|
||||
_SeededOffersCubit(List<Offer> offers) : super(_NoopOfferTransport()) {
|
||||
emit(state.copyWith(offers: offers, hasSearched: true, areaGeohash: 'sp3e'));
|
||||
}
|
||||
}
|
||||
|
||||
/// A transport that is present (so the market reads as online) but never used.
|
||||
class _NoopOfferTransport implements OfferTransport {
|
||||
@override
|
||||
Stream<Offer> discover(DiscoveryQuery query) => const Stream.empty();
|
||||
@override
|
||||
Future<PublishResult> publish(Offer offer) => throw UnimplementedError();
|
||||
@override
|
||||
Future<void> retract(String offerId) async {}
|
||||
@override
|
||||
Future<void> close() async {}
|
||||
}
|
||||
|
||||
/// A small, internationally-neutral set of nearby offers across gift / swap /
|
||||
/// sale and colour-coded botanical families.
|
||||
List<Offer> _sampleOffers() => [
|
||||
Offer(id: 'o1', authorPubkeyHex: 'a1' * 32, summary: 'Cherry tomato', type: OfferType.gift, category: 'Solanaceae', approxGeohash: 'sp3e9', isOrganic: true),
|
||||
Offer(id: 'o2', authorPubkeyHex: 'a2' * 32, summary: 'Climbing bean', type: OfferType.exchange, category: 'Fabaceae', approxGeohash: 'sp3e8'),
|
||||
Offer(id: 'o3', authorPubkeyHex: 'a3' * 32, summary: 'Sunflower', type: OfferType.sale, category: 'Asteraceae', approxGeohash: 'sp3ec', priceAmount: 2, priceCurrency: '€'),
|
||||
Offer(id: 'o4', authorPubkeyHex: 'a4' * 32, summary: 'Sweet basil', type: OfferType.gift, category: 'Lamiaceae', approxGeohash: 'sp3e2', isOrganic: true),
|
||||
Offer(id: 'o5', authorPubkeyHex: 'a5' * 32, summary: 'Purple carrot', type: OfferType.exchange, category: 'Apiaceae', approxGeohash: 'sp3ef'),
|
||||
];
|
||||
54
apps/app_seeds/tool/collect_screenshots.sh
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copies the localized golden screenshots into the two places that consume them:
|
||||
# 1. the Hugo landing site (site/assets/screenshots/<locale>/)
|
||||
# 2. the Play Store metadata (fastlane/metadata/android/<play-locale>/images/phoneScreenshots/)
|
||||
#
|
||||
# Regenerate the PNGs first:
|
||||
# flutter test --update-goldens --tags screenshots test/screenshots/screenshots_test.dart
|
||||
# then run this from apps/app_seeds/:
|
||||
# tool/collect_screenshots.sh
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # apps/app_seeds
|
||||
repo_root="$(cd "$here/../.." && pwd)"
|
||||
goldens="$here/test/screenshots/goldens"
|
||||
site_dir="$repo_root/site/assets/screenshots"
|
||||
fastlane_dir="$here/fastlane/metadata/android"
|
||||
|
||||
if [[ ! -d "$goldens" ]]; then
|
||||
echo "No goldens at $goldens — run the screenshots test with --update-goldens first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# App locale (golden dir) -> Play Store locale (fastlane dir). 'rtl' is a layout
|
||||
# demo only (not a real locale) and goes to the site, not the stores.
|
||||
declare -A play_locale=(
|
||||
[en]=en-US [es]=es-ES [fr]=fr-FR [de]=de-DE [pt]=pt-PT [ja]=ja-JP
|
||||
)
|
||||
|
||||
for dir in "$goldens"/*/; do
|
||||
locale="$(basename "$dir")"
|
||||
|
||||
# 1) Landing site: every locale, including the RTL demo.
|
||||
mkdir -p "$site_dir/$locale"
|
||||
cp "$dir"*.png "$site_dir/$locale/"
|
||||
|
||||
# 2) Play Store: only locales that ALREADY have text metadata (a title.txt).
|
||||
# A locale dir with images but no store text is invalid for `fastlane supply`,
|
||||
# so we don't create image-only locales — add the text first, then it's picked up.
|
||||
play="${play_locale[$locale]:-}"
|
||||
if [[ -n "$play" && -f "$fastlane_dir/$play/title.txt" ]]; then
|
||||
shots="$fastlane_dir/$play/images/phoneScreenshots"
|
||||
mkdir -p "$shots"
|
||||
# Number them so the store shows them in a deliberate order.
|
||||
i=1
|
||||
for name in home inventory market calendar detail; do
|
||||
[[ -f "$dir$name.png" ]] && cp "$dir$name.png" "$shots/$i.png" && i=$((i + 1))
|
||||
done
|
||||
echo " store: $play ($((i - 1)) shots)"
|
||||
fi
|
||||
echo "site: $locale"
|
||||
done
|
||||
|
||||
echo "Done. To add a Play locale beyond en-US/es-ES, create its title/short/full"
|
||||
echo "description text under fastlane/metadata/android/<locale>/ first, then re-run."
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
# Tane — qué es
|
||||
|
||||
> *Texto divulgativo para todos los públicos, sin dar por sabidos los conceptos.*
|
||||
|
||||
**Tane** (種) es «semilla» en japonés; el nombre completo, *tanemaki* (種まき), es «sembrar / esparcir semillas».
|
||||
|
||||
## En una frase
|
||||
|
|
@ -33,8 +31,6 @@ con libretas y hojas de cálculo.
|
|||
|
||||
## Por qué es distinta
|
||||
|
||||
*(cada idea, explicada)*
|
||||
|
||||
- **Es libre y de todos.** No es de ninguna empresa: cualquiera puede usarla, copiarla,
|
||||
traducirla o mejorarla, gratis y para siempre. Es más una *receta que se comparte* que un
|
||||
producto cerrado — a esto se le llama **software libre**. Y quien la mejore está obligado
|
||||
|
|
|
|||
72
docs/what-is-tane.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# Tane — what it is
|
||||
|
||||
**Tane** (種) means "seed" in Japanese; the full name, *tanemaki* (種まき), means "to sow / scatter seeds".
|
||||
|
||||
## In one sentence
|
||||
|
||||
A simple, free app to **keep your seeds and share them** with whoever you like. It works
|
||||
**without internet** and with no company in the middle.
|
||||
|
||||
## Why it's needed
|
||||
|
||||
Today a handful of companies control much of the world's seed. Many seeds are made so they
|
||||
won't serve again: they give one harvest, but their seeds don't germinate well, so you have
|
||||
to **buy them again every year**. Meanwhile the traditional varieties — grown and improved
|
||||
over thousands of years — are being lost, and with them the knowledge of how to grow them.
|
||||
|
||||
Sharing seeds is one of the oldest and most natural things there is, yet in some places it
|
||||
has become complicated or even fined (in France an association was penalised for handing out
|
||||
varieties that weren't on the official approved list). And the people who care for seeds
|
||||
still do it with notebooks and spreadsheets.
|
||||
|
||||
## What it does, made easy
|
||||
|
||||
- **Keep** — your seed inventory: what you have, from which year, how much, where it came
|
||||
from, under **the name you use** (no Latin required). The same whether you have four
|
||||
packets in a drawer or a group with hundreds of varieties.
|
||||
- **Share** — you say what you offer; someone nearby sees it and writes to you, to **give
|
||||
away, swap or sell** if you want. You close the deal yourself, directly. No company steps
|
||||
in or takes a commission.
|
||||
|
||||
## Why it's different
|
||||
|
||||
- **It's free and belongs to everyone.** It isn't owned by any company: anyone can use,
|
||||
copy, translate or improve it, free and forever. It's more a *recipe that gets shared*
|
||||
than a closed product — this is called **free software**. And whoever improves it is
|
||||
bound to share those improvements just as freely, so no one can "close" it later (that's
|
||||
**copyleft**).
|
||||
- **It works offline.** The basics run even out in the field with no signal.
|
||||
- **Your data is yours.** Your information is kept on **your own phone**, protected with a
|
||||
key, not on some company's computers. We don't sell it or upload it anywhere. No ads.
|
||||
- **No one can shut it down or control it.** There's no central computer that everything
|
||||
passes through: people communicate **directly with each other**, like passing seeds from
|
||||
hand to hand. So no one can censor it or charge you to use it (that's what being
|
||||
**decentralized** means).
|
||||
- **You trust by word of mouth.** You deal with people you know and with those vouched for
|
||||
by people you trust — the way it's always worked in a village or at a fair — without
|
||||
having to give your real name or phone number unless you want to.
|
||||
- **In many languages.** For anywhere in the world, not for a single country. Volunteers
|
||||
translate it.
|
||||
|
||||
## Who it's for
|
||||
|
||||
Seed groups and networks, gardens and collectives, growers… and anyone with a few packets
|
||||
put away. For all ages, from 10 to 80.
|
||||
|
||||
## The name
|
||||
|
||||
**Tane** means "seed" (種). It comes from *tanemaki* (種まき), "to sow seeds" in Japanese, a
|
||||
nod to old customs of mutual aid between neighbours (sharing the work, saving together).
|
||||
|
||||
## Where it stands and how to help
|
||||
|
||||
In its early days. You can help by trying it out in a real seed group, translating it,
|
||||
sharing what you know about the varieties, or coding. It has no price and never will: it's
|
||||
sustained by volunteers, by the communities themselves, and by public funding for projects
|
||||
of common interest.
|
||||
|
||||
---
|
||||
|
||||
> *The idea underneath: traditional seeds are a heritage of humankind — everyone's and no
|
||||
> one's. Against those who would privatise them, Tane aims to make it easy for you to keep
|
||||
> them, multiply them and keep them moving.*
|
||||
4
site/.dockerignore
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
public/
|
||||
resources/
|
||||
.hugo_build.lock
|
||||
.git/
|
||||
3
site/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
public/
|
||||
resources/
|
||||
.hugo_build.lock
|
||||
13
site/Dockerfile
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Multi-stage: build the static site with Hugo, serve it with nginx.
|
||||
# Build context is site/ only — legal pages are pre-generated (build-legal.sh)
|
||||
# and committed, and screenshots are copied in by collect_screenshots.sh, so no
|
||||
# other part of the repo is needed at image-build time.
|
||||
FROM hugomods/hugo:exts-0.140.2 AS build
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN hugo --minify --gc
|
||||
|
||||
FROM nginx:alpine
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=build /src/public /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
198
site/assets/css/main.css
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
:root {
|
||||
--green: #2f7d34;
|
||||
--green-dark: #22521e;
|
||||
--appbar: #3a8434;
|
||||
--canvas: #e7f1e0;
|
||||
--container: #d3e8c8;
|
||||
--on-container: #2f6d2a;
|
||||
--title: #1b2416;
|
||||
--muted: #5c6b52;
|
||||
--field: #f3f7ee;
|
||||
--outline: #c3cbb6;
|
||||
--white: #fff;
|
||||
--maxw: 1060px;
|
||||
--radius: 18px;
|
||||
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", sans-serif;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
html { scroll-behavior: smooth; }
|
||||
body {
|
||||
margin: 0;
|
||||
color: var(--title);
|
||||
background: var(--canvas);
|
||||
line-height: 1.55;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
img { max-width: 100%; display: block; }
|
||||
a { color: var(--green); }
|
||||
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
inset-inline-start: -999px;
|
||||
background: var(--green);
|
||||
color: #fff;
|
||||
padding: .6rem 1rem;
|
||||
border-radius: 0 0 8px 0;
|
||||
z-index: 10;
|
||||
}
|
||||
.skip-link:focus { inset-inline-start: 0; }
|
||||
|
||||
/* Header */
|
||||
.site-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: .4rem 1.2rem;
|
||||
padding: .7rem clamp(1rem, 4vw, 2rem);
|
||||
background: var(--appbar);
|
||||
color: #fff;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 5;
|
||||
}
|
||||
.brand {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .55rem;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
font-size: 1.25rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.brand img { border-radius: 8px; }
|
||||
.site-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: .5rem 1.1rem;
|
||||
}
|
||||
.site-nav a { color: #fff; text-decoration: none; opacity: .95; white-space: nowrap; }
|
||||
.site-nav a:hover { text-decoration: underline; }
|
||||
.lang-switch { display: inline-flex; gap: .6rem; font-size: .92rem; white-space: nowrap; }
|
||||
.lang-switch .current { opacity: .7; }
|
||||
.lang-switch a.lang { color: #fff; }
|
||||
|
||||
/* Narrow phones: brand on its own row, nav wraps beneath it, left-aligned. */
|
||||
@media (max-width: 560px) {
|
||||
.site-header { gap: .5rem; }
|
||||
.brand { font-size: 1.15rem; }
|
||||
.site-nav { width: 100%; gap: .4rem 1rem; font-size: .95rem; }
|
||||
}
|
||||
|
||||
main { max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1rem, 4vw, 2rem); }
|
||||
|
||||
/* Hero */
|
||||
.hero {
|
||||
display: grid;
|
||||
grid-template-columns: 1.1fr .9fr;
|
||||
gap: clamp(1.5rem, 4vw, 3rem);
|
||||
align-items: center;
|
||||
padding: clamp(2rem, 6vw, 4rem) 0 2rem;
|
||||
}
|
||||
.hero h1 {
|
||||
font-size: clamp(2rem, 5vw, 3.1rem);
|
||||
line-height: 1.1;
|
||||
margin: 0 0 .6rem;
|
||||
color: var(--green-dark);
|
||||
}
|
||||
.hero .tagline { font-size: 1.25rem; font-weight: 600; color: var(--on-container); margin: 0 0 1rem; }
|
||||
.hero .lead { font-size: 1.05rem; margin: 0 0 1rem; }
|
||||
.hero-shot { display: flex; justify-content: center; }
|
||||
|
||||
/* Phone frame */
|
||||
.phone {
|
||||
background: #12261a;
|
||||
padding: 8px;
|
||||
border-radius: 28px;
|
||||
box-shadow: 0 18px 40px rgba(20, 50, 25, .22);
|
||||
width: 232px;
|
||||
max-width: 62vw;
|
||||
}
|
||||
.phone img { border-radius: 20px; }
|
||||
|
||||
/* Sections */
|
||||
section { margin: 2.5rem 0; }
|
||||
h2 { font-size: clamp(1.4rem, 3vw, 1.9rem); color: var(--green-dark); }
|
||||
|
||||
.pillars {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 1.2rem;
|
||||
}
|
||||
.pillar {
|
||||
background: var(--white);
|
||||
border: 1px solid var(--outline);
|
||||
border-radius: var(--radius);
|
||||
padding: 1.4rem;
|
||||
}
|
||||
.pillar-icon { font-size: 1.8rem; }
|
||||
.pillar h2 { font-size: 1.2rem; margin: .5rem 0; }
|
||||
.pillar p { margin: 0; color: #2c3826; }
|
||||
|
||||
.shots .shot-row {
|
||||
display: flex;
|
||||
gap: 1.2rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.shots h2 { text-align: center; }
|
||||
|
||||
.values {
|
||||
background: var(--container);
|
||||
border-radius: var(--radius);
|
||||
padding: 1.6rem clamp(1.2rem, 4vw, 2.2rem);
|
||||
}
|
||||
.values ul { margin: .5rem 0 0; padding-inline-start: 1.2rem; }
|
||||
.values li { margin: .45rem 0; }
|
||||
|
||||
.get-it { text-align: center; }
|
||||
.store-badges { margin-top: 1.2rem; }
|
||||
.coming-soon { color: var(--muted); font-style: italic; }
|
||||
.badge {
|
||||
display: inline-block;
|
||||
background: var(--green);
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
padding: .7rem 1.4rem;
|
||||
border-radius: 999px;
|
||||
margin: .3rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Legal docs */
|
||||
.doc { padding: 2rem 0 3rem; max-width: 760px; }
|
||||
.doc h1 { color: var(--green-dark); }
|
||||
.doc-body h2 { font-size: 1.3rem; margin-top: 1.8rem; }
|
||||
.doc-body { font-size: 1.02rem; }
|
||||
.crumb { color: var(--muted); }
|
||||
.legal-index { list-style: none; padding: 0; }
|
||||
.legal-index li {
|
||||
padding: 1rem 1.2rem;
|
||||
background: var(--white);
|
||||
border: 1px solid var(--outline);
|
||||
border-radius: 12px;
|
||||
margin: .7rem 0;
|
||||
}
|
||||
.legal-index a { font-weight: 600; font-size: 1.1rem; text-decoration: none; }
|
||||
.legal-index .desc { display: block; color: var(--muted); font-size: .95rem; margin-top: .2rem; }
|
||||
|
||||
/* Footer */
|
||||
.site-footer {
|
||||
background: var(--green-dark);
|
||||
color: #dfeeda;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
.foot-inner { max-width: var(--maxw); margin: 0 auto; padding: 2rem clamp(1rem, 4vw, 2rem); }
|
||||
.foot-legal { display: flex; flex-wrap: wrap; gap: 1rem; margin-bottom: 1rem; }
|
||||
.foot-legal a { color: #fff; }
|
||||
.foot-note { margin: .3rem 0; font-size: .92rem; }
|
||||
.site-footer a { color: #cfe7c3; }
|
||||
|
||||
@media (max-width: 820px) {
|
||||
.hero { grid-template-columns: 1fr; }
|
||||
.hero-shot { order: -1; }
|
||||
.pillars { grid-template-columns: 1fr; }
|
||||
}
|
||||
BIN
site/assets/img/logo.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
site/assets/screenshots/de/calendar.png
Normal file
|
After Width: | Height: | Size: 146 KiB |
BIN
site/assets/screenshots/de/detail.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
site/assets/screenshots/de/home.png
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
site/assets/screenshots/de/inventory.png
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
site/assets/screenshots/de/market.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
site/assets/screenshots/en/calendar.png
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
site/assets/screenshots/en/detail.png
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
site/assets/screenshots/en/home.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
site/assets/screenshots/en/inventory.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
site/assets/screenshots/en/market.png
Normal file
|
After Width: | Height: | Size: 175 KiB |
BIN
site/assets/screenshots/es/calendar.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
site/assets/screenshots/es/detail.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
site/assets/screenshots/es/home.png
Normal file
|
After Width: | Height: | Size: 125 KiB |
BIN
site/assets/screenshots/es/inventory.png
Normal file
|
After Width: | Height: | Size: 165 KiB |
BIN
site/assets/screenshots/es/market.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
site/assets/screenshots/fr/calendar.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
site/assets/screenshots/fr/detail.png
Normal file
|
After Width: | Height: | Size: 181 KiB |
BIN
site/assets/screenshots/fr/home.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
site/assets/screenshots/fr/inventory.png
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
site/assets/screenshots/fr/market.png
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
site/assets/screenshots/ja/calendar.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
site/assets/screenshots/ja/detail.png
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
site/assets/screenshots/ja/home.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
site/assets/screenshots/ja/inventory.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
site/assets/screenshots/ja/market.png
Normal file
|
After Width: | Height: | Size: 175 KiB |
BIN
site/assets/screenshots/pt/calendar.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
site/assets/screenshots/pt/detail.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
site/assets/screenshots/pt/home.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
site/assets/screenshots/pt/inventory.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
site/assets/screenshots/pt/market.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
site/assets/screenshots/rtl/inventory.png
Normal file
|
After Width: | Height: | Size: 165 KiB |
71
site/build-legal.sh
Executable file
|
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/env bash
|
||||
# Generates the Hugo legal pages from docs/legal/ — the single source of truth.
|
||||
# Each doc's first "# Heading" becomes the page title (and is stripped from the
|
||||
# body so it isn't rendered twice). Run from site/ whenever the legal docs change:
|
||||
# ./build-legal.sh
|
||||
# The generated content/legal/<slug>.<lang>.md files are committed so the Docker
|
||||
# build only needs site/.
|
||||
set -euo pipefail
|
||||
|
||||
site_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
legal_src="$(cd "$site_dir/../docs/legal" && pwd)"
|
||||
out="$site_dir/content/legal"
|
||||
|
||||
# slug | English master | Spanish mirror | menu weight
|
||||
rows=(
|
||||
"privacy|privacy-policy.md|politica-de-privacidad.md|1"
|
||||
"terms|terms-of-use.md|condiciones-de-uso.md|2"
|
||||
"rules|community-rules.md|normas-de-la-comunidad.md|3"
|
||||
"seeds|seed-legality-notice.md|aviso-sobre-semillas.md|4"
|
||||
)
|
||||
|
||||
emit() { # <src-md> <out-md> <slug> <weight>
|
||||
local src="$1" dst="$2" slug="$3" weight="$4"
|
||||
# First "# ..." line -> title; everything after that line -> body. Strip a
|
||||
# leading "Tane — " so it doesn't collide with the site title suffix in <title>.
|
||||
local title
|
||||
title="$(sed -n 's/^# \(.*\)/\1/p' "$src" | head -n1 \
|
||||
| sed -E 's/^Tane[[:space:]]*(—|–|-)[[:space:]]*//')"
|
||||
{
|
||||
printf -- '---\n'
|
||||
printf 'title: "%s"\n' "${title//\"/\\\"}"
|
||||
printf 'slug: "%s"\n' "$slug"
|
||||
printf 'weight: %s\n' "$weight"
|
||||
printf 'translationKey: "legal-%s"\n' "$slug"
|
||||
printf -- '---\n\n'
|
||||
# Drop the first H1 line, keep the rest verbatim.
|
||||
awk 'NR==1 && /^# /{next} {print}' "$src"
|
||||
} > "$dst"
|
||||
echo " $(basename "$dst") <- $(basename "$src")"
|
||||
}
|
||||
|
||||
for row in "${rows[@]}"; do
|
||||
IFS='|' read -r slug en es weight <<<"$row"
|
||||
emit "$legal_src/$en" "$out/$slug.en.md" "$slug" "$weight"
|
||||
emit "$legal_src/es/$es" "$out/$slug.es.md" "$slug" "$weight"
|
||||
done
|
||||
|
||||
echo "Generated legal pages in $out"
|
||||
|
||||
# --- Plain-language "About" page, generated from the docs/ explainers ---------
|
||||
# Each page uses its own fixed title (not the doc's H1) and drops the first H1.
|
||||
docs_dir="$(cd "$site_dir/../docs" && pwd)"
|
||||
emit_about() { # <src-md> <out-md> <title> <description>
|
||||
local src="$1" dst="$2" title="$3" desc="$4"
|
||||
[[ -f "$src" ]] || return 0
|
||||
{
|
||||
printf -- '---\n'
|
||||
printf 'title: "%s"\n' "$title"
|
||||
printf 'slug: "about"\n'
|
||||
printf 'translationKey: "about"\n'
|
||||
printf 'description: "%s"\n' "$desc"
|
||||
printf -- '---\n\n'
|
||||
awk 'NR==1 && /^# /{next} {print}' "$src"
|
||||
} > "$dst"
|
||||
echo "Generated $(basename "$dst") <- $(basename "$src")"
|
||||
}
|
||||
|
||||
emit_about "$docs_dir/que-es-tane.md" "$site_dir/content/about.es.md" \
|
||||
"Qué es Tane" "Tane explicada para todos los públicos."
|
||||
emit_about "$docs_dir/what-is-tane.md" "$site_dir/content/about.en.md" \
|
||||
"What is Tane" "Tane explained for everyone."
|
||||
36
site/config.toml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
baseURL = "https://tane.comunes.org/"
|
||||
title = "Tane"
|
||||
defaultContentLanguage = "en"
|
||||
defaultContentLanguageInSubdir = false
|
||||
enableRobotsTXT = true
|
||||
enableGitInfo = false
|
||||
|
||||
# Static, no-JS marketing site. Kept intentionally light: one page + a small
|
||||
# legal section, English/Spanish. Screenshots come from the app's golden
|
||||
# harness (apps/app_seeds/test/screenshots), copied in by collect_screenshots.sh.
|
||||
|
||||
[params]
|
||||
email = "info@comunes.org"
|
||||
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 = ""
|
||||
|
||||
[languages]
|
||||
[languages.en]
|
||||
languageName = "English"
|
||||
languageCode = "en"
|
||||
weight = 1
|
||||
[languages.es]
|
||||
languageName = "Español"
|
||||
languageCode = "es"
|
||||
weight = 2
|
||||
|
||||
[markup.goldmark.renderer]
|
||||
unsafe = false
|
||||
|
||||
[minify]
|
||||
disableJSON = true
|
||||
34
site/content/_index.en.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
title: "Your seed bank in your pocket"
|
||||
description: "A local-first, decentralized app for keeping and sharing traditional seeds. Offline, encrypted, no account."
|
||||
hero:
|
||||
title: "Your seed bank in your pocket"
|
||||
tagline: "Keep and share traditional seeds — offline, encrypted, no account."
|
||||
lead: >
|
||||
Every traditional seed is a letter written by thousands of generations,
|
||||
passed from hand to hand. Tane helps people and seed-saver collectives keep
|
||||
a friendly inventory of their bank, decide what they offer, and share it
|
||||
locally — without a central intermediary that could control it, censor it,
|
||||
or be fined for it.
|
||||
pillars:
|
||||
- icon: "🌱"
|
||||
title: "Manage your bank"
|
||||
body: "Add a seed with just a photo and a name — no Latin required. Note the year, how much you have, where it came from, germination tests. Search, filter, snap now and name later."
|
||||
- icon: "🔒"
|
||||
title: "Yours, and only yours"
|
||||
body: "Works fully offline. No account, no server, no trackers. Everything is encrypted on your device. Keep an encrypted backup and a printed recovery sheet to restore your whole bank on a new device."
|
||||
- icon: "🤝"
|
||||
title: "Share, as it's always been done"
|
||||
body: "Mark what you have spare to give away, swap or sell. Someone nearby finds it and contacts you — no middleman. Print a catalog of what you share to take to a seed fair."
|
||||
values:
|
||||
title: "Why Tane is different"
|
||||
points:
|
||||
- "No center: no company can shut it down, censor it, or be fined for it."
|
||||
- "Anti-monopoly by design — sharing seeds multiplies the commons instead of depleting it."
|
||||
- "Spreads like a seed, person to person, with no server in the middle."
|
||||
- "Free software (AGPL-3.0). No ads, no commissions, no business model."
|
||||
---
|
||||
|
||||
Tane (種, "seed"; from *tanemaki* 種まき, "to sow seeds") is a local-first,
|
||||
decentralized app for keeping and sharing traditional seeds. It works with zero
|
||||
network — and connects you to a neighborly seed-sharing network when you want it.
|
||||
35
site/content/_index.es.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
title: "Tu banco de semillas en el bolsillo"
|
||||
description: "Una app local-first y descentralizada para guardar y compartir semillas tradicionales. Sin conexión, cifrada, sin cuenta."
|
||||
hero:
|
||||
title: "Tu banco de semillas en el bolsillo"
|
||||
tagline: "Guarda y comparte semillas tradicionales: sin conexión, cifrado, sin cuenta."
|
||||
lead: >
|
||||
Cada semilla tradicional es una carta escrita por miles de generaciones, que
|
||||
pasa de mano en mano. Tane ayuda a personas y colectivos de guardianas de
|
||||
semillas a llevar un inventario amable de su banco, decidir qué ofrecen y
|
||||
compartirlo localmente, sin un intermediario central que pueda controlarlo,
|
||||
censurarlo o ser multado por ello.
|
||||
pillars:
|
||||
- icon: "🌱"
|
||||
title: "Gestiona tu banco"
|
||||
body: "Añade una semilla con solo una foto y un nombre; sin latín. Anota el año, cuánta tienes, de dónde viene, pruebas de germinación. Busca, filtra, haz la foto ahora y ponle nombre después."
|
||||
- icon: "🔒"
|
||||
title: "Tuyo, y solo tuyo"
|
||||
body: "Funciona totalmente sin conexión. Sin cuenta, sin servidor, sin rastreadores. Todo va cifrado en tu dispositivo. Guarda una copia cifrada y una hoja de recuperación impresa para restaurar todo tu banco en un dispositivo nuevo."
|
||||
- icon: "🤝"
|
||||
title: "Compartir, como se ha hecho siempre"
|
||||
body: "Marca lo que te sobra para regalar, intercambiar o vender. Alguien cerca lo encuentra y te contacta, sin intermediarios. Imprime un catálogo de lo que compartes para llevar a una feria de semillas."
|
||||
values:
|
||||
title: "Por qué Tane es diferente"
|
||||
points:
|
||||
- "Sin centro: ninguna empresa puede apagarlo, censurarlo ni ser multada por ello."
|
||||
- "Anti-monopolio por diseño: compartir semillas multiplica el común en lugar de agotarlo."
|
||||
- "Se propaga como una semilla, de persona a persona, sin servidor en medio."
|
||||
- "Software libre (AGPL-3.0). Sin anuncios, sin comisiones, sin modelo de negocio."
|
||||
---
|
||||
|
||||
Tane (種, "semilla"; de *tanemaki* 種まき, "sembrar semillas") es una app
|
||||
local-first y descentralizada para guardar y compartir semillas tradicionales.
|
||||
Funciona sin ninguna red, y te conecta a una red vecinal de intercambio de
|
||||
semillas cuando tú quieras.
|
||||
78
site/content/about.en.md
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
title: "What is Tane"
|
||||
slug: "about"
|
||||
translationKey: "about"
|
||||
description: "Tane explained for everyone."
|
||||
---
|
||||
|
||||
|
||||
**Tane** (種) means "seed" in Japanese; the full name, *tanemaki* (種まき), means "to sow / scatter seeds".
|
||||
|
||||
## In one sentence
|
||||
|
||||
A simple, free app to **keep your seeds and share them** with whoever you like. It works
|
||||
**without internet** and with no company in the middle.
|
||||
|
||||
## Why it's needed
|
||||
|
||||
Today a handful of companies control much of the world's seed. Many seeds are made so they
|
||||
won't serve again: they give one harvest, but their seeds don't germinate well, so you have
|
||||
to **buy them again every year**. Meanwhile the traditional varieties — grown and improved
|
||||
over thousands of years — are being lost, and with them the knowledge of how to grow them.
|
||||
|
||||
Sharing seeds is one of the oldest and most natural things there is, yet in some places it
|
||||
has become complicated or even fined (in France an association was penalised for handing out
|
||||
varieties that weren't on the official approved list). And the people who care for seeds
|
||||
still do it with notebooks and spreadsheets.
|
||||
|
||||
## What it does, made easy
|
||||
|
||||
- **Keep** — your seed inventory: what you have, from which year, how much, where it came
|
||||
from, under **the name you use** (no Latin required). The same whether you have four
|
||||
packets in a drawer or a group with hundreds of varieties.
|
||||
- **Share** — you say what you offer; someone nearby sees it and writes to you, to **give
|
||||
away, swap or sell** if you want. You close the deal yourself, directly. No company steps
|
||||
in or takes a commission.
|
||||
|
||||
## Why it's different
|
||||
|
||||
- **It's free and belongs to everyone.** It isn't owned by any company: anyone can use,
|
||||
copy, translate or improve it, free and forever. It's more a *recipe that gets shared*
|
||||
than a closed product — this is called **free software**. And whoever improves it is
|
||||
bound to share those improvements just as freely, so no one can "close" it later (that's
|
||||
**copyleft**).
|
||||
- **It works offline.** The basics run even out in the field with no signal.
|
||||
- **Your data is yours.** Your information is kept on **your own phone**, protected with a
|
||||
key, not on some company's computers. We don't sell it or upload it anywhere. No ads.
|
||||
- **No one can shut it down or control it.** There's no central computer that everything
|
||||
passes through: people communicate **directly with each other**, like passing seeds from
|
||||
hand to hand. So no one can censor it or charge you to use it (that's what being
|
||||
**decentralized** means).
|
||||
- **You trust by word of mouth.** You deal with people you know and with those vouched for
|
||||
by people you trust — the way it's always worked in a village or at a fair — without
|
||||
having to give your real name or phone number unless you want to.
|
||||
- **In many languages.** For anywhere in the world, not for a single country. Volunteers
|
||||
translate it.
|
||||
|
||||
## Who it's for
|
||||
|
||||
Seed groups and networks, gardens and collectives, growers… and anyone with a few packets
|
||||
put away. For all ages, from 10 to 80.
|
||||
|
||||
## The name
|
||||
|
||||
**Tane** means "seed" (種). It comes from *tanemaki* (種まき), "to sow seeds" in Japanese, a
|
||||
nod to old customs of mutual aid between neighbours (sharing the work, saving together).
|
||||
|
||||
## Where it stands and how to help
|
||||
|
||||
In its early days. You can help by trying it out in a real seed group, translating it,
|
||||
sharing what you know about the varieties, or coding. It has no price and never will: it's
|
||||
sustained by volunteers, by the communities themselves, and by public funding for projects
|
||||
of common interest.
|
||||
|
||||
---
|
||||
|
||||
> *The idea underneath: traditional seeds are a heritage of humankind — everyone's and no
|
||||
> one's. Against those who would privatise them, Tane aims to make it easy for you to keep
|
||||
> them, multiply them and keep them moving.*
|
||||
81
site/content/about.es.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
---
|
||||
title: "Qué es Tane"
|
||||
slug: "about"
|
||||
translationKey: "about"
|
||||
description: "Tane explicada para todos los públicos."
|
||||
---
|
||||
|
||||
|
||||
**Tane** (種) es «semilla» en japonés; el nombre completo, *tanemaki* (種まき), es «sembrar / esparcir semillas».
|
||||
|
||||
## En una frase
|
||||
|
||||
Una app sencilla y gratuita para **guardar tus semillas y compartirlas** con quien
|
||||
quieras. Funciona **sin internet** y sin ninguna empresa de por medio.
|
||||
|
||||
## Por qué hace falta
|
||||
|
||||
Hoy unas pocas empresas controlan gran parte de las semillas del mundo. Muchas están
|
||||
hechas para no volver a servir: dan una cosecha, pero sus semillas no germinan bien, así
|
||||
que hay que **comprarlas otra vez cada año**. Mientras tanto, las variedades de toda la
|
||||
vida —cultivadas y mejoradas durante miles de años— se están perdiendo, y con ellas el
|
||||
saber cómo cultivarlas.
|
||||
|
||||
Compartir semillas es de lo más viejo y natural que hay, pero en algunos sitios se ha
|
||||
vuelto complicado o hasta se multa (en Francia sancionaron a una asociación por repartir
|
||||
variedades que no estaban en la lista oficial permitida). Y quien las cuida lo hace hoy
|
||||
con libretas y hojas de cálculo.
|
||||
|
||||
## Qué hace, y fácil
|
||||
|
||||
- **Guardar** — tu inventario de semillas: qué tienes, de qué año, cuánta, de dónde vino,
|
||||
con **el nombre que tú usas** (no hace falta saber latín). Igual para quien tiene cuatro
|
||||
sobres en un cajón que para un grupo con cientos de variedades.
|
||||
- **Compartir** — dices qué ofreces; alguien cerca lo ve y te escribe, para **regalar,
|
||||
intercambiar o vender** si quieres. El trato lo cierras tú, directamente. Ninguna empresa
|
||||
se mete ni se lleva comisión.
|
||||
|
||||
## Por qué es distinta
|
||||
|
||||
- **Es libre y de todos.** No es de ninguna empresa: cualquiera puede usarla, copiarla,
|
||||
traducirla o mejorarla, gratis y para siempre. Es más una *receta que se comparte* que un
|
||||
producto cerrado — a esto se le llama **software libre**. Y quien la mejore está obligado
|
||||
a compartir esas mejoras igual de libres, para que nadie pueda «cerrarla» después (eso es
|
||||
el **copyleft**).
|
||||
- **Funciona sin internet.** Lo básico va aunque estés en el campo sin cobertura.
|
||||
- **Tus datos son tuyos.** Tu información se guarda en **tu propio móvil**, protegida con una
|
||||
clave, no en los ordenadores de una empresa. No la vendemos ni la subimos a ningún sitio.
|
||||
Sin publicidad.
|
||||
- **Nadie la puede apagar ni controlar.** No hay un ordenador central por el que pase todo:
|
||||
las personas se comunican **directamente entre sí**, como quien se pasa unas semillas de
|
||||
mano en mano. Por eso nadie puede censurarla ni cobrarte por usarla (eso es que sea
|
||||
**descentralizada**).
|
||||
- **Te fías por el boca a boca.** Te relacionas con gente que conoces y con quien te
|
||||
recomienda gente de confianza —como siempre se ha hecho en un pueblo o en una feria— sin
|
||||
tener que dar tu nombre real ni tu teléfono si no quieres.
|
||||
- **En muchos idiomas.** Para cualquier lugar del mundo, no para un solo país. La traduce
|
||||
gente voluntaria.
|
||||
|
||||
## Para quién
|
||||
|
||||
Grupos y redes de semillas, huertos y colectivos, agricultores y agricultoras… y cualquier
|
||||
persona con unos sobres guardados. Para todas las edades, de 10 a 80.
|
||||
|
||||
## El nombre
|
||||
|
||||
**Tane** quiere decir «semilla» (種). Viene de *tanemaki* (種まき), «sembrar semillas» en
|
||||
japonés, un guiño a viejas costumbres de ayuda mutua entre vecinos (compartir el trabajo,
|
||||
ahorrar juntos).
|
||||
|
||||
## En qué punto está y cómo ayudar
|
||||
|
||||
En sus primeros pasos. Se puede ayudar probándola en un grupo de semillas de verdad,
|
||||
traduciéndola, aportando lo que sabes de las variedades, o programando. No tiene ni tendrá
|
||||
precio: se sostiene con gente voluntaria, con las propias comunidades y con ayudas públicas
|
||||
a proyectos de interés común.
|
||||
|
||||
---
|
||||
|
||||
> *Idea de fondo: las semillas de toda la vida son un patrimonio de la humanidad —de todos
|
||||
> y de nadie—. Frente a quien quiere privatizarlas, Tane busca ponértelo fácil para
|
||||
> guardarlas, multiplicarlas y hacerlas circular.*
|
||||
4
site/content/legal/_index.en.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: "Legal"
|
||||
description: "Tane's privacy policy, terms of use, community rules and seed-legality notice."
|
||||
---
|
||||
4
site/content/legal/_index.es.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: "Legal"
|
||||
description: "Política de privacidad, condiciones de uso, normas de la comunidad y aviso sobre semillas de Tane."
|
||||
---
|
||||
96
site/content/legal/privacy.en.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
---
|
||||
title: "Privacy Policy"
|
||||
slug: "privacy"
|
||||
weight: 1
|
||||
translationKey: "legal-privacy"
|
||||
---
|
||||
|
||||
|
||||
**Version 1.0 — 13 July 2026**
|
||||
|
||||
Tane is published by **Asociación Comunes** (Spain) — <https://comunes.org> —
|
||||
contact: <info@comunes.org>. Tane is free software (AGPL-3.0); its source code is
|
||||
public, so everything described here can be verified.
|
||||
|
||||
## The short version
|
||||
|
||||
- Tane works **without an account**. We don't know who you are.
|
||||
- Everything you record stays **on your device, encrypted**. We run no servers that
|
||||
receive it, and we have no way to read it.
|
||||
- Nothing leaves your device unless **you** choose to share it (an offer, a message,
|
||||
your profile). What you share travels through community-run servers we don't control.
|
||||
- **No analytics, no ads, no trackers.** Tane collects nothing about you.
|
||||
|
||||
## 1. No accounts, no collection by us
|
||||
|
||||
Tane does not ask for your name, email, or phone number. There is no registration and
|
||||
no central Tane server. Your identity in the app is a cryptographic key created on your
|
||||
device and stored in your device's secure keystore. Asociación Comunes does not collect,
|
||||
receive, or process your personal data through the app.
|
||||
|
||||
## 2. Data stored on your device
|
||||
|
||||
Your seed inventory (varieties, quantities, notes, photos), your messages, your
|
||||
contacts' vouches and ratings, and your keys are stored **only on your device**, in an
|
||||
encrypted database (SQLCipher). The encryption key lives in your device's system
|
||||
keystore. Backups you create are also encrypted; you choose where to keep them, and
|
||||
they never pass through us.
|
||||
|
||||
## 3. Data that leaves your device — only when you choose
|
||||
|
||||
Nothing is published automatically. Each of these happens only by your explicit action:
|
||||
|
||||
- **Offers.** When you offer seeds, the app publishes the offer's title, description,
|
||||
optional photo, optional price, and an **approximate area** (a zone of roughly 2–80 km,
|
||||
as you configure it — never your address or precise location). Offers are public.
|
||||
- **Profile.** If you fill it in, your chosen name, bio, and avatar are public.
|
||||
- **Messages.** Direct messages are **end-to-end encrypted**: only you and the person
|
||||
you write to can read them. The servers that carry them see only encrypted envelopes.
|
||||
- **Vouches and ratings.** If you vouch for or rate someone, that statement is public
|
||||
and signed by your key.
|
||||
- **Sync between your devices.** If you link a second device, your data travels between
|
||||
them encrypted so that only your devices can read it.
|
||||
|
||||
## 4. Where shared data goes: community relays
|
||||
|
||||
Tane's social features use open, community-run servers ("relays"). By default the app
|
||||
uses a small set that includes `relay.comunes.org` (operated by Asociación Comunes) and
|
||||
well-known public relays; you can change this list, or empty it to turn the network off
|
||||
entirely. Relays other than `relay.comunes.org` are **third-party infrastructure**:
|
||||
their operators decide their own retention and policies, and this policy does not cover
|
||||
them.
|
||||
|
||||
## 5. Deletion — an honest note
|
||||
|
||||
You can delete anything local instantly, and you can withdraw an offer at any time.
|
||||
When you withdraw or delete something you had published, the app asks the relays to
|
||||
delete it too. Relays we don't operate may keep copies despite that request, and public
|
||||
posts may have been copied elsewhere while they were visible. **Treat anything you
|
||||
publish as potentially permanent.** On `relay.comunes.org` we honour deletion requests.
|
||||
|
||||
## 6. Device permissions
|
||||
|
||||
- **Photos / camera** — only when you attach a picture to a variety, offer, or profile.
|
||||
- **Approximate location** (optional) — only if you use "set my area from where I am",
|
||||
to pick your coarse sharing zone. Tane never requests precise location.
|
||||
- **Notifications** (optional) — to tell you about new messages.
|
||||
|
||||
## 7. Your rights
|
||||
|
||||
Because your data lives on your device under your control, you exercise most rights
|
||||
yourself: read, correct, export, or delete everything from within the app. For data on
|
||||
`relay.comunes.org`, or any question about this policy, write to <info@comunes.org>.
|
||||
If you are in the EU, you also have the right to complain to your data protection
|
||||
authority (in Spain, the AEPD).
|
||||
|
||||
## 8. Children
|
||||
|
||||
The seed inventory can be used by anyone. The market and messaging features are not
|
||||
directed at children; by using them you confirm you are old enough to use social
|
||||
features under the laws of your country.
|
||||
|
||||
## 9. Changes
|
||||
|
||||
We will update this policy if Tane's behaviour changes, and note the changes in the
|
||||
app's release notes. The current version always lives at
|
||||
<https://tane.comunes.org/legal/privacy>, with history in the public repository.
|
||||
102
site/content/legal/privacy.es.md
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
title: "Política de privacidad"
|
||||
slug: "privacy"
|
||||
weight: 1
|
||||
translationKey: "legal-privacy"
|
||||
---
|
||||
|
||||
|
||||
**Versión 1.0 — 13 de julio de 2026**
|
||||
|
||||
Tane está publicada por la **Asociación Comunes** (España) — <https://comunes.org> —
|
||||
contacto: <info@comunes.org>. Tane es software libre (AGPL-3.0); su código fuente es
|
||||
público, así que todo lo que se describe aquí puede verificarse.
|
||||
|
||||
## La versión corta
|
||||
|
||||
- Tane funciona **sin cuenta**. No sabemos quién eres.
|
||||
- Todo lo que registras se queda **en tu dispositivo, cifrado**. No tenemos servidores
|
||||
que lo reciban ni forma de leerlo.
|
||||
- Nada sale de tu dispositivo salvo que **tú** decidas compartirlo (una oferta, un
|
||||
mensaje, tu perfil). Lo que compartes viaja por servidores comunitarios que no
|
||||
controlamos.
|
||||
- **Sin analíticas, sin publicidad, sin rastreadores.** Tane no recoge nada sobre ti.
|
||||
|
||||
## 1. Sin cuentas, sin recogida por nuestra parte
|
||||
|
||||
Tane no pide tu nombre, correo ni teléfono. No hay registro ni servidor central de
|
||||
Tane. Tu identidad en la aplicación es una clave criptográfica creada en tu dispositivo
|
||||
y guardada en el almacén seguro del sistema. La Asociación Comunes no recoge, recibe ni
|
||||
trata tus datos personales a través de la aplicación.
|
||||
|
||||
## 2. Datos guardados en tu dispositivo
|
||||
|
||||
Tu inventario de semillas (variedades, cantidades, notas, fotos), tus mensajes, los
|
||||
avales y valoraciones de tus contactos y tus claves se guardan **solo en tu
|
||||
dispositivo**, en una base de datos cifrada (SQLCipher). La clave de cifrado vive en el
|
||||
almacén seguro del sistema. Las copias de seguridad que crees también van cifradas; tú
|
||||
eliges dónde guardarlas y nunca pasan por nosotros.
|
||||
|
||||
## 3. Datos que salen de tu dispositivo — solo cuando tú quieres
|
||||
|
||||
Nada se publica automáticamente. Cada una de estas cosas ocurre solo por tu acción
|
||||
explícita:
|
||||
|
||||
- **Ofertas.** Cuando ofreces semillas, la aplicación publica el título, la
|
||||
descripción, una foto opcional, un precio opcional y una **zona aproximada** (un área
|
||||
de entre 2 y 80 km, según la configures — nunca tu dirección ni tu ubicación
|
||||
precisa). Las ofertas son públicas.
|
||||
- **Perfil.** Si lo rellenas, el nombre que elijas, tu biografía y tu avatar son
|
||||
públicos.
|
||||
- **Mensajes.** Los mensajes directos van **cifrados de extremo a extremo**: solo tú y
|
||||
la persona a la que escribes podéis leerlos. Los servidores que los transportan solo
|
||||
ven sobres cifrados.
|
||||
- **Avales y valoraciones.** Si avalas o valoras a alguien, esa declaración es pública
|
||||
y va firmada con tu clave.
|
||||
- **Sincronización entre tus dispositivos.** Si enlazas un segundo dispositivo, tus
|
||||
datos viajan entre ellos cifrados de forma que solo tus dispositivos pueden leerlos.
|
||||
|
||||
## 4. A dónde van los datos compartidos: servidores comunitarios
|
||||
|
||||
Las funciones sociales de Tane usan servidores abiertos gestionados por comunidades
|
||||
("relés"). Por defecto la aplicación usa un pequeño conjunto que incluye
|
||||
`relay.comunes.org` (operado por la Asociación Comunes) y relés públicos conocidos;
|
||||
puedes cambiar esa lista, o vaciarla para desconectar la red por completo. Los relés
|
||||
distintos de `relay.comunes.org` son **infraestructura de terceros**: sus operadores
|
||||
deciden su propia retención y sus políticas, y esta política no los cubre.
|
||||
|
||||
## 5. Borrado — una nota honesta
|
||||
|
||||
Puedes borrar al instante todo lo local, y puedes retirar una oferta en cualquier
|
||||
momento. Cuando retiras o borras algo que habías publicado, la aplicación pide a los
|
||||
relés que también lo borren. Los relés que no operamos pueden conservar copias pese a
|
||||
esa petición, y lo publicado pudo copiarse a otros sitios mientras fue visible.
|
||||
**Trata todo lo que publiques como potencialmente permanente.** En `relay.comunes.org`
|
||||
atendemos las peticiones de borrado.
|
||||
|
||||
## 6. Permisos del dispositivo
|
||||
|
||||
- **Fotos / cámara** — solo cuando adjuntas una imagen a una variedad, oferta o perfil.
|
||||
- **Ubicación aproximada** (opcional) — solo si usas "fijar mi zona desde donde estoy",
|
||||
para elegir tu zona amplia de intercambio. Tane nunca pide la ubicación precisa.
|
||||
- **Notificaciones** (opcional) — para avisarte de mensajes nuevos.
|
||||
|
||||
## 7. Tus derechos
|
||||
|
||||
Como tus datos viven en tu dispositivo y bajo tu control, la mayoría de derechos los
|
||||
ejerces tú directamente: consultar, corregir, exportar o borrar todo desde la propia
|
||||
aplicación. Para los datos en `relay.comunes.org`, o cualquier duda sobre esta
|
||||
política, escribe a <info@comunes.org>. Si estás en la UE, también tienes derecho a
|
||||
reclamar ante tu autoridad de protección de datos (en España, la AEPD).
|
||||
|
||||
## 8. Menores
|
||||
|
||||
El inventario de semillas puede usarlo cualquiera. El mercado y la mensajería no están
|
||||
dirigidos a menores; al usarlos confirmas que tienes edad suficiente para usar
|
||||
funciones sociales según las leyes de tu país.
|
||||
|
||||
## 9. Cambios
|
||||
|
||||
Actualizaremos esta política si cambia el comportamiento de Tane, y lo señalaremos en
|
||||
las notas de cada versión. La versión vigente está siempre en
|
||||
<https://tane.comunes.org/legal/privacy>, con su historial en el repositorio público.
|
||||
47
site/content/legal/rules.en.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
title: "Community Rules"
|
||||
slug: "rules"
|
||||
weight: 3
|
||||
translationKey: "legal-rules"
|
||||
---
|
||||
|
||||
|
||||
**Version 1.0 — 13 July 2026**
|
||||
|
||||
The market and messages in Tane are shared spaces built on trust between neighbours.
|
||||
These rules are what everyone accepts before joining. They also define what counts as
|
||||
content that can be reported and removed from the servers we operate.
|
||||
|
||||
## The rules
|
||||
|
||||
1. **Be honest about your seeds.** Describe what you actually have: the variety as you
|
||||
know it, the harvest year, anything relevant about how it was grown. Don't invent
|
||||
provenance.
|
||||
2. **Share only what you may share.** Don't offer:
|
||||
- seed of **commercially protected varieties** (plant variety rights, patents)
|
||||
unless you are authorized;
|
||||
- **invasive or protected species** where their exchange is prohibited;
|
||||
- anything else that is illegal to share or sell where you or the recipient live.
|
||||
3. **Seeds, not anything else.** The market is for seeds and plant reproductive
|
||||
material in the spirit of the app. It is not a general classifieds board.
|
||||
4. **Respect people.** No harassment, threats, hate, or discrimination — in offers,
|
||||
profiles, ratings, or messages.
|
||||
5. **No spam or scams.** No repeated postings, misleading offers, phishing, or
|
||||
pressure to move people onto shady deals.
|
||||
6. **Honest reputation.** Vouch only for people you have actually met or exchanged
|
||||
with; rate only real experiences. Don't game the trust system.
|
||||
|
||||
## What happens if someone breaks them
|
||||
|
||||
- Anyone can **block** you — your offers and messages disappear for them.
|
||||
- Anyone can **report** an offer or a person. Reports travel to the servers that carry
|
||||
the content; on the relay operated by Comunes (`relay.comunes.org`), content and keys
|
||||
that break these rules are removed. Other servers apply their own policies.
|
||||
- There are no appeals or account suspensions because there are no accounts: the
|
||||
network simply stops carrying and showing what breaks the rules.
|
||||
|
||||
## A note on good faith
|
||||
|
||||
Most seed sharing is between amateurs, in small quantities, for the joy of keeping
|
||||
varieties alive. When in doubt, prefer **gifting and swapping** over selling, label
|
||||
things clearly, and ask. That's how it's always been done.
|
||||
54
site/content/legal/rules.es.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
title: "Normas de la comunidad"
|
||||
slug: "rules"
|
||||
weight: 3
|
||||
translationKey: "legal-rules"
|
||||
---
|
||||
|
||||
|
||||
**Versión 1.0 — 13 de julio de 2026**
|
||||
|
||||
El mercado y los mensajes de Tane son espacios compartidos construidos sobre la
|
||||
confianza entre vecinas y vecinos. Estas normas son lo que todo el mundo acepta antes
|
||||
de entrar. También definen qué contenido puede denunciarse y eliminarse de los
|
||||
servidores que operamos.
|
||||
|
||||
## Las normas
|
||||
|
||||
1. **Sé honesto con tus semillas.** Describe lo que realmente tienes: la variedad tal
|
||||
y como la conoces, el año de cosecha, lo relevante sobre cómo se cultivó. No
|
||||
inventes procedencias.
|
||||
2. **Comparte solo lo que puedas compartir.** No ofrezcas:
|
||||
- semilla de **variedades protegidas comercialmente** (obtenciones vegetales,
|
||||
patentes) salvo que tengas autorización;
|
||||
- **especies invasoras o protegidas** allí donde su intercambio esté prohibido;
|
||||
- cualquier otra cosa que sea ilegal compartir o vender donde vives tú o donde vive
|
||||
quien la recibe.
|
||||
3. **Semillas, no cualquier cosa.** El mercado es para semillas y material de
|
||||
reproducción vegetal, en el espíritu de la aplicación. No es un tablón de anuncios
|
||||
general.
|
||||
4. **Respeta a las personas.** Nada de acoso, amenazas, odio o discriminación — ni en
|
||||
ofertas, ni en perfiles, ni en valoraciones, ni en mensajes.
|
||||
5. **Sin spam ni engaños.** Nada de publicaciones repetidas, ofertas engañosas,
|
||||
phishing o presiones para llevar a la gente a tratos turbios.
|
||||
6. **Reputación honesta.** Avala solo a personas que conozcas de verdad o con las que
|
||||
hayas intercambiado; valora solo experiencias reales. No hagas trampas al sistema de
|
||||
confianza.
|
||||
|
||||
## Qué pasa si alguien las incumple
|
||||
|
||||
- Cualquiera puede **bloquearte** — tus ofertas y mensajes desaparecen para esa
|
||||
persona.
|
||||
- Cualquiera puede **denunciar** una oferta o a una persona. Las denuncias llegan a los
|
||||
servidores que transportan el contenido; en el relé operado por Comunes
|
||||
(`relay.comunes.org`), el contenido y las claves que incumplen estas normas se
|
||||
eliminan. Otros servidores aplican sus propias políticas.
|
||||
- No hay apelaciones ni suspensiones de cuenta porque no hay cuentas: sencillamente, la
|
||||
red deja de transportar y de mostrar lo que incumple las normas.
|
||||
|
||||
## Una nota sobre la buena fe
|
||||
|
||||
La mayor parte del intercambio de semillas ocurre entre aficionados, en pequeñas
|
||||
cantidades, por el gusto de mantener vivas las variedades. Ante la duda, prefiere
|
||||
**regalar e intercambiar** antes que vender, etiqueta las cosas con claridad y
|
||||
pregunta. Así se ha hecho siempre.
|
||||
66
site/content/legal/seeds.en.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
title: "Notice on the Legality of Exchanging Seeds"
|
||||
slug: "seeds"
|
||||
weight: 4
|
||||
translationKey: "legal-seeds"
|
||||
---
|
||||
|
||||
|
||||
**Version 1.0 — 13 July 2026**
|
||||
|
||||
Tane helps people keep and share traditional seeds. Laws about seeds differ a lot
|
||||
between countries, and they distinguish sharply between **giving or swapping** seeds
|
||||
and **selling** them. This notice is general information, not legal advice; you are
|
||||
responsible for following the law where you live and where your seeds are going.
|
||||
|
||||
## Gifting and swapping between amateurs
|
||||
|
||||
Exchanging seeds **without commercial purpose** — gifts, swaps, seed libraries,
|
||||
conservation networks — is broadly recognized and lawful in most places:
|
||||
|
||||
- **European Union.** EU seed marketing law regulates *commercial marketing* of seed.
|
||||
Exchange in kind between individuals, and the work of conservation networks and gene
|
||||
banks, fall outside or are expressly exempted; the plant-reproductive-material reform
|
||||
underway (proposal COM(2023) 414) keeps exemptions for amateurs and conservation
|
||||
networks, provided the activity is not commercial.
|
||||
- **Spain.** Ley 30/2006 regulates the *commercial* seed trade; non-commercial exchange
|
||||
between amateurs and conservation-oriented exchange are recognized practice (art. 24).
|
||||
- **United States.** Following the 2016 amendment to the Recommended Uniform State Seed
|
||||
Law, most states exempt **non-commercial seed sharing** (seed libraries, swaps) from
|
||||
commercial labeling and testing requirements.
|
||||
|
||||
## Selling seeds
|
||||
|
||||
Selling is different. In the EU and many other jurisdictions, **marketing seed of
|
||||
varieties not registered in an official catalogue may be restricted or prohibited**,
|
||||
and quantities, labeling, or species may be regulated even for small sellers.
|
||||
Exemptions for conservation varieties and amateur quantities exist but vary. If you
|
||||
use Tane's option to ask a price, **check your national rules first** — the app cannot
|
||||
do this for you.
|
||||
|
||||
## Protected varieties
|
||||
|
||||
Varieties covered by **plant variety rights (PVR/PBR) or patents** may not be
|
||||
propagated or sold without the holder's authorization — this can apply even to seed
|
||||
you bought legally. Traditional and heirloom varieties are generally not protected,
|
||||
but modern commercial varieties usually are. When in doubt, don't offer it.
|
||||
|
||||
## Sending seeds across borders
|
||||
|
||||
Most countries restrict importing seeds: **phytosanitary certificates**, prohibited
|
||||
species lists, and quarantine rules commonly apply — even to small envelopes between
|
||||
individuals, and also **within** the EU for certain species (plant passport rules).
|
||||
Before mailing seeds to another country, check the rules of the destination country.
|
||||
The safest exchanges are local ones — which is what Tane is designed for.
|
||||
|
||||
## Invasive and protected species
|
||||
|
||||
Some species may not be exchanged at all in some regions, either because they are
|
||||
**invasive** there or because they are **protected**. Lists are regional; check yours.
|
||||
|
||||
---
|
||||
|
||||
*Tane takes no commission, mediates no transaction, and verifies no offer: exchanges
|
||||
are private dealings between the people involved (see the
|
||||
[Terms of use](terms-of-use.md)). This notice exists so those dealings are informed
|
||||
ones.*
|
||||
72
site/content/legal/seeds.es.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
title: "Aviso sobre la legalidad del intercambio de semillas"
|
||||
slug: "seeds"
|
||||
weight: 4
|
||||
translationKey: "legal-seeds"
|
||||
---
|
||||
|
||||
|
||||
**Versión 1.0 — 13 de julio de 2026**
|
||||
|
||||
Tane ayuda a conservar y compartir semillas tradicionales. Las leyes sobre semillas
|
||||
varían mucho entre países, y distinguen con claridad entre **regalar o intercambiar**
|
||||
semillas y **venderlas**. Este aviso es información general, no asesoramiento jurídico;
|
||||
eres responsable de cumplir la ley allí donde vives y allí donde van tus semillas.
|
||||
|
||||
## Regalar e intercambiar entre aficionados
|
||||
|
||||
Intercambiar semillas **sin ánimo comercial** — regalos, trueques, bibliotecas de
|
||||
semillas, redes de conservación — está ampliamente reconocido y es legal en la mayoría
|
||||
de lugares:
|
||||
|
||||
- **Unión Europea.** La normativa de semillas de la UE regula la *comercialización* de
|
||||
semilla. El intercambio en especie entre particulares y la labor de las redes de
|
||||
conservación y bancos de germoplasma quedan fuera o están expresamente exentos; la
|
||||
reforma en curso del material de reproducción vegetal (propuesta COM(2023) 414)
|
||||
mantiene exenciones para aficionados y redes de conservación, siempre que la
|
||||
actividad no sea comercial.
|
||||
- **España.** La Ley 30/2006 regula el comercio de semillas; el intercambio no
|
||||
comercial entre aficionados y el intercambio con fines de conservación son práctica
|
||||
reconocida (art. 24).
|
||||
- **Estados Unidos.** Tras la enmienda de 2016 a la ley uniforme estatal de semillas
|
||||
(RUSSL), la mayoría de estados eximen el **intercambio no comercial** (bibliotecas de
|
||||
semillas, trueques) de los requisitos comerciales de etiquetado y análisis.
|
||||
|
||||
## Vender semillas
|
||||
|
||||
Vender es distinto. En la UE y en muchas otras jurisdicciones, **comercializar semilla
|
||||
de variedades no inscritas en un catálogo oficial puede estar restringido o
|
||||
prohibido**, y las cantidades, el etiquetado o las especies pueden estar regulados
|
||||
incluso para vendedores pequeños. Existen exenciones para variedades de conservación y
|
||||
cantidades de aficionado, pero varían. Si usas la opción de Tane de pedir un precio,
|
||||
**consulta antes tu normativa nacional** — la aplicación no puede hacerlo por ti.
|
||||
|
||||
## Variedades protegidas
|
||||
|
||||
Las variedades cubiertas por **títulos de obtención vegetal (PVR/PBR) o patentes** no
|
||||
pueden propagarse ni venderse sin autorización del titular — y esto puede aplicarse
|
||||
incluso a semilla comprada legalmente. Las variedades tradicionales y de herencia
|
||||
normalmente no están protegidas; las variedades comerciales modernas casi siempre sí.
|
||||
Ante la duda, no la ofrezcas.
|
||||
|
||||
## Enviar semillas entre países
|
||||
|
||||
La mayoría de países restringen la importación de semillas: **certificados
|
||||
fitosanitarios**, listas de especies prohibidas y normas de cuarentena se aplican con
|
||||
frecuencia — incluso a sobres pequeños entre particulares, y también **dentro** de la
|
||||
UE para ciertas especies (pasaporte fitosanitario). Antes de enviar semillas a otro
|
||||
país, consulta las normas del país de destino. Los intercambios más seguros son los
|
||||
locales — que es justo para lo que está pensada Tane.
|
||||
|
||||
## Especies invasoras y protegidas
|
||||
|
||||
Algunas especies no pueden intercambiarse en absoluto en ciertas regiones, bien porque
|
||||
allí son **invasoras**, bien porque están **protegidas**. Las listas son regionales;
|
||||
consulta la tuya.
|
||||
|
||||
---
|
||||
|
||||
*Tane no cobra comisiones, no media en transacciones y no verifica ofertas: los
|
||||
intercambios son tratos privados entre las personas implicadas (ver las
|
||||
[Condiciones de uso](condiciones-de-uso.md)). Este aviso existe para que esos tratos
|
||||
sean informados.*
|
||||
81
site/content/legal/terms.en.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
---
|
||||
title: "Terms of Use"
|
||||
slug: "terms"
|
||||
weight: 2
|
||||
translationKey: "legal-terms"
|
||||
---
|
||||
|
||||
|
||||
**Version 1.0 — 13 July 2026**
|
||||
|
||||
These terms cover the use of the Tane application, published by **Asociación Comunes**
|
||||
(Spain) — <https://comunes.org>, contact <info@comunes.org>. By using Tane's sharing
|
||||
features (the market and messaging) you accept these terms and the
|
||||
[Community rules](community-rules.md).
|
||||
|
||||
## 1. What Tane is — and what it is not
|
||||
|
||||
Tane is a **personal tool**: a seed inventory that lives on your device, plus a way to
|
||||
discover people near you who share seeds. Tane is **not a marketplace operator, not a
|
||||
shop, and not a party to any exchange**:
|
||||
|
||||
- We host no listings — offers are published by you, under your own key, to
|
||||
community-run relays.
|
||||
- We take **no commission** and process no payments. Any exchange, gift, or sale is
|
||||
agreed and carried out directly between the people involved.
|
||||
- We do not verify seeds, users, or offers, and we cannot remove content from servers
|
||||
we do not operate.
|
||||
|
||||
## 2. Your responsibilities
|
||||
|
||||
You are solely responsible for:
|
||||
|
||||
- **What you offer and exchange.** Make sure you are allowed to share or sell the
|
||||
seeds you list. Rules differ by country — see the
|
||||
[Seed legality notice](seed-legality-notice.md). In particular, selling seed of
|
||||
varieties that are not registered may be restricted where you live, and propagating
|
||||
commercially protected varieties without authorization is illegal in most countries.
|
||||
- **Shipping.** Sending seeds across borders is often restricted (phytosanitary rules).
|
||||
Check before you mail anything abroad.
|
||||
- **What you publish.** Offers, your profile, vouches, and ratings are public and
|
||||
signed by you. Follow the [Community rules](community-rules.md).
|
||||
- **Your keys and backups.** There is no account recovery: if you lose your device and
|
||||
your recovery code, we cannot restore anything.
|
||||
|
||||
## 3. No warranties
|
||||
|
||||
Tane is provided **"as is"**, without warranty of any kind, as free software under the
|
||||
[AGPL-3.0 license](https://www.gnu.org/licenses/agpl-3.0.html). In particular, nobody —
|
||||
not Comunes, not the people you exchange with through the app — guarantees the
|
||||
**identity, purity, germination, health, or legality** of any seed exchanged. Growing
|
||||
information shown in the app (calendars, seed-saving tips, viability estimates) is
|
||||
general guidance, not professional advice.
|
||||
|
||||
## 4. Disputes between users
|
||||
|
||||
Exchanges are private dealings between the people involved. Comunes is not a mediator
|
||||
and accepts no liability for failed exchanges, quality disputes, or losses arising from
|
||||
them. The vouching and rating features exist so communities can build their own trust.
|
||||
|
||||
## 5. Moderation
|
||||
|
||||
There is no central moderation: your app filters what you see through the people you
|
||||
trust, and you can **block** anyone and **report** offers or people from within the
|
||||
app. Reports are shared with the servers involved; on the relay we operate
|
||||
(`relay.comunes.org`), content that breaks the community rules is removed. Relays run
|
||||
by others apply their own policies.
|
||||
|
||||
## 6. Liability
|
||||
|
||||
To the maximum extent permitted by law, Asociación Comunes' total liability arising
|
||||
from the app is limited to the amount you paid for it (Tane is gratis: zero). Nothing
|
||||
in these terms limits liability that cannot be limited by law, or your statutory rights
|
||||
as a consumer.
|
||||
|
||||
## 7. General
|
||||
|
||||
If a part of these terms is found invalid, the rest remains in force. These terms are
|
||||
governed by Spanish and EU law, without depriving you of protections of the law of
|
||||
your country of residence. We may update these terms; material changes will be noted in
|
||||
the app's release notes, and the current version always lives at
|
||||
<https://tane.comunes.org/legal/terms>.
|
||||
84
site/content/legal/terms.es.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
---
|
||||
title: "Condiciones de uso"
|
||||
slug: "terms"
|
||||
weight: 2
|
||||
translationKey: "legal-terms"
|
||||
---
|
||||
|
||||
|
||||
**Versión 1.0 — 13 de julio de 2026**
|
||||
|
||||
Estas condiciones regulan el uso de la aplicación Tane, publicada por la **Asociación
|
||||
Comunes** (España) — <https://comunes.org>, contacto <info@comunes.org>. Al usar las
|
||||
funciones de intercambio de Tane (el mercado y la mensajería) aceptas estas condiciones
|
||||
y las [Normas de la comunidad](normas-de-la-comunidad.md).
|
||||
|
||||
## 1. Qué es Tane — y qué no es
|
||||
|
||||
Tane es una **herramienta personal**: un inventario de semillas que vive en tu
|
||||
dispositivo, más una forma de descubrir personas cercanas que comparten semillas. Tane
|
||||
**no es un operador de mercado, ni una tienda, ni parte de ningún intercambio**:
|
||||
|
||||
- No alojamos anuncios — las ofertas las publicas tú, con tu propia clave, en relés
|
||||
gestionados por comunidades.
|
||||
- No cobramos **ninguna comisión** ni procesamos pagos. Todo intercambio, regalo o
|
||||
venta se acuerda y se realiza directamente entre las personas implicadas.
|
||||
- No verificamos semillas, personas ni ofertas, y no podemos eliminar contenido de
|
||||
servidores que no operamos.
|
||||
|
||||
## 2. Tus responsabilidades
|
||||
|
||||
Eres la única persona responsable de:
|
||||
|
||||
- **Lo que ofreces e intercambias.** Asegúrate de que puedes compartir o vender las
|
||||
semillas que publicas. Las normas cambian según el país — mira el
|
||||
[Aviso sobre semillas](aviso-sobre-semillas.md). En particular, vender semilla de
|
||||
variedades no registradas puede estar restringido donde vives, y propagar variedades
|
||||
protegidas comercialmente sin autorización es ilegal en la mayoría de países.
|
||||
- **Los envíos.** Enviar semillas entre países suele estar restringido (normas
|
||||
fitosanitarias). Infórmate antes de mandar nada al extranjero.
|
||||
- **Lo que publicas.** Las ofertas, tu perfil, los avales y las valoraciones son
|
||||
públicos y van firmados por ti. Sigue las
|
||||
[Normas de la comunidad](normas-de-la-comunidad.md).
|
||||
- **Tus claves y copias de seguridad.** No hay recuperación de cuenta: si pierdes tu
|
||||
dispositivo y tu código de recuperación, no podemos restaurar nada.
|
||||
|
||||
## 3. Sin garantías
|
||||
|
||||
Tane se ofrece **"tal cual"**, sin garantía de ningún tipo, como software libre bajo la
|
||||
[licencia AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.html). En particular, nadie —
|
||||
ni Comunes, ni las personas con las que intercambias a través de la aplicación —
|
||||
garantiza la **identidad, pureza, germinación, sanidad o legalidad** de ninguna semilla
|
||||
intercambiada. La información de cultivo que muestra la aplicación (calendarios,
|
||||
consejos para extraer semilla, estimaciones de viabilidad) es orientación general, no
|
||||
asesoramiento profesional.
|
||||
|
||||
## 4. Conflictos entre personas usuarias
|
||||
|
||||
Los intercambios son tratos privados entre las personas implicadas. Comunes no actúa
|
||||
como mediadora y no acepta responsabilidad por intercambios fallidos, disputas de
|
||||
calidad o pérdidas derivadas de ellos. Los avales y las valoraciones existen para que
|
||||
cada comunidad construya su propia confianza.
|
||||
|
||||
## 5. Moderación
|
||||
|
||||
No hay moderación central: tu aplicación filtra lo que ves a través de la gente en la
|
||||
que confías, y puedes **bloquear** a cualquiera y **denunciar** ofertas o personas
|
||||
desde la propia aplicación. Las denuncias se comparten con los servidores implicados;
|
||||
en el relé que operamos (`relay.comunes.org`), el contenido que incumple las normas de
|
||||
la comunidad se elimina. Los relés de terceros aplican sus propias políticas.
|
||||
|
||||
## 6. Responsabilidad
|
||||
|
||||
En la máxima medida que permita la ley, la responsabilidad total de la Asociación
|
||||
Comunes derivada de la aplicación se limita a lo que pagaste por ella (Tane es
|
||||
gratuita: cero). Nada en estas condiciones limita la responsabilidad que no pueda
|
||||
limitarse por ley, ni tus derechos como consumidor.
|
||||
|
||||
## 7. General
|
||||
|
||||
Si una parte de estas condiciones resultara inválida, el resto sigue en vigor. Estas
|
||||
condiciones se rigen por el derecho español y de la UE, sin privarte de las
|
||||
protecciones de la ley de tu país de residencia. Podemos actualizar estas condiciones;
|
||||
los cambios relevantes se señalarán en las notas de versión de la aplicación, y la
|
||||
versión vigente está siempre en <https://tane.comunes.org/legal/terms>.
|
||||