diff --git a/apps/web/src/lib/components/AudioFrontView.svelte b/apps/web/src/lib/components/AudioFrontView.svelte new file mode 100644 index 0000000..8af178f --- /dev/null +++ b/apps/web/src/lib/components/AudioFrontView.svelte @@ -0,0 +1,98 @@ + + +
+ + + + + + {#if frontText} +

{frontText}

+ {/if} +
+ + diff --git a/apps/web/src/routes/study/[deckId]/+page.svelte b/apps/web/src/routes/study/[deckId]/+page.svelte index 5b70855..607e430 100644 --- a/apps/web/src/routes/study/[deckId]/+page.svelte +++ b/apps/web/src/routes/study/[deckId]/+page.svelte @@ -16,6 +16,7 @@ import { toasts } from '$lib/stores/toasts.svelte.ts'; import { t } from '$lib/i18n/index.svelte.ts'; import ImageOcclusionView from '$lib/components/ImageOcclusionView.svelte'; + import AudioFrontView from '$lib/components/AudioFrontView.svelte'; import CardSurface from '$lib/components/CardSurface.svelte'; const deckId = $derived(page.params.deckId ?? ''); @@ -93,6 +94,17 @@ }; }); + const isAudioFront = $derived(current?.card?.type === 'audio-front'); + const audioFrontData = $derived.by(() => { + const c = current; + if (!c?.card || c.card.type !== 'audio-front') return null; + const fields = c.card.fields as Record; + return { + audioRef: fields.audio_ref ?? '', + frontText: fields.front || undefined, + }; + }); + onMount(async () => { if (!devUser.id) { goto('/'); @@ -217,7 +229,14 @@ {revealed} /> {:else} -
{@html promptHtml}
+ {#if isAudioFront && audioFrontData} + + {:else} +
{@html promptHtml}
+ {/if} {#if revealed}
{@html answerHtml}
diff --git a/packages/cards-domain/src/fsrs.ts b/packages/cards-domain/src/fsrs.ts index ef9bbfa..92f3aa5 100644 --- a/packages/cards-domain/src/fsrs.ts +++ b/packages/cards-domain/src/fsrs.ts @@ -147,7 +147,7 @@ export function subIndexCount(type: string): number { throw new Error( 'subIndexCount("image-occlusion") not supported — use maskRegionCount(fields.mask_regions) from @cards/domain' ); - case 'audio': + case 'audio-front': return 1; case 'multiple-choice': return 1; diff --git a/packages/cards-domain/src/schemas/card.ts b/packages/cards-domain/src/schemas/card.ts index 3a9c35c..11c718e 100644 --- a/packages/cards-domain/src/schemas/card.ts +++ b/packages/cards-domain/src/schemas/card.ts @@ -10,6 +10,7 @@ export const CardTypeSchema = z.enum([ 'basic-reverse', 'cloze', 'image-occlusion', + 'audio-front', ]); export type CardType = z.infer; @@ -20,7 +21,7 @@ export const CardTypeFutureSchema = z.enum([ 'cloze', 'type-in', 'image-occlusion', - 'audio', + 'audio-front', 'multiple-choice', ]); @@ -46,7 +47,7 @@ export function validateFieldsForType( cloze: ['text'], 'type-in': ['question', 'expected'], 'image-occlusion': ['image_ref', 'mask_regions'], - audio: ['audio_ref'], + 'audio-front': ['audio_ref', 'back'], 'multiple-choice': ['question', 'options', 'correct_index'], }; const need = required[type] ?? [];