Commit graph

1085 commits

Author SHA1 Message Date
SkateSpots
30903eadb0 chore(license): adopt AGPL-3.0-or-later
Add the canonical AGPL-3.0 text at /LICENSE (with the project copyright
notice on top) and set package.json license to AGPL-3.0-or-later. Chosen
because the trust work reviews AGPL reference implementations and we
reimplement rather than copy; AGPL section 13 source-offer is covered by
the public repo + the License page's source link. Recorded in AGENTS.md.
2026-10-09 17:30:01 +07:00
SkateSpots
d1fae2688c feat(trust): attribute the badge and add a /trust explainer
Legibility pass: a trust verdict has to be explainable and sourced.

- TrustBadge tooltips now attribute the claim (from your network / the
  community provider / the provider you chose) and link to /trust.
- New /trust page: the three states, why absence is not distrust, who
  computes it, presence-is-not-endorsement, and point-of-view. Public,
  linked from the badge; added to the smoke-test route list.
- New trustUi.* keys and four walletUi.trust attribution keys (en/es).
2026-10-09 17:30:00 +07:00
SkateSpots
2d1144bb7e feat(trust): batch provider reads, neutral direct follows, flagged notice
Second pass of TRUST_SCORE.md.

- useTrustAssertions now batches: every TrustBadge registers its subject into
  a shared per-viewer union and ONE query fetches the union (no per-card
  query), with a debounced refetch when a list grows. Same hook API.
- A direct follow (or self) is no longer shown as Verified - only a
  friend-of-friend or a provider assertion counts; Flagged is never
  suppressed.
- useUserReports reads public NIP-56 reports for an account, and
  TrustFlaggedNotice shows a flagged counterparty with the reporters grouped
  by the viewer's network plus Report / Dismiss. Wired into the listing
  seller card and the coach detail page.
- New walletUi.trust.* keys (en/es).
2026-10-09 17:17:11 +07:00
SkateSpots
fead9ca781 feat(trust): spec-correct NIP-85 consumer + Verified/Unknown/Flagged badge
First slice of TRUST_SCORE.md.

- lib/nip85.ts: parse kind-10040 provider designations, resolve a provider
  with a house fallback, parse kind-30382 assertions (rank/followers/
  reporters/muters/hops; absent hops means no path, absence is not
  distrust), and author-check the provider.
- hooks/useTrustAssertions.ts: batch read from the resolved provider,
  signature-verified via onlyVerified + the author check.
- lib/trustLadder.ts: three buckets and thresholds (flagged = trusted
  reporters >= 2; verified rank >= 2).
- hooks/useTrustBucket.ts: prefers a NIP-85 assertion (verify + flag),
  falls back to the local WoT ladder (verify only).
- TrustBadge.tsx: now renders Verified / Unknown / Flagged with glyph,
  colour and tooltip; Unknown hidden by default, Flagged always shown.
  Reaches the map/tour/event cards, marketplace card, listing detail and
  coach detail through the shared component.

Open follow-ups (in TRUST_SCORE.md): batch the bucket at list level, a
'who reported' breakdown, a provider-choice setting, alerts, confidence
scoring.
2026-10-09 17:07:34 +07:00
SkateSpots
8833a15830 docs: add TRUST_SCORE.md (trust-scoring review + plan)
Ideas-only review of a personalized web-of-trust approach: a spec-correct
NIP-85 consumer (kind-10040 provider designation, house fallback, author +
signature verification, the rank/followers/reporters/muters/hops tags, and
the absence rules), a Verified/Unknown/Flagged display with a viewer mode,
counterparty alerts, confidence-gated scoring, presets and negative
signals. Notes what we already have, concrete file touch points, license
and privacy caveats, and a recommended first slice. Links it from the
parked identity/conflict section.
2026-10-09 16:55:10 +07:00
SkateSpots
486ffdb000 feat(map): add autocomplete suggestions to the search bar
Typing in the map search pill now opens a suggestions dropdown built
from the items that already match the active filters:
- Spots: title matches; selecting one flies to it and opens its sheet.
- Places: distinct city/region/country tokens split out of each item's
  location; selecting one sets the query to that token (e.g. spain ->
  Spain).

