From d21d794420403339efa2230bcba6006c1c8b58cf Mon Sep 17 00:00:00 2001 From: Thomas Fransolet Date: Tue, 15 Sep 2026 22:18:22 +0200 Subject: [PATCH] =?UTF-8?q?Studio=20lot=208d=20:=20portrait=20du=20narrate?= =?UTF-8?q?ur=20=C3=A0=20c=C3=B4t=C3=A9=20du=20lecteur=20audio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Article et parcours (liste et carte). Corrige au passage l'audio rangé par identifiant de ressource, qui n'avait jamais de lecteur : useAudioResource le résout. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_011VxSQeGQYUvPmSEoGdnidA --- src/components/sections/ArticleSection.tsx | 16 ++++++-- src/components/sections/ParcoursSection.tsx | 38 ++++++++++++++----- src/components/ui/NarratorAvatar.tsx | 26 +++++++++++++ src/hooks/useAudioResource.ts | 42 +++++++++++++++++++++ src/lib/api/client.ts | 6 +++ src/lib/api/types.ts | 3 ++ 6 files changed, 118 insertions(+), 13 deletions(-) create mode 100644 src/components/ui/NarratorAvatar.tsx create mode 100644 src/hooks/useAudioResource.ts diff --git a/src/components/sections/ArticleSection.tsx b/src/components/sections/ArticleSection.tsx index e8ca5dd..4125b0d 100644 --- a/src/components/sections/ArticleSection.tsx +++ b/src/components/sections/ArticleSection.tsx @@ -8,6 +8,8 @@ import { useVisitor } from '@/context/VisitorContext' import { t, tPlain } from '@/lib/i18n' import type { ContentDTO, SectionDTO } from '@/lib/api/types' import AppBar from '@/components/ui/AppBar' +import NarratorAvatar from '@/components/ui/NarratorAvatar' +import { useAudioResource } from '@/hooks/useAudioResource' import { trackEvent } from '@/lib/stats' interface Props { @@ -15,9 +17,10 @@ interface Props { slug: string configId: string languages: string[] + apiKey: string } -export default function ArticleSection({ section, configId, languages }: Props) { +export default function ArticleSection({ section, configId, languages, apiKey }: Props) { const { language, setAvailableLanguages, instanceId } = useVisitor() const back = useBack() const article = section.article @@ -60,8 +63,11 @@ export default function ArticleSection({ section, configId, languages }: Props) return () => el.removeEventListener('scroll', onScroll) }, [instanceId, configId, section.id, language, isLandscape]) - const audioUrl = article?.audioIds?.find((a) => a.language === language)?.value - ?? article?.audioIds?.[0]?.value + const audio = useAudioResource( + article?.audioIds?.find((a) => a.language === language)?.value ?? article?.audioIds?.[0]?.value, + apiKey, + ) + const audioUrl = audio.url useEffect(() => { if (article?.isReadAudioAuto && audioRef.current) { @@ -131,7 +137,9 @@ export default function ArticleSection({ section, configId, languages }: Props) )}
- GUIDE AUDIO + {audio.narratorName + ? + : GUIDE AUDIO} {!isAudioCompact && (
diff --git a/src/components/sections/ParcoursSection.tsx b/src/components/sections/ParcoursSection.tsx index 4c2d445..cc0cad7 100644 --- a/src/components/sections/ParcoursSection.tsx +++ b/src/components/sections/ParcoursSection.tsx @@ -4,6 +4,8 @@ import { useEffect, useRef, useState } from 'react' import { useBack } from '@/hooks/useBack' import ChevronLeft from '@/components/ui/ChevronLeftIcon' import ResourceViewer, { isImageResource } from '@/components/ui/ResourceViewer' +import NarratorAvatar from '@/components/ui/NarratorAvatar' +import { useAudioResource } from '@/hooks/useAudioResource' import { useVisitor } from '@/context/VisitorContext' import { useIsLandscape, useMediaQuery } from '@/hooks/useOrientation' import FloatingPanel from '@/components/ui/FloatingPanel' @@ -37,7 +39,7 @@ interface Props { type View = 'list' | 'start' | 'progress' | 'end' -export default function ParcoursSection({ section, languages }: Props) { +export default function ParcoursSection({ section, languages, apiKey }: Props) { const { language, setAvailableLanguages } = useVisitor() const back = useBack() @@ -130,6 +132,7 @@ export default function ParcoursSection({ section, languages }: Props) { if (useMapView) { return ( a.language === language)?.value - ?? currentStep?.audioIds?.[0]?.value - const audioUrl = audioUrlRaw?.startsWith('http') ? audioUrlRaw : undefined + const audio = useAudioResource( + currentStep?.audioIds?.find((a) => a.language === language)?.value ?? currentStep?.audioIds?.[0]?.value, + apiKey, + ) + const audioUrl = audio.url const stepContents = [...(currentStep?.contents ?? [])].sort((a, b) => (a.order ?? 0) - (b.order ?? 0)) const hasCarousel = stepContents.length > 0 @@ -875,6 +882,11 @@ function ParcoursMapProgression({ path, steps, stepIndex, completedSteps, primar border: `1px solid ${isGame ? 'rgba(212,175,55,0.2)' : '#E8E3DA'}`, }} > + {audio.narratorName && ( +
+ +
+ )}