From e42ed06a5ce560a3ae7aad3d1ec857ac06748f6a Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Wed, 29 Apr 2026 17:11:09 +0000 Subject: [PATCH] feat(place): add wiki summary display from Kiwix When place API response includes wiki_summary, display: - Summary text in PlaceCard and PlaceDetail - Population with Users icon if wiki_population present - "Read more" link to wiki_url (local Kiwix article) - "Travel guide" link if wikivoyage_url present - (local) indicator on wiki links to signal Kiwix-served content Gate on has_kiwix_wiki feature flag - no changes when disabled or when wiki_summary not present in response. Co-Authored-By: Claude Opus 4.5 --- src/components/PlaceCard.jsx | 57 +++++++++++++++++++++++++++++++- src/components/PlaceDetail.jsx | 59 +++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/src/components/PlaceCard.jsx b/src/components/PlaceCard.jsx index 1167217..4860a37 100644 --- a/src/components/PlaceCard.jsx +++ b/src/components/PlaceCard.jsx @@ -1,7 +1,7 @@ import { useEffect, useState, useRef, useCallback } from "react" import { X, Navigation, Plus, Bookmark, ChevronDown, ChevronUp, Copy, LogIn, - Clock, Phone, Globe, Mail, BookOpen, Info, Trees, GripVertical, + Clock, Phone, Globe, Mail, BookOpen, Info, Trees, GripVertical, Map, Users, } from "lucide-react" import OpeningHours from "opening_hours" import toast from "react-hot-toast" @@ -158,6 +158,60 @@ function PrivateLandIndicator({ data }) { ) } + +function WikiSummarySection({ details }) { + // Gate on has_kiwix_wiki feature flag + if (!hasFeature('has_kiwix_wiki')) return null + if (!details || !details.wiki_summary) return null + + return ( +
+ {/* Summary text */} +

+ {details.wiki_summary} +

+ + {/* Population */} + {details.wiki_population && ( +
+ + Pop. {details.wiki_population.toLocaleString ? details.wiki_population.toLocaleString() : details.wiki_population} +
+ )} + + {/* Wiki links */} +
+ {details.wiki_url && ( + + + Read more + (local) + + )} + {details.wikivoyage_url && ( + + + Travel guide + (local) + + )} +
+
+ ) +} + function EnrichmentSkeleton() { return (
@@ -417,6 +471,7 @@ export function PlaceCard({ place, variant = "preview", expanded = true, onToggl {placeDetails === "loading" && } {placeDetails && placeDetails !== "loading" && } + {placeDetails && placeDetails !== "loading" && }
{variant === "preview" && ( <> diff --git a/src/components/PlaceDetail.jsx b/src/components/PlaceDetail.jsx index 2aed16c..18ea48b 100644 --- a/src/components/PlaceDetail.jsx +++ b/src/components/PlaceDetail.jsx @@ -1,7 +1,7 @@ import { useEffect, useState, useRef, useCallback } from 'react' import { X, Navigation, Plus, Bookmark, ChevronDown, ChevronUp, Copy, LogIn, - Clock, Phone, Globe, Mail, BookOpen, Info, Trees, + Clock, Phone, Globe, Mail, BookOpen, Info, Trees, Map, Users, } from 'lucide-react' import OpeningHours from 'opening_hours' import toast from 'react-hot-toast' @@ -394,6 +394,60 @@ function PrivateLandIndicator({ data }) { ) } + +function WikiSummarySection({ details }) { + // Gate on has_kiwix_wiki feature flag + if (!hasFeature('has_kiwix_wiki')) return null + if (!details || !details.wiki_summary) return null + + return ( +
+ {/* Summary text */} +

+ {details.wiki_summary} +

+ + {/* Population */} + {details.wiki_population && ( +
+ + Population: {details.wiki_population.toLocaleString ? details.wiki_population.toLocaleString() : details.wiki_population} +
+ )} + + {/* Wiki links */} +
+ {details.wiki_url && ( + + + Read more + (local) + + )} + {details.wikivoyage_url && ( + + + Travel guide + (local) + + )} +
+
+ ) +} + function EnrichmentSkeleton() { return (
@@ -714,6 +768,9 @@ export default function PlaceDetail() { {placeDetails === 'loading' && } {placeDetails && placeDetails !== 'loading' && } + {/* Wiki summary (Kiwix) */} + {placeDetails && placeDetails !== 'loading' && } + {/* Action buttons */}