buildSearchSuggestions lives in lib (pure, testable) and
MapSearchSuggestions.tsx is presentational; MapPage owns the list and
keyboard nav (ArrowUp/Down, Enter, Escape). Adds mapPage.searchSuggestPlaces
(en/es only; other locales fall back to English).
2026-10-09 16:31:31 +07:00
SkateSpots
bbae55b610 chore: sync package-lock version to 1.6.0 2026-10-09 09:03:24 +07:00
SkateSpots
ef01c3a5ed fix(map): stop deleted spots flashing back from cache
A NIP-09 kind-5 delete is only honoured by relays and was never applied
locally, so on refresh the persisted React Query cache and the Dexie spot
cache re-rendered a just-deleted spot for a few seconds until fresh data
(or the admin hidden-label query) filtered it out.

Add src/lib/localDeletions.ts: a device-local tombstone keyed by coord
and event id, written optimistically by useDeleteEntity on the owner path
(rolled back if signing/publishing fails). The shared filterAdminHidden/
filterAdminHiddenMixed now also drop tombstoned items, so every list hook
filters them from first render with no per-hook changes. useSkateSpot
returns null for a tombstoned spot, and cacheSpots/cacheSpot refuse and
evict tombstoned rows. Prune by tombstone only (callers use limits 8-2000,
so pruning by 'not in fresh result' would wipe valid cached spots).
2026-10-09 09:03:16 +07:00
SkateSpots
72693732dd docs: record dropdown scroll fix + language picker search gotchas 2026-10-08 20:01:18 +07:00
SkateSpots
281a4c6ba5 feat(i18n): add search/filter to the language picker
The language list now has a search input in both the header dropdown
(pinned above the scrolling list) and the inline list used in the mobile
nav sheet. Filtering matches the English name, native name, or locale
code, and shows a localized empty state. Adds nav.searchLanguages and
nav.noLanguages to en/es (other locales fall back to English).
2026-10-08 18:16:13 +07:00
SkateSpots
bd9eaf9b5f fix(ui): make long dropdown menus scrollable
The shared DropdownMenuContent used overflow-hidden with no max-height,
so any menu taller than the viewport (e.g. the language picker with 22
locales) was clipped and could not scroll to its last items. Apply
Radix's available-height CSS var as max-height and switch to
overflow-y-auto (canonical shadcn pattern).
2026-10-08 18:10:55 +07:00
SkateSpots
0f01eb1bc6 chore: bump to 1.6.0 (10 new languages) 2026-10-08 17:21:57 +07:00
SkateSpots
d0e6fd5274 i18n(sv): finalize batch2 2026-10-08 17:21:49 +07:00
SkateSpots
d7a836e558 i18n(uk): complete Ukrainian (100%) + add to picker 2026-10-08 17:21:03 +07:00
SkateSpots
2e1167f8bd i18n(id): complete Indonesian (100%) + add to picker 2026-10-08 17:19:24 +07:00
SkateSpots
86427a0fb0 i18n(cs): complete Czech (100%) + add to picker 2026-10-08 17:18:34 +07:00
SkateSpots
2d656e5269 i18n(ro): complete Romanian (100%) + add to picker 2026-10-08 17:18:03 +07:00
SkateSpots
4acfa59e56 i18n(sv): complete Swedish (100%) + add to picker 2026-10-08 17:17:54 +07:00
SkateSpots
9998e7b8f6 i18n(el): complete Greek (100%) + add to picker 2026-10-08 17:17:43 +07:00
SkateSpots
09859bb7da i18n(vi): complete Vietnamese (100%) + add to picker 2026-10-08 17:17:35 +07:00
SkateSpots
69d04469f5 i18n(tr): complete Turkish (100%) + add to picker 2026-10-08 17:17:34 +07:00
SkateSpots
8e98a43949 i18n(zh-TW): complete Traditional Chinese (100%) + add to picker 2026-10-08 17:15:51 +07:00
SkateSpots
1c670d314b i18n(zh-CN): complete Simplified Chinese (100%) + add to picker 2026-10-08 16:00:33 +07:00
SkateSpots
feac9f764b i18n: register 10 locales (framework + scaffold); ro/el partial 2026-10-08 14:59:27 +07:00
SkateSpots
1dd23c1549 i18n(ko): separate South and North Korean options, one flag each 2026-10-08 12:45:09 +07:00
SkateSpots
4e8999b84c i18n(ko): show both Korean flags in the language picker 2026-10-08 12:24:31 +07:00
SkateSpots
a7c3a9f130 docs(AGENTS): 12 locales (all 100%), lazy-loading, NK flag, one-writer rule 2026-10-08 00:02:08 +07:00
SkateSpots
361f03c988 i18n(ru,ko): complete Russian + Korean translations; use North Korean flag for Korean 2026-10-07 23:56:20 +07:00
SkateSpots
78660580fa i18n(nl,pl): complete Dutch + Polish translations (100% — 8450 keys each) 2026-10-07 23:51:30 +07:00
SkateSpots
e73c678199 i18n(it): complete Italian translation (100% — 8450 keys) 2026-10-07 23:04:59 +07:00
SkateSpots
7635e1eaa9 i18n(de): complete German translation (100% — 8450 keys) 2026-10-07 22:35:32 +07:00
SkateSpots
1954adfdc2 i18n(fr): complete French translation (100% — 8450 keys) 2026-10-07 22:20:07 +07:00
SkateSpots
845733de24 i18n(pt): complete Brazilian Portuguese translation (100% — 8450 keys) 2026-10-07 21:57:07 +07:00
SkateSpots
90c06eeb91 i18n: scaffold fragment slots for the 8 new locales 2026-10-07 21:24:09 +07:00
SkateSpots
1460b06277 i18n: lazy-load locales + register 8 new (pt fr de it nl pl ru ko) with fonts 2026-10-07 21:23:39 +07:00
SkateSpots
7ab9a5b399 docs(AGENTS): refresh legacyMiscUi scope 2026-10-07 18:31:31 +07:00
SkateSpots
a3b7f311ce i18n: translate image alt/aria + generated export documents (last English literals) 2026-10-07 18:30:52 +07:00
SkateSpots
ac1b56ce76 docs(AGENTS): record the hardcoded-string sweep + legacy fragment layer 2026-10-07 18:12:30 +07:00
SkateSpots
0339395036 i18n: translate the moderation help line (last hardcoded JSX prose) 2026-10-07 18:11:57 +07:00
SkateSpots
f7c9f9ef4c i18n: sweep hardcoded English (deckCost, becomeRoles, weather, skaterLabels, notify, misc) into 4 locales 2026-10-07 18:09:57 +07:00
SkateSpots
af0a138d1a fix(nav): inline language switcher in the mobile sheet (portaled dropdown was unclickable inside a dialog) 2026-10-07 17:54:32 +07:00
SkateSpots
b4411c930b docs(AGENTS): record th + ja at 100% coverage 2026-10-07 17:48:33 +07:00
SkateSpots
8d1598d6c4 i18n: complete Japanese + Thai translation (both 100% — 7,889/7,889 keys) 2026-10-07 17:48:18 +07:00
SkateSpots
ba4beba09d i18n(th): add missing common.hide/undo keys 2026-10-07 17:45:52 +07:00
SkateSpots
312ee3a21c i18n: ja batches 9-11 (social, labOptions, small ns) + th batches 10-13 (lab, social, labOptions, small ns) 2026-10-07 17:45:12 +07:00
SkateSpots
c4c540826a i18n(ja): batch 6 — settingsUi 2026-10-07 17:41:51 +07:00
SkateSpots
83cc11f2dc i18n(th): batch 8 — settingsUi 2026-10-07 17:40:49 +07:00
SkateSpots
f1043c8881 i18n(th): batch 9 — walletUi 2026-10-07 17:39:44 +07:00
SkateSpots
2392b0ee2f i18n(ja): batch 7 — walletUi 2026-10-07 17:39:01 +07:00
SkateSpots
4ba13675cf i18n(ja): batch 8 — labUi 2026-10-07 17:38:05 +07:00