chore: initial sync
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import { Paper, Text, Stack, Group, Badge, ScrollArea } from '@mantine/core'
|
||||
import { IconMapPin, IconVolume } from '@tabler/icons-react'
|
||||
import { ActionIcon } from '@mantine/core'
|
||||
import type { GuideResponse } from '../lib/api'
|
||||
|
||||
interface GuidePanelProps {
|
||||
response: GuideResponse | null
|
||||
loading: boolean
|
||||
onSpeak: (text: string) => void
|
||||
speaking: boolean
|
||||
onStopSpeaking: () => void
|
||||
}
|
||||
|
||||
export function GuidePanel({ response, loading, onSpeak, speaking, onStopSpeaking }: GuidePanelProps) {
|
||||
if (loading) {
|
||||
return (
|
||||
<Paper withBorder p="md" radius="md">
|
||||
<Text size="sm" c="dimmed">Consultando tu entorno...</Text>
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
|
||||
if (!response) {
|
||||
return (
|
||||
<Paper withBorder p="md" radius="md">
|
||||
<Text size="sm" c="dimmed">
|
||||
Pulsa el micrófono o el botón de explorar para recibir información sobre tu entorno.
|
||||
</Text>
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
|
||||
const { guide, location, pois } = response
|
||||
|
||||
return (
|
||||
<Stack gap="sm">
|
||||
{/* Location header */}
|
||||
<Paper withBorder p="sm" radius="md">
|
||||
<Group gap="xs" wrap="nowrap">
|
||||
<IconMapPin size={16} style={{ flexShrink: 0 }} />
|
||||
<Text size="xs" lineClamp={2}>
|
||||
{location.street ? `${location.street}, ` : ''}
|
||||
{location.neighbourhood ? `${location.neighbourhood}, ` : ''}
|
||||
{location.city}
|
||||
</Text>
|
||||
</Group>
|
||||
</Paper>
|
||||
|
||||
{/* Guide text */}
|
||||
<Paper withBorder p="md" radius="md">
|
||||
<Group justify="space-between" mb="xs">
|
||||
<Text fw={600} size="sm">Guía</Text>
|
||||
<ActionIcon
|
||||
variant={speaking ? 'filled' : 'subtle'}
|
||||
color="teal"
|
||||
size="sm"
|
||||
onClick={() => speaking ? onStopSpeaking() : onSpeak(guide)}
|
||||
>
|
||||
<IconVolume size={14} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
<Text size="sm" style={{ whiteSpace: 'pre-wrap' }}>{guide}</Text>
|
||||
</Paper>
|
||||
|
||||
{/* POIs */}
|
||||
{pois.length > 0 && (
|
||||
<Paper withBorder p="sm" radius="md">
|
||||
<Text fw={600} size="sm" mb="xs">Lugares cercanos</Text>
|
||||
<ScrollArea.Autosize mah={200}>
|
||||
<Stack gap={4}>
|
||||
{pois.map(poi => (
|
||||
<Group key={poi.id} gap="xs" wrap="nowrap">
|
||||
<Text size="xs" fw={500} style={{ flex: 1 }} lineClamp={1}>
|
||||
{poi.name}
|
||||
</Text>
|
||||
<Badge size="xs" variant="light">{poi.category}</Badge>
|
||||
{(poi.score ?? 0) > 0 && (
|
||||
<Badge size="xs" variant="dot" color="teal">
|
||||
{poi.score?.toFixed(1)}
|
||||
</Badge>
|
||||
)}
|
||||
</Group>
|
||||
))}
|
||||
</Stack>
|
||||
</ScrollArea.Autosize>
|
||||
</Paper>
|
||||
)}
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user