@tinyweb_dev/oe-exam-sdk 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -4
- package/dist/api/contest-rooms.d.ts +13 -0
- package/dist/api/contest-rooms.js +1 -0
- package/dist/api/contest-rooms.types.d.ts +47 -0
- package/dist/api/contest-rooms.types.js +1 -0
- package/dist/api/exam-entry.d.ts +14 -0
- package/dist/api/exam-entry.js +1 -0
- package/dist/api/exam-entry.types.d.ts +93 -0
- package/dist/api/exam-entry.types.js +1 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +1 -1
- package/dist/components/exams/entry/EntryRestartDialog.d.ts +12 -0
- package/dist/components/exams/entry/EntryRestartDialog.js +1 -0
- package/dist/components/exams/entry/StudentExamEntryPageContainer.d.ts +31 -0
- package/dist/components/exams/entry/StudentExamEntryPageContainer.js +1 -0
- package/dist/components/exams/entry/exam-entry.states.d.ts +22 -0
- package/dist/components/exams/entry/exam-entry.states.js +1 -0
- package/dist/components/exams/entry/exam-entry.utils.d.ts +16 -0
- package/dist/components/exams/entry/exam-entry.utils.js +1 -0
- package/dist/components/exams/entry/fullscreen-loading.d.ts +5 -0
- package/dist/components/exams/entry/fullscreen-loading.js +1 -0
- package/dist/components/exams/entry/index.d.ts +7 -0
- package/dist/components/exams/entry/index.js +1 -0
- package/dist/components/exams/index.d.ts +8 -0
- package/dist/components/exams/index.js +1 -1
- package/dist/components/exams/rooms/StudentContestRoomsPageContainer.d.ts +18 -0
- package/dist/components/exams/rooms/StudentContestRoomsPageContainer.js +1 -0
- package/dist/components/exams/rooms/contest-rooms.utils.d.ts +32 -0
- package/dist/components/exams/rooms/contest-rooms.utils.js +1 -0
- package/dist/components/exams/rooms/index.d.ts +3 -0
- package/dist/components/exams/rooms/index.js +1 -0
- package/dist/components/exams/take/ExamTakingApiContext.d.ts +10 -0
- package/dist/components/exams/take/ExamTakingApiContext.js +1 -0
- package/dist/components/exams/take/ExamTakingPageContainer.d.ts +28 -4
- package/dist/components/exams/take/ExamTakingPageContainer.js +1 -1
- package/dist/components/exams/take/components/QuestionRenderer.d.ts +25 -0
- package/dist/components/exams/take/components/QuestionRenderer.js +1 -0
- package/dist/components/exams/take/components/index.d.ts +10 -0
- package/dist/components/exams/take/components/index.js +1 -0
- package/dist/components/exams/take/components/question-renderers/ArticlesViewer.d.ts +7 -0
- package/dist/components/exams/take/components/question-renderers/ArticlesViewer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversAnswerTheQuestionRenderer.d.ts +22 -0
- package/dist/components/exams/take/components/question-renderers/MoversAnswerTheQuestionRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversChooseAdjectiveRenderer.d.ts +14 -0
- package/dist/components/exams/take/components/question-renderers/MoversChooseAdjectiveRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversChooseBestAnswerRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversChooseBestAnswerRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversColoringRenderer.d.ts +3 -0
- package/dist/components/exams/take/components/question-renderers/MoversColoringRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversGridFillRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversGridFillRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversLabelThePictureRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversLabelThePictureRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversListenAndWriteRenderer.d.ts +21 -0
- package/dist/components/exams/take/components/question-renderers/MoversListenAndWriteRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversMatchByWritingAnswerRenderer.d.ts +19 -0
- package/dist/components/exams/take/components/question-renderers/MoversMatchByWritingAnswerRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversReadingPassageRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversReadingPassageRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversTrueFalseRenderer.d.ts +20 -0
- package/dist/components/exams/take/components/question-renderers/MoversTrueFalseRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordFillParagraphRenderer.d.ts +32 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordFillParagraphRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordFillStructuredFormRenderer.d.ts +18 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordFillStructuredFormRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordOrderingRenderer.d.ts +19 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordOrderingRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversWriteSentencesRenderer.d.ts +22 -0
- package/dist/components/exams/take/components/question-renderers/MoversWriteSentencesRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.d.ts +18 -0
- package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/index.d.ts +19 -0
- package/dist/components/exams/take/components/question-renderers/index.js +1 -0
- package/dist/components/exams/take/components/speaking/FindObjectInPicture.module.css +133 -0
- package/dist/components/exams/take/components/speaking/SpeakingAudioPlayer.d.ts +9 -0
- package/dist/components/exams/take/components/speaking/SpeakingAudioPlayer.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingCompareImages.module.css +153 -0
- package/dist/components/exams/take/components/speaking/SpeakingContentFrame.d.ts +7 -0
- package/dist/components/exams/take/components/speaking/SpeakingContentFrame.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingDragObjects.module.css +238 -0
- package/dist/components/exams/take/components/speaking/SpeakingExamLayout.d.ts +27 -0
- package/dist/components/exams/take/components/speaking/SpeakingExamLayout.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingHeader.d.ts +6 -0
- package/dist/components/exams/take/components/speaking/SpeakingHeader.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingInfoExchange.module.css +193 -0
- package/dist/components/exams/take/components/speaking/SpeakingInfoExchangeSummerSky.module.css +238 -0
- package/dist/components/exams/take/components/speaking/SpeakingInstructionBar.d.ts +5 -0
- package/dist/components/exams/take/components/speaking/SpeakingInstructionBar.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingMicButton.d.ts +14 -0
- package/dist/components/exams/take/components/speaking/SpeakingMicButton.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingNavButton.d.ts +7 -0
- package/dist/components/exams/take/components/speaking/SpeakingNavButton.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingPartBadge.d.ts +6 -0
- package/dist/components/exams/take/components/speaking/SpeakingPartBadge.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingReadDisplayedContent.module.css +115 -0
- package/dist/components/exams/take/components/speaking/SpeakingRecordingPreview.d.ts +11 -0
- package/dist/components/exams/take/components/speaking/SpeakingRecordingPreview.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingReportErrorButton.d.ts +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingReportErrorButton.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingStoryImages.module.css +231 -0
- package/dist/components/exams/take/components/speaking/SpeakingVideoIntro.d.ts +13 -0
- package/dist/components/exams/take/components/speaking/SpeakingVideoIntro.js +1 -0
- package/dist/components/exams/take/components/speaking/index.d.ts +1 -0
- package/dist/components/exams/take/components/speaking/index.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseAnswerGroupRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseAnswerGroupRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseObjectsRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseObjectsRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingCompareImagesRenderer.d.ts +17 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingCompareImagesRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingConversationRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingConversationRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingCueCardRenderer.d.ts +17 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingCueCardRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingDescribeImageRenderer.d.ts +18 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingDescribeImageRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingDragObjectsRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingDragObjectsRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingInfoExchangeRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingInfoExchangeRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingListenAndSpeakAnswerRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingListenAndSpeakAnswerRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingOddOneOutRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingOddOneOutRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionListRenderer.d.ts +26 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionListRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionRenderer.d.ts +32 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingReadDisplayedContentRenderer.d.ts +34 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingReadDisplayedContentRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingSpontaneousQARenderer.d.ts +17 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingSpontaneousQARenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingStoryImagesRenderer.d.ts +17 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingStoryImagesRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/index.d.ts +13 -0
- package/dist/components/exams/take/components/speaking/renderers/index.js +1 -0
- package/dist/components/exams/take/hooks/index.d.ts +2 -0
- package/dist/components/exams/take/hooks/index.js +1 -0
- package/dist/components/exams/take/hooks/useAnswerAutosave.d.ts +27 -0
- package/dist/components/exams/take/hooks/useAnswerAutosave.js +1 -0
- package/dist/components/exams/take/hooks/useAttemptSubmit.d.ts +29 -0
- package/dist/components/exams/take/hooks/useAttemptSubmit.js +1 -0
- package/dist/components/exams/take/hooks/useAutoSave.d.ts +20 -0
- package/dist/components/exams/take/hooks/useAutoSave.js +1 -0
- package/dist/components/exams/take/hooks/useExamCountdown.d.ts +22 -0
- package/dist/components/exams/take/hooks/useExamCountdown.js +1 -0
- package/dist/components/exams/take/hooks/useExamTimer.d.ts +21 -0
- package/dist/components/exams/take/hooks/useExamTimer.js +1 -0
- package/dist/components/exams/take/hooks/useProctoringCamera.d.ts +19 -0
- package/dist/components/exams/take/hooks/useProctoringCamera.js +1 -0
- package/dist/components/exams/take/hooks/useProctoringSnapshot.d.ts +25 -0
- package/dist/components/exams/take/hooks/useProctoringSnapshot.js +1 -0
- package/dist/components/exams/take/hooks/useSpeakingConversationAudio.d.ts +19 -0
- package/dist/components/exams/take/hooks/useSpeakingConversationAudio.js +1 -0
- package/dist/components/exams/take/hooks/useSpeakingNavigation.d.ts +37 -0
- package/dist/components/exams/take/hooks/useSpeakingNavigation.js +1 -0
- package/dist/components/exams/take/hooks/useSpeakingRecorder.d.ts +45 -5
- package/dist/components/exams/take/hooks/useSpeakingRecorder.js +1 -1
- package/dist/components/exams/take/hooks/useSpeakingRendererSetup.d.ts +39 -0
- package/dist/components/exams/take/hooks/useSpeakingRendererSetup.js +1 -0
- package/dist/components/exams/take/hooks/useToeicAudio.d.ts +17 -0
- package/dist/components/exams/take/hooks/useToeicAudio.js +1 -0
- package/dist/components/exams/take/index.d.ts +9 -1
- package/dist/components/exams/take/index.js +1 -1
- package/dist/components/exams/take/types/speaking-cue-card.types.d.ts +10 -0
- package/dist/components/exams/take/types/speaking-cue-card.types.js +1 -0
- package/dist/components/exams/take/types/speaking.types.d.ts +153 -0
- package/dist/components/exams/take/types/speaking.types.js +1 -0
- package/dist/components/exams/take/types.d.ts +286 -1
- package/dist/components/exams/take/utils/answer-transformers.d.ts +26 -0
- package/dist/components/exams/take/utils/answer-transformers.js +1 -0
- package/dist/components/exams/take/utils/coloring-assignments.d.ts +5 -0
- package/dist/components/exams/take/utils/coloring-assignments.js +1 -0
- package/dist/components/exams/take/utils/question-transformers.d.ts +362 -0
- package/dist/components/exams/take/utils/question-transformers.js +1 -0
- package/dist/components/features/exam-entry/entry-state-cards.d.ts +19 -0
- package/dist/components/features/exam-entry/entry-state-cards.js +1 -0
- package/dist/components/features/exam-entry/index.d.ts +2 -0
- package/dist/components/features/exam-entry/index.js +1 -0
- package/dist/components/features/exam-entry/themed/CambridgeYleWaitingRoom.d.ts +12 -0
- package/dist/components/features/exam-entry/themed/CambridgeYleWaitingRoom.js +1 -0
- package/dist/components/features/exam-entry/themed/ThemedWaitingRoom.d.ts +14 -0
- package/dist/components/features/exam-entry/themed/ThemedWaitingRoom.js +1 -0
- package/dist/components/features/exam-entry/themed/ToeicWaitingRoom.d.ts +16 -0
- package/dist/components/features/exam-entry/themed/ToeicWaitingRoom.js +1 -0
- package/dist/components/features/exam-entry/themed/components/CloseButton.d.ts +9 -0
- package/dist/components/features/exam-entry/themed/components/CloseButton.js +1 -0
- package/dist/components/features/exam-entry/themed/components/ExamInfoPanel.d.ts +13 -0
- package/dist/components/features/exam-entry/themed/components/ExamInfoPanel.js +1 -0
- package/dist/components/features/exam-entry/themed/components/ModeSelector.d.ts +7 -0
- package/dist/components/features/exam-entry/themed/components/ModeSelector.js +1 -0
- package/dist/components/features/exam-entry/themed/components/StartButton.d.ts +11 -0
- package/dist/components/features/exam-entry/themed/components/StartButton.js +1 -0
- package/dist/components/features/exam-entry/themed/components/index.d.ts +4 -0
- package/dist/components/features/exam-entry/themed/components/index.js +1 -0
- package/dist/components/features/exam-entry/themed/index.d.ts +1 -0
- package/dist/components/features/exam-entry/themed/index.js +1 -0
- package/dist/components/results/ResultReviewPageContainer.d.ts +3 -1
- package/dist/components/results/ResultReviewPageContainer.js +1 -1
- package/dist/components/results/hooks/useResultReviewPolling.d.ts +27 -0
- package/dist/components/results/hooks/useResultReviewPolling.js +1 -0
- package/dist/components/results/index.d.ts +3 -0
- package/dist/components/results/index.js +1 -1
- package/dist/components/results/review-status.utils.d.ts +12 -0
- package/dist/components/results/review-status.utils.js +1 -0
- package/dist/components/shared/audio/SpeakingAudioPlayer.d.ts +12 -0
- package/dist/components/shared/audio/SpeakingAudioPlayer.js +1 -0
- package/dist/components/shared/audio/SpeakingAudioPlayer.module.css +115 -0
- package/dist/components/shared/audio/assets/fr-image-part1-border.png +0 -0
- package/dist/components/shared/audio/assets/ic-speaker.webp +0 -0
- package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.d.ts +11 -3
- package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.d.ts +5 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -1
- package/dist/components/themes/index.d.ts +11 -0
- package/dist/components/themes/index.js +1 -1
- package/dist/components/themes/spaceship/SpaceshipAudioPlayer.d.ts +8 -0
- package/dist/components/themes/spaceship/SpaceshipAudioPlayer.js +1 -0
- package/dist/components/themes/spaceship/SpaceshipLayout.d.ts +2 -0
- package/dist/components/themes/spaceship/SpaceshipLayout.js +1 -0
- package/dist/components/themes/spaceship/assets/images/X-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/X.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/audio-bar.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/background.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/bg_sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/big-blue-badge-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/big-blue-badge.png +0 -0
- package/dist/components/themes/spaceship/assets/images/big-blue-badge.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/bingo.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/blue-badge-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/blue-badge.png +0 -0
- package/dist/components/themes/spaceship/assets/images/blue-wrapper-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/blue-wrapper.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/board_red.png +0 -0
- package/dist/components/themes/spaceship/assets/images/button_feedback_vi.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn-right-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn-right.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/focus-vector.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/head-phone_red.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-mute-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-mute.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-play-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-play-violet.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-play.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/micro.png +0 -0
- package/dist/components/themes/spaceship/assets/images/next-small.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/next-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/next.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/purple-circle.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/question-badge-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/question-badge.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/red-badge-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/red-badge.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/red-wrapper-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/red-wrapper.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/robot-avatar.png +0 -0
- package/dist/components/themes/spaceship/assets/images/sound_red.png +0 -0
- package/dist/components/themes/spaceship/assets/images/student-avatar.png +0 -0
- package/dist/components/themes/spaceship/assets/images/teacher-play-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/teacher-play.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/timer-badge.png +0 -0
- package/dist/components/themes/spaceship/assets/styles/SpaceshipLayout.module.css +347 -0
- package/dist/components/themes/spaceship/assets/styles/SpaceshipWaitingRoom.module.css +395 -0
- package/dist/components/ui/badge.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/shared/lib/stores/examTakingStore.d.ts +54 -0
- package/dist/shared/lib/stores/examTakingStore.js +1 -0
- package/dist/shared/lib/stores/gradingTransientStore.d.ts +23 -0
- package/dist/shared/lib/stores/gradingTransientStore.js +1 -0
- package/dist/shared/lib/themes/config/starters.config.d.ts +3 -0
- package/dist/shared/lib/themes/config/starters.config.js +1 -0
- package/dist/shared/lib/themes/index.d.ts +18 -0
- package/dist/shared/lib/themes/index.js +1 -0
- package/dist/shared/lib/themes/types.d.ts +39 -0
- package/dist/shared/lib/themes/types.js +1 -0
- package/dist/shared/lib/toast.d.ts +19 -0
- package/dist/shared/lib/toast.js +1 -0
- package/package.json +10 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e}from"react/jsx-runtime";export function SpeakingInstructionBar({text:r}){return e("div",{className:"rounded-lg px-5 py-2.5 text-center",style:{background:"linear-gradient(180deg, #44271a 0%, #2d1a0e 100%)",boxShadow:"0 4px 8px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.08)",border:"2px solid #1c0e07"},children:e("span",{className:"text-sm font-bold uppercase tracking-widest text-amber-100",children:r})})}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RecordingState } from '../../types/speaking.types';
|
|
2
|
+
interface SpeakingMicButtonProps {
|
|
3
|
+
status: RecordingState['status'];
|
|
4
|
+
durationSeconds: number;
|
|
5
|
+
remainingSeconds?: number;
|
|
6
|
+
isWarning?: boolean;
|
|
7
|
+
onStartRecording: () => void;
|
|
8
|
+
onStopRecording: () => void;
|
|
9
|
+
onRetryUpload?: () => void;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
hasExistingRecording?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function SpeakingMicButton({ status, durationSeconds: _durationSeconds, remainingSeconds, isWarning, onStartRecording, onStopRecording, onRetryUpload, disabled, hasExistingRecording, }: SpeakingMicButtonProps): import("react").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import{Mic as t,Square as o,CheckCircle as a,AlertCircle as n,RotateCcw as i}from"lucide-react";import{cn as d}from"../../../../../shared/lib/utils";function l(e){const r=Math.floor(e/60),t=e%60;return`${String(r).padStart(1,"0")}:${String(t).padStart(2,"0")}`}export function SpeakingMicButton({status:s,durationSeconds:g,remainingSeconds:c,isWarning:h=!1,onStartRecording:m,onStopRecording:b,onRetryUpload:u,disabled:p=!1,hasExistingRecording:x=!1}){const f="recording"===s,w="uploading"===s,v="uploaded"===s,N="error"===s,y=x&&!N&&!f;return r("div",{className:"flex flex-col items-center gap-0",children:[f&&e("div",{className:d("mb-2 rounded-full px-4 py-1 text-sm font-bold tabular-nums",h?"bg-red-600 text-white":"bg-red-900/80 text-white"),children:void 0!==c?l(c):""}),r("button",{type:"button",onClick:()=>{p||w||y||(N&&u?u():f?b():m())},disabled:p||w||y,"aria-label":f?"Dừng ghi âm":N?"Thử lại upload":"Bắt đầu ghi âm",className:d("relative flex h-20 w-20 items-center justify-center rounded-full","border-4 shadow-[0_6px_20px_rgba(0,0,0,0.4)]","transition-all duration-200","active:scale-95","disabled:cursor-not-allowed disabled:opacity-50",!f&&!v&&!w&&!N&&"border-orange-700 bg-gradient-to-b from-orange-400 to-orange-600 hover:from-orange-500 hover:to-orange-700",f&&!h&&"animate-pulse border-red-700 bg-gradient-to-b from-red-500 to-red-700",f&&h&&"animate-pulse border-red-900 bg-gradient-to-b from-red-600 to-red-900",w&&"border-orange-700 bg-gradient-to-b from-orange-400 to-orange-600",v&&"border-green-700 bg-gradient-to-b from-green-400 to-green-600 hover:from-green-500 hover:to-green-700",N&&"border-orange-700 bg-gradient-to-b from-orange-400 to-orange-600 hover:from-orange-500 hover:to-orange-700"),children:[f&&e(o,{className:"h-8 w-8 fill-white text-white"}),v&&e(a,{className:"h-8 w-8 text-white"}),N&&e(u?i:n,{className:"h-8 w-8 text-white"}),!f&&!v&&!N&&e(t,{className:"h-8 w-8 text-white"}),w&&e("span",{className:"absolute inset-0 flex items-center justify-center rounded-full bg-black/30",children:r("svg",{className:"h-8 w-8 animate-spin text-white",viewBox:"0 0 24 24",fill:"none","aria-hidden":"true",children:[e("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]})})]}),e("div",{className:"mt-3 rounded-lg px-4 py-2 text-center",style:{background:"linear-gradient(180deg, #3d2008 0%, #2a1505 100%)",boxShadow:"0 3px 8px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.07)",border:"2px solid #1c0a02"},children:e("p",{className:"text-[11px] font-bold uppercase tracking-widest text-amber-200",children:N?u?"Thử lại upload":"Lỗi ghi âm":v?"Đã ghi âm thành công":w?"Đang tải lên...":f?"Nhấn để dừng ghi âm":x?"Câu trả lời đã được ghi nhận":"Thí sinh ấn vào biểu tượng micro để trả lời"})})]})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e}from"react/jsx-runtime";import{ChevronLeft as r,ChevronRight as t}from"lucide-react";import{cn as a}from"../../../../../shared/lib/utils";export function SpeakingNavButton({direction:o,onClick:i,disabled:s=!1}){const d="prev"===o?r:t;return e("button",{onClick:i,disabled:s,className:a("flex h-14 w-14 items-center justify-center rounded-full","border-4 border-amber-800","bg-gradient-to-b from-amber-500 to-amber-700","shadow-[0_4px_12px_rgba(0,0,0,0.4),inset_0_1px_0_rgba(255,255,255,0.2)]","transition-all duration-200","hover:from-amber-600 hover:to-amber-800","active:scale-95 active:shadow-[0_2px_6px_rgba(0,0,0,0.4)]","disabled:cursor-not-allowed disabled:opacity-40","sm:h-16 sm:w-16"),"aria-label":"prev"===o?"Câu trước":"Câu tiếp theo",children:e(d,{className:"h-7 w-7 text-white drop-shadow sm:h-8 sm:w-8",strokeWidth:2.5})})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import{cn as r}from"../../../../../shared/lib/utils";export function SpeakingPartBadge({partName:t,className:s}){return e("div",{className:r("relative inline-flex items-center justify-center",s),children:a("div",{className:"relative flex items-center gap-2 rounded-full border-4 border-amber-600 bg-gradient-to-b from-amber-300 via-amber-400 to-amber-600 px-6 py-2 shadow-[0_4px_12px_rgba(0,0,0,0.4),inset_0_1px_0_rgba(255,255,255,0.3)]",children:[e("span",{className:"text-sm","aria-hidden":"true",children:"🍃"}),e("span",{className:"font-bold tracking-wide text-amber-900 drop-shadow-sm",style:{fontSize:"1.1rem"},children:t}),e("span",{className:"text-sm","aria-hidden":"true",children:"🍃"})]})})}
|
package/dist/components/exams/take/components/speaking/SpeakingReadDisplayedContent.module.css
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/* ===== Read Displayed Content — Scoped styles ===== */
|
|
2
|
+
|
|
3
|
+
/* Reference text card — prominent, readable display */
|
|
4
|
+
.referenceTextCard {
|
|
5
|
+
background: rgba(255, 255, 255, 0.95);
|
|
6
|
+
border-radius: 16px;
|
|
7
|
+
padding: 32px 40px;
|
|
8
|
+
max-width: 720px;
|
|
9
|
+
width: 100%;
|
|
10
|
+
box-shadow:
|
|
11
|
+
0 4px 24px rgba(0, 0, 0, 0.12),
|
|
12
|
+
0 1px 4px rgba(0, 0, 0, 0.08);
|
|
13
|
+
border: 2px solid rgba(255, 255, 255, 0.6);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.referenceText {
|
|
17
|
+
font-size: 1.5rem;
|
|
18
|
+
line-height: 2;
|
|
19
|
+
color: #1a1a2e;
|
|
20
|
+
font-family: 'Georgia', 'Times New Roman', serif;
|
|
21
|
+
letter-spacing: 0.02em;
|
|
22
|
+
text-align: center;
|
|
23
|
+
word-spacing: 0.05em;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Difficulty tag badge */
|
|
27
|
+
.difficultyBadge {
|
|
28
|
+
display: inline-flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
gap: 6px;
|
|
31
|
+
padding: 4px 12px;
|
|
32
|
+
border-radius: 20px;
|
|
33
|
+
font-size: 0.75rem;
|
|
34
|
+
font-weight: 600;
|
|
35
|
+
text-transform: uppercase;
|
|
36
|
+
letter-spacing: 0.05em;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.difficultyBasicPhonics {
|
|
40
|
+
background: #dbeafe;
|
|
41
|
+
color: #1d4ed8;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.difficultyDailyRoutine {
|
|
45
|
+
background: #fef3c7;
|
|
46
|
+
color: #92400e;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.difficultyDescriptiveEmotional {
|
|
50
|
+
background: #ede9fe;
|
|
51
|
+
color: #6d28d9;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Model audio section */
|
|
55
|
+
.modelAudioSection {
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
gap: 8px;
|
|
60
|
+
margin-top: 12px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.modelAudioLabel {
|
|
64
|
+
font-size: 0.85rem;
|
|
65
|
+
color: #64748b;
|
|
66
|
+
font-weight: 500;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Task number indicator */
|
|
70
|
+
.taskIndicator {
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
gap: 8px;
|
|
74
|
+
color: rgba(255, 255, 255, 0.9);
|
|
75
|
+
font-weight: 700;
|
|
76
|
+
font-size: 0.9rem;
|
|
77
|
+
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.taskDot {
|
|
81
|
+
width: 10px;
|
|
82
|
+
height: 10px;
|
|
83
|
+
border-radius: 50%;
|
|
84
|
+
background: rgba(255, 255, 255, 0.4);
|
|
85
|
+
transition: background 0.2s;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.taskDotActive {
|
|
89
|
+
background: #fbbf24;
|
|
90
|
+
box-shadow: 0 0 8px rgba(251, 191, 36, 0.5);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.taskDotCompleted {
|
|
94
|
+
background: #34d399;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Responsive adjustments */
|
|
98
|
+
@media (max-width: 768px) {
|
|
99
|
+
.referenceTextCard {
|
|
100
|
+
padding: 20px 24px;
|
|
101
|
+
max-width: 100%;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.referenceText {
|
|
105
|
+
font-size: 1.2rem;
|
|
106
|
+
line-height: 1.8;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@media (max-width: 480px) {
|
|
111
|
+
.referenceText {
|
|
112
|
+
font-size: 1rem;
|
|
113
|
+
line-height: 1.7;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RecordingState } from '../../types/speaking.types';
|
|
2
|
+
interface SpeakingRecordingPreviewProps {
|
|
3
|
+
previewUrl: string;
|
|
4
|
+
uploadedKey: string | null;
|
|
5
|
+
status: RecordingState['status'];
|
|
6
|
+
onReRecord: () => void;
|
|
7
|
+
/** Called when audio playback state changes (play/pause/ended) */
|
|
8
|
+
onPlayingChange?: (isPlaying: boolean) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function SpeakingRecordingPreview({ previewUrl, uploadedKey, status, onReRecord, onPlayingChange, }: SpeakingRecordingPreviewProps): import("react").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useRef as n,useState as r,useEffect as i}from"react";import{Play as a,Pause as l,RotateCcw as s,CheckCircle as d,AlertCircle as o,Loader2 as c}from"lucide-react";import{cn as m}from"../../../../../shared/lib/utils";function u(e){const t=Math.floor(e/60),n=Math.floor(e%60);return`${String(t).padStart(2,"0")}:${String(n).padStart(2,"0")}`}export function SpeakingRecordingPreview({previewUrl:p,uploadedKey:h,status:b,onReRecord:x,onPlayingChange:f}){const g=n(null),[w,v]=r(!1),[N,k]=r(0),[y,L]=r(0),E=!h&&"uploading"!==b&&"uploaded"!==b;i(()=>{const e=g.current;if(!e)return;const t=()=>{e.duration&&!isNaN(e.duration)&&isFinite(e.duration)&&L(e.duration)},n=()=>{k(e.currentTime),t()},r=()=>{v(!1),k(0),f?.(!1)};return t(),e.addEventListener("loadedmetadata",t),e.addEventListener("timeupdate",n),e.addEventListener("ended",r),()=>{e.removeEventListener("loadedmetadata",t),e.removeEventListener("timeupdate",n),e.removeEventListener("ended",r)}},[p]);const j=y>0?N/y*100:0;return t("div",{className:"mx-auto flex w-fit min-w-[320px] max-w-full items-center gap-3 rounded-full bg-white/70 backdrop-blur-md px-4 py-2.5 shadow-[0_8px_30px_rgb(0,0,0,0.12)] border border-white/60 ring-2 ring-white/40",children:[e("audio",{ref:g,src:p,preload:"metadata"}),e("button",{type:"button",onClick:()=>{const e=g.current;e&&(w?(e.pause(),v(!1),f?.(!1)):(e.play(),v(!0),f?.(!0)))},className:"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-blue-500 text-white shadow-md transition-all hover:bg-blue-600 hover:scale-105 active:scale-95","aria-label":w?"Tạm dừng":"Nghe lại",children:w?e(l,{className:"h-4 w-4 fill-current"}):e(a,{className:"ml-0.5 h-4 w-4 fill-current"})}),e("div",{className:"flex-1 min-w-[100px] relative flex items-center",children:e("input",{type:"range",min:"0",max:y||0,step:"0.1",value:N,onChange:e=>{const t=g.current;if(!t)return;const n=parseFloat(e.target.value);t.currentTime=n,k(n)},className:m("w-full h-1.5 cursor-pointer appearance-none rounded-full bg-stone-200","[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-3.5 [&::-webkit-slider-thumb]:w-3.5","[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:shadow-md","[&::-webkit-slider-thumb]:border-[3px] [&::-webkit-slider-thumb]:border-blue-500","[&::-webkit-slider-thumb]:transition-transform [&::-webkit-slider-thumb]:hover:scale-125"),style:{background:`linear-gradient(to right, #3b82f6 0%, #3b82f6 ${j}%, #e5e7eb ${j}%, #e5e7eb 100%)`}})}),t("span",{className:"min-w-[72px] text-right text-[11px] tabular-nums text-stone-600 font-bold shrink-0 tracking-wide",children:[u(N)," / ",u(y)]}),e("div",{className:"w-px h-6 bg-stone-200 shrink-0 mx-1"}),t("div",{className:"shrink-0 flex items-center justify-center min-w-[70px]",children:["uploading"===b&&t("div",{className:"flex items-center gap-1.5 rounded-full bg-amber-100 px-2.5 py-1 text-[11px] font-bold text-amber-700",children:[e(c,{className:"h-3 w-3 animate-spin"}),e("span",{className:"hidden sm:inline",children:"Đang lưu"})]}),"uploaded"===b&&t("div",{className:"flex items-center gap-1.5 rounded-full bg-green-100 px-2.5 py-1 text-[11px] font-bold text-green-700",children:[e(d,{className:"h-3.5 w-3.5"}),e("span",{className:"hidden sm:inline",children:"Đã lưu"})]}),"error"===b&&t("div",{className:"flex items-center gap-1.5 rounded-full bg-red-100 px-2.5 py-1 text-[11px] font-bold text-red-700",children:[e(o,{className:"h-3.5 w-3.5"}),e("span",{className:"hidden sm:inline",children:"Lỗi"})]}),"recorded"===b&&e("div",{className:"flex items-center gap-1 text-[11px] text-stone-400 font-medium",children:e(c,{className:"h-3 w-3 animate-spin"})})]}),E&&t("button",{type:"button",onClick:x,className:"flex items-center gap-1.5 rounded-full bg-stone-100 px-3 py-1.5 text-[11px] font-bold text-stone-700 transition-all hover:bg-stone-200 hover:text-stone-900 active:bg-stone-300 disabled:cursor-not-allowed disabled:opacity-50 shrink-0 ml-1",children:[e(s,{className:"h-3.5 w-3.5"}),e("span",{className:"hidden sm:inline",children:"Ghi lại"})]})]})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function SpeakingReportErrorButton(): import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as o}from"react/jsx-runtime";import{toast as e}from"../../../../../shared/lib/toast";export function SpeakingReportErrorButton(){return o("button",{type:"button",onClick:()=>{e.info("Tính năng báo cáo lỗi sẽ sớm có")},className:"flex flex-col items-center justify-center gap-0.5 rounded-lg border-2 border-yellow-600 bg-gradient-to-b from-yellow-400 to-yellow-600 px-2 py-3 shadow-md transition-all hover:from-yellow-500 hover:to-yellow-700 active:scale-95","aria-label":"Báo cáo lỗi",title:"Báo cáo lỗi",children:"BÁO CÁO LỖI".split("").map((e,t)=>o("span",{className:"text-[9px] font-extrabold leading-tight text-yellow-900",children:" "===e?" ":e},t))})}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
* SpeakingStoryImages — 2-row grid layout
|
|
3
|
+
*
|
|
4
|
+
* Goals:
|
|
5
|
+
* - Larger image frames (acceptable to scroll vertically).
|
|
6
|
+
* - 2 rows by default (e.g. 3+3, 3+2, 2+2). For ≤3 images,
|
|
7
|
+
* a single row still renders naturally via auto-fit.
|
|
8
|
+
* - Never overlap the floating audio bar at the top of the
|
|
9
|
+
* Summer Sky board, nor the mic label / mic button at the
|
|
10
|
+
* bottom — handled via fixed safe-zone padding.
|
|
11
|
+
* - Numbered frames so the story order remains obvious.
|
|
12
|
+
* ============================================================ */
|
|
13
|
+
|
|
14
|
+
/* Outer wrapper takes the full content area and reserves
|
|
15
|
+
* vertical "safe zones". Vertical scroll is allowed; horizontal
|
|
16
|
+
* is not. */
|
|
17
|
+
.part3Container {
|
|
18
|
+
height: 100%;
|
|
19
|
+
width: 100%;
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: flex-start;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
position: relative;
|
|
24
|
+
/* Top: clears the floating audio pill (top:50px + ~36px tall). */
|
|
25
|
+
/* Bottom: clears mic label that sits inside the board. */
|
|
26
|
+
padding: 96px 110px 140px;
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
overflow-x: hidden;
|
|
29
|
+
overflow-y: auto;
|
|
30
|
+
scrollbar-color: rgba(255, 255, 255, 0.8) transparent;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.part3Container::-webkit-scrollbar {
|
|
34
|
+
width: 8px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.part3Container::-webkit-scrollbar-track {
|
|
38
|
+
background: transparent;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.part3Container::-webkit-scrollbar-thumb {
|
|
42
|
+
background: rgba(255, 255, 255, 0.8);
|
|
43
|
+
border-radius: 10px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Grid: auto-fit so 1–6 images naturally lay out. With minmax
|
|
47
|
+
* around 320px and a max board width of ~1180px (after padding),
|
|
48
|
+
* 4 columns fit comfortably; ≥5 wraps to a second row, giving
|
|
49
|
+
* the requested 3+2 / 3+3 style without manual breakpoints. */
|
|
50
|
+
.storyGrid {
|
|
51
|
+
width: 100%;
|
|
52
|
+
display: grid;
|
|
53
|
+
gap: 24px;
|
|
54
|
+
justify-items: center;
|
|
55
|
+
align-content: start;
|
|
56
|
+
/* Default: 3 columns (covers 3, 5→3+2, 6→3+3). Renderer overrides
|
|
57
|
+
* via data-count for cases where a different split looks better. */
|
|
58
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.storyGrid[data-count="1"] {
|
|
62
|
+
grid-template-columns: minmax(0, 520px);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.storyGrid[data-count="2"],
|
|
66
|
+
.storyGrid[data-count="4"] {
|
|
67
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Each frame keeps a fixed landscape aspect ratio so all images
|
|
71
|
+
* render at the same size regardless of source dimensions. */
|
|
72
|
+
.storyFrame {
|
|
73
|
+
position: relative;
|
|
74
|
+
width: 100%;
|
|
75
|
+
max-width: 380px;
|
|
76
|
+
aspect-ratio: 4 / 3;
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* The clickable image surface — themed border + shadow that
|
|
83
|
+
* matches Summer Sky cards. */
|
|
84
|
+
.imageBorder {
|
|
85
|
+
position: relative;
|
|
86
|
+
width: 100%;
|
|
87
|
+
height: 100%;
|
|
88
|
+
border-radius: 16px;
|
|
89
|
+
/* Soft fill behind contained images so any letterboxing blends in. */
|
|
90
|
+
background: #f4f8ff;
|
|
91
|
+
border: 4px solid #ffffff;
|
|
92
|
+
box-shadow:
|
|
93
|
+
0 6px 14px rgba(11, 76, 142, 0.22),
|
|
94
|
+
0 0 0 2px rgba(74, 144, 217, 0.25);
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
cursor: zoom-in;
|
|
97
|
+
transition: transform 0.18s ease, box-shadow 0.18s ease;
|
|
98
|
+
padding: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.imageBorder:hover {
|
|
102
|
+
transform: translateY(-2px) scale(1.02);
|
|
103
|
+
box-shadow:
|
|
104
|
+
0 10px 22px rgba(11, 76, 142, 0.32),
|
|
105
|
+
0 0 0 2px rgba(74, 144, 217, 0.45);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.imageBorder img {
|
|
109
|
+
width: 100%;
|
|
110
|
+
height: 100%;
|
|
111
|
+
/* `contain` ensures the full story illustration is always visible —
|
|
112
|
+
* never crop characters/objects out at the edges. Minor letterboxing
|
|
113
|
+
* is acceptable and blends with the background fill. */
|
|
114
|
+
object-fit: contain;
|
|
115
|
+
object-position: center;
|
|
116
|
+
display: block;
|
|
117
|
+
pointer-events: none;
|
|
118
|
+
user-select: none;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Numbered sequence badge (top-left). */
|
|
122
|
+
.storyNumber {
|
|
123
|
+
position: absolute;
|
|
124
|
+
top: -12px;
|
|
125
|
+
left: -12px;
|
|
126
|
+
width: 40px;
|
|
127
|
+
height: 40px;
|
|
128
|
+
border-radius: 50%;
|
|
129
|
+
background: linear-gradient(180deg, #ffe341 0%, #f7ab16 100%);
|
|
130
|
+
color: #0b4c8e;
|
|
131
|
+
font-family: 'Nunito', 'Open Sans', system-ui, sans-serif;
|
|
132
|
+
font-weight: 900;
|
|
133
|
+
font-size: 20px;
|
|
134
|
+
line-height: 1;
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
justify-content: center;
|
|
138
|
+
border: 3px solid #ffffff;
|
|
139
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
|
140
|
+
z-index: 2;
|
|
141
|
+
pointer-events: none;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* Empty state */
|
|
145
|
+
.emptyState {
|
|
146
|
+
display: flex;
|
|
147
|
+
height: 100%;
|
|
148
|
+
width: 100%;
|
|
149
|
+
align-items: center;
|
|
150
|
+
justify-content: center;
|
|
151
|
+
color: #cbd5e1;
|
|
152
|
+
font-size: 14px;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* ===== Lightbox / enlarged preview ===== */
|
|
156
|
+
.lightboxBackdrop {
|
|
157
|
+
position: fixed;
|
|
158
|
+
inset: 0;
|
|
159
|
+
background: rgba(0, 0, 0, 0.78);
|
|
160
|
+
z-index: 1000;
|
|
161
|
+
display: flex;
|
|
162
|
+
align-items: center;
|
|
163
|
+
justify-content: center;
|
|
164
|
+
padding: 40px;
|
|
165
|
+
animation: storyFadeIn 0.18s ease-out;
|
|
166
|
+
cursor: zoom-out;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.lightboxImage {
|
|
170
|
+
max-width: min(90vw, 1100px);
|
|
171
|
+
max-height: 90vh;
|
|
172
|
+
border-radius: 18px;
|
|
173
|
+
border: 6px solid #ffffff;
|
|
174
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.55);
|
|
175
|
+
object-fit: contain;
|
|
176
|
+
background: #fff;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.lightboxClose {
|
|
180
|
+
position: fixed;
|
|
181
|
+
top: 24px;
|
|
182
|
+
right: 32px;
|
|
183
|
+
width: 44px;
|
|
184
|
+
height: 44px;
|
|
185
|
+
border-radius: 50%;
|
|
186
|
+
background: #ffffff;
|
|
187
|
+
color: #0b4c8e;
|
|
188
|
+
font-size: 24px;
|
|
189
|
+
font-weight: 900;
|
|
190
|
+
border: none;
|
|
191
|
+
cursor: pointer;
|
|
192
|
+
display: flex;
|
|
193
|
+
align-items: center;
|
|
194
|
+
justify-content: center;
|
|
195
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@keyframes storyFadeIn {
|
|
199
|
+
from { opacity: 0; }
|
|
200
|
+
to { opacity: 1; }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* ===== Responsive tightening ===== */
|
|
204
|
+
@media (max-width: 1530px) {
|
|
205
|
+
.part3Container {
|
|
206
|
+
padding: 90px 90px 130px;
|
|
207
|
+
}
|
|
208
|
+
.storyGrid {
|
|
209
|
+
gap: 20px;
|
|
210
|
+
}
|
|
211
|
+
.storyFrame {
|
|
212
|
+
max-width: 340px;
|
|
213
|
+
}
|
|
214
|
+
.storyNumber {
|
|
215
|
+
width: 36px;
|
|
216
|
+
height: 36px;
|
|
217
|
+
font-size: 18px;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@media (max-width: 1280px) {
|
|
222
|
+
.part3Container {
|
|
223
|
+
padding: 84px 70px 120px;
|
|
224
|
+
}
|
|
225
|
+
.storyGrid {
|
|
226
|
+
gap: 16px;
|
|
227
|
+
}
|
|
228
|
+
.storyFrame {
|
|
229
|
+
max-width: 300px;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* speakingVideoMap — Maps speaking question types to their AI teacher intro video URLs.
|
|
3
|
+
*
|
|
4
|
+
* These videos play muted in the floating AI teacher widget within the speaking exam layout,
|
|
5
|
+
* corresponding to the current question type being answered.
|
|
6
|
+
*/
|
|
7
|
+
import type { QuestionType } from '../../utils/question-transformers';
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the AI teacher video URL for the given question type.
|
|
10
|
+
* Returns the type-specific video or undefined if no video exists.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getTeacherVideoUrl(questionType: QuestionType): string | undefined;
|
|
13
|
+
export declare function shouldWaitForTeacherVideo(questionType: QuestionType): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={READ_DISPLAYED_CONTENT:"/speaking/video/read_displayed_content.webm",SPEAKING_DESCRIBE_IMAGE:"/speaking/video/speaking_describe_image.webm",SPONTANEOUS_QA:"/speaking/video/spontaneous_qa.webm"};export function getTeacherVideoUrl(n){return e[n]}const n=new Set(["READ_DISPLAYED_CONTENT","SPEAKING_DESCRIBE_IMAGE","SPONTANEOUS_QA"]);export function shouldWaitForTeacherVideo(e){return n.has(e)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SpeakingRecordingPreview } from './SpeakingRecordingPreview';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{SpeakingRecordingPreview}from"./SpeakingRecordingPreview";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { QuestionPart } from '../../../utils/question-transformers';
|
|
2
|
+
interface SpeakingChooseAnswerGroupRendererProps {
|
|
3
|
+
part: QuestionPart;
|
|
4
|
+
answers: Record<string, unknown>;
|
|
5
|
+
onAnswerChange: (questionId: string, value: unknown) => void;
|
|
6
|
+
isReviewMode?: boolean;
|
|
7
|
+
onExit: () => void;
|
|
8
|
+
onPartComplete?: () => void;
|
|
9
|
+
onPartBack?: () => void;
|
|
10
|
+
speakingTheme?: string;
|
|
11
|
+
teacherVideoUrl?: string;
|
|
12
|
+
onTeacherIntroPlayed?: () => void;
|
|
13
|
+
skipTeacherVideo?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function SpeakingChooseAnswerGroupRenderer(props: SpeakingChooseAnswerGroupRendererProps): import("react").JSX.Element;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsxs as e,jsx as n}from"react/jsx-runtime";import{ResolvedImage as o}from"../../../../../../components/common/ResolvedImage";import{cn as r}from"../../../../../../shared/lib/utils";import{useSpeakingRendererSetup as t}from"../../../hooks/useSpeakingRendererSetup";import{getSpeakingLayout as a}from"../../../../../../components/themes";import s from"../SpeakingReadDisplayedContent.module.css";function i({total:o,currentIndex:r,answeredIds:t,questionIds:a}){return e("div",{className:s.taskIndicator,style:{color:"#1e3a8a",textShadow:"none",fontWeight:800},children:[e("span",{children:["Question ",r+1,"/ ",o]}),n("div",{className:"flex gap-2",children:Array.from({length:o},(e,o)=>{const i=o===r,l=t.has(a[o]);return n("div",{className:`${s.taskDot} ${i?s.taskDotActive:""} ${l&&!i?s.taskDotCompleted:""}`,style:i||l?void 0:{background:"#bfdbfe"}},o)})})]})}function l({option:e,isSelected:t,isDisabled:a,onClick:s}){return n("button",{type:"button",onClick:s,disabled:a&&!t,className:r("group relative aspect-square w-[calc(33.333%-16px)] overflow-hidden rounded-xl bg-white shadow-sm cursor-pointer outline-none focus:outline-none transition-all duration-200",t?"border-[5px] border-red-400 shadow-[0_0_8px_rgba(239,68,68,0.5),0_0_16px_rgba(239,68,68,0.3)]":"border-2 border-gray-300 hover:border-gray-400 hover:shadow-md hover:scale-105",a&&!t&&"cursor-not-allowed"),children:n(o,{src:e.imageUrl,alt:e.label||"Answer option",className:"h-full w-full object-contain p-2 pointer-events-none",draggable:!1})})}export function SpeakingChooseAnswerGroupRenderer(e){const o=t({...e,hasMic:!1}),r=a(e.speakingTheme),s=o.currentQuestion?.content,d=o.currentQuestion?.questionGroup?.payload,c=s?.audioUrl??"",u=d?.options??s?.options??[],p=o.currentQuestion?e.answers[o.currentQuestion.id]:void 0,h=p?.answer??"";if(!o.currentQuestion)return null;const m=new Set(e.part.questions.map(e=>e.id).filter(n=>!!e.answers[n])),v=e.part.questions.map(e=>e.id),f=n(i,{total:e.part.questions.length,currentIndex:o.nav.currentIndex,answeredIds:m,questionIds:v});return n(r,{onExit:e.onExit,partName:e.part.name||`Part ${e.part.partNo}`,instruction:e.part.instructions||"LISTEN AND CHOOSE THE CORRECT ANSWER.",audioUrl:c,questionNumber:o.nav.questionNumberInPart,onPrev:o.handlePrev,onNext:o.handleNext,showPrev:o.nav.showPrev,showNext:o.nav.showNext,canGoPrev:o.nav.canGoPrev,canGoNext:o.nav.canGoNext,onAudioPlayingChange:o.onAudioPlayingChange,recorder:null,headerRight:f,teacherVideoUrl:e.teacherVideoUrl,onTeacherVideoEnded:e.onTeacherIntroPlayed,skipTeacherVideo:e.skipTeacherVideo,contentClassName:"h-full !p-0",children:n("div",{className:"w-full h-full overflow-y-auto pr-2",style:{scrollbarWidth:"thin",scrollbarColor:"#fff rgba(0,0,0,0.2)"},children:u.length>0?n("div",{className:"mx-auto flex max-w-[830px] flex-wrap justify-center gap-6 pb-6 pt-17",children:u.map(r=>n(l,{option:r,isSelected:h===r.id,isDisabled:e.isReviewMode||!1,onClick:()=>{return n=r.id,void(o.currentQuestion&&!e.isReviewMode&&e.onAnswerChange(o.currentQuestion.id,{answer:n}));var n}},r.id))}):n("div",{className:"flex h-48 items-center justify-center text-sm text-stone-400",children:"No options available"})})})}
|
package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseObjectsRenderer.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { QuestionPart } from '../../../utils/question-transformers';
|
|
2
|
+
interface SpeakingChooseObjectsRendererProps {
|
|
3
|
+
part: QuestionPart;
|
|
4
|
+
answers: Record<string, unknown>;
|
|
5
|
+
onAnswerChange: (questionId: string, value: unknown) => void;
|
|
6
|
+
isReviewMode?: boolean;
|
|
7
|
+
onExit: () => void;
|
|
8
|
+
onPartComplete?: () => void;
|
|
9
|
+
onPartBack?: () => void;
|
|
10
|
+
speakingTheme?: string;
|
|
11
|
+
teacherVideoUrl?: string;
|
|
12
|
+
onTeacherIntroPlayed?: () => void;
|
|
13
|
+
skipTeacherVideo?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function SpeakingChooseObjectsRenderer(props: SpeakingChooseObjectsRendererProps): import("react").JSX.Element;
|
|
16
|
+
export {};
|
package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseObjectsRenderer.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{usePresignedFileUrl as n}from"../../../../../../shared/lib/hooks";import{useSpeakingRendererSetup as r}from"../../../hooks/useSpeakingRendererSetup";import{getSpeakingLayout as o}from"../../../../../../components/themes";import i from"../FindObjectInPicture.module.css";import a from"../SpeakingReadDisplayedContent.module.css";function s({total:n,currentIndex:r,answeredIds:o,questionIds:i}){return e("div",{className:a.taskIndicator,style:{color:"#1e3a8a",textShadow:"none",fontWeight:800},children:[e("span",{children:["Question ",r+1,"/ ",n]}),t("div",{className:"flex gap-2",children:Array.from({length:n},(e,n)=>{const s=n===r,c=o.has(i[n]);return t("div",{className:`${a.taskDot} ${s?a.taskDotActive:""} ${c&&!s?a.taskDotCompleted:""}`,style:s||c?void 0:{background:"#bfdbfe"}},n)})})]})}function c({node:e,isSelected:r,isDisabled:o,onClick:a}){const{previewUrl:s}=n(e.imageUrl||"");return t("button",{type:"button",onClick:a,disabled:o,className:`${i.objectItem} ${r?i.objectItemSelected:""}`,style:{left:`${e.x}%`,top:`${e.y}%`,width:`${e.width}%`,height:`${e.height}%`},children:s?t("img",{src:s,alt:e.label,className:i.objectItemImageBorder,style:{height:"100%",width:"100%"},draggable:!1}):t("div",{style:{display:"flex",height:"100%",width:"100%",alignItems:"center",justifyContent:"center",background:"rgba(255,255,255,0.5)",fontSize:"12px",color:"#999"},children:e.label})})}export function SpeakingChooseObjectsRenderer(a){const d=r({...a,hasMic:!1}),l=o(a.speakingTheme),u=d.currentQuestion?.content,h=d.currentQuestion;let m=h?.questionGroup?.payload||h?.question_group?.payload;if("string"==typeof m)try{m=JSON.parse(m)}catch{m={}}const p=u?.audioUrl??"",g=m?.backgroundImageUrl??"",b=m?.objectNodes??[],v=d.currentQuestion?a.answers[d.currentQuestion.id]:void 0,f=v?.objectId??"",{previewUrl:x}=n(g);if(!d.currentQuestion)return null;const y=new Set(a.part.questions.map(e=>e.id).filter(e=>!!a.answers[e])),N=a.part.questions.map(e=>e.id),k=t(s,{total:a.part.questions.length,currentIndex:d.nav.currentIndex,answeredIds:y,questionIds:N});return t(l,{onExit:a.onExit,partName:a.part.name||`Part ${a.part.partNo}`,instruction:a.part.instructions||"Choose the correct objects in the Scene picture:",audioUrl:p,questionNumber:d.nav.questionNumberInPart,onPrev:d.handlePrev,onNext:d.handleNext,showPrev:d.nav.showPrev,showNext:d.nav.showNext,canGoPrev:d.nav.canGoPrev,canGoNext:d.nav.canGoNext,onAudioPlayingChange:d.onAudioPlayingChange,recorder:null,headerRight:k,teacherVideoUrl:a.teacherVideoUrl,onTeacherVideoEnded:a.onTeacherIntroPlayed,skipTeacherVideo:a.skipTeacherVideo,contentClassName:"!p-0",children:t("div",{className:i.findObjectContainer,children:e("div",{className:i.objectBackground,children:[t("div",{className:i.imageBackground,children:x?t("img",{alt:"Scene",src:x,draggable:!1}):t("div",{style:{display:"flex",height:"100%",width:"100%",alignItems:"center",justifyContent:"center",color:"#999"},children:"Loading..."})}),b.map(e=>t(c,{node:e,isSelected:f===e.id,isDisabled:a.isReviewMode||!1,onClick:()=>{return t=e.id,void(d.currentQuestion&&!a.isReviewMode&&a.onAnswerChange(d.currentQuestion.id,{objectId:t}));var t}},e.id))]})})})}
|
package/dist/components/exams/take/components/speaking/renderers/SpeakingCompareImagesRenderer.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { QuestionPart } from '../../../utils/question-transformers';
|
|
2
|
+
interface SpeakingCompareImagesRendererProps {
|
|
3
|
+
part: QuestionPart;
|
|
4
|
+
answers: Record<string, unknown>;
|
|
5
|
+
onAnswerChange: (questionId: string, value: unknown) => void;
|
|
6
|
+
isReviewMode?: boolean;
|
|
7
|
+
onExit: () => void;
|
|
8
|
+
onPartComplete?: () => void;
|
|
9
|
+
onPartBack?: () => void;
|
|
10
|
+
speakingTheme?: string;
|
|
11
|
+
teacherVideoUrl?: string;
|
|
12
|
+
onTeacherIntroPlayed?: () => void;
|
|
13
|
+
skipTeacherVideo?: boolean;
|
|
14
|
+
waitForTeacherVideo?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function SpeakingCompareImagesRenderer(props: SpeakingCompareImagesRendererProps): import("react").JSX.Element;
|
|
17
|
+
export {};
|
package/dist/components/exams/take/components/speaking/renderers/SpeakingCompareImagesRenderer.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as r,Fragment as a}from"react/jsx-runtime";import{ResolvedImage as n}from"../../../../../../components/common/ResolvedImage";import{useSpeakingRendererSetup as t}from"../../../hooks/useSpeakingRendererSetup";import{getSpeakingLayout as o}from"../../../../../../components/themes";export function SpeakingCompareImagesRenderer(r){const a=t({...r,maxDurationMs:3e4}),n=o(r.speakingTheme),d=a.currentQuestion?.content,l=a.currentQuestion?.questionGroup?.payload;if(!a.currentQuestion)return null;const s=d?.audioUrl??"",c=l?.candidateImageUrl??"",m=l?.examinerImageUrl??"";return e(n,{onExit:r.onExit,partName:r.part.name||`Part ${r.part.partNo}`,instruction:r.part.instructions||"LOOK AT THE TWO PICTURES. THEY LOOK THE SAME BUT SOME THINGS ARE DIFFERENT.",audioUrl:s,questionNumber:a.nav.questionNumberInPart,onPrev:a.handlePrev,onNext:a.handleNext,showPrev:a.nav.showPrev,showNext:a.nav.showNext,canGoPrev:a.nav.canGoPrev,canGoNext:a.nav.canGoNext,onAudioPlayingChange:a.onAudioPlayingChange,recorder:r.isReviewMode?null:a.recorder,showExistingBadge:a.showExistingBadge,teacherVideoUrl:r.teacherVideoUrl,onTeacherVideoEnded:r.onTeacherIntroPlayed,skipTeacherVideo:r.skipTeacherVideo,waitForTeacherVideo:r.waitForTeacherVideo,children:e("div",{className:"flex h-full w-full flex-col items-center gap-8 overflow-y-auto overflow-x-hidden px-4 py-18 scrollbar-thin",children:e(i,{candidateImageUrl:c,examinerImageUrl:m,showExistingBadge:a.showExistingBadge})})})}function i({candidateImageUrl:t,examinerImageUrl:o,showExistingBadge:i}){return r(a,{children:[i&&r("div",{className:"absolute right-4 top-4 z-10 flex items-center gap-2 rounded-full border-2 border-white bg-green-500 px-4 py-1 text-sm font-bold text-white shadow-md",children:[e("span",{className:"h-2.5 w-2.5 animate-pulse rounded-full bg-white"}),"Đã ghi âm"]}),r("div",{className:"relative flex w-full max-w-[1000px] flex-col items-center",children:[e("div",{className:"z-10 -mb-3 flex h-8 min-w-[200px] items-center justify-center rounded-xl bg-[#1e3458] px-6 text-[13px] font-bold uppercase tracking-[1.5px] text-white shadow-md md:-mb-4 md:h-10 md:text-sm",children:"Candidate's copy"}),e("div",{className:"relative aspect-[3.3] w-full overflow-hidden rounded-xl border-4 p-[10px] border-[#b45309] bg-white shadow-md",children:e(n,{src:t,alt:"Candidate's copy",className:"pointer-events-none h-full w-full object-cover rounded-xl",draggable:!1})})]}),r("div",{className:"relative flex w-full max-w-[1000px] flex-col items-center pb-8",children:[e("div",{className:"z-10 -mb-3 flex h-8 min-w-[200px] items-center justify-center rounded-xl bg-[#1e3458] px-6 text-[13px] font-bold uppercase tracking-[1.5px] text-white shadow-md md:-mb-4 md:h-10 md:text-sm",children:"Examiner's copy"}),e("div",{className:"relative aspect-[3.3] w-full overflow-hidden rounded-xl border-4 p-[10px] border-[#1e3a8a] bg-white shadow-md",children:e(n,{src:o,alt:"Examiner's copy",className:"pointer-events-none h-full w-full object-cover rounded-xl",draggable:!1})})]})]})}
|
package/dist/components/exams/take/components/speaking/renderers/SpeakingConversationRenderer.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { QuestionPart } from '../../../utils/question-transformers';
|
|
2
|
+
interface SpeakingConversationRendererProps {
|
|
3
|
+
part: QuestionPart;
|
|
4
|
+
answers: Record<string, unknown>;
|
|
5
|
+
onAnswerChange: (questionId: string, value: unknown) => void;
|
|
6
|
+
isReviewMode?: boolean;
|
|
7
|
+
onExit: () => void;
|
|
8
|
+
onPartComplete?: () => void;
|
|
9
|
+
onPartBack?: () => void;
|
|
10
|
+
speakingTheme?: string;
|
|
11
|
+
teacherVideoUrl?: string;
|
|
12
|
+
onTeacherIntroPlayed?: () => void;
|
|
13
|
+
skipTeacherVideo?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function SpeakingConversationRenderer(props: SpeakingConversationRendererProps): import("react").JSX.Element;
|
|
16
|
+
export {};
|
package/dist/components/exams/take/components/speaking/renderers/SpeakingConversationRenderer.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as a}from"react";import s from"next/image";import{Pause as n,Play as r}from"lucide-react";import{ResolvedImage as i}from"../../../../../../components/common/ResolvedImage";import{useSpeakingRendererSetup as l}from"../../../hooks/useSpeakingRendererSetup";import{useSpeakingConversationAudio as o}from"../../../hooks/useSpeakingConversationAudio";import{getSpeakingLayout as c}from"../../../../../../components/themes";import d from"../../../../../../components/themes/spaceship/assets/styles/SpaceshipLayout.module.css";import p from"../../../../../../components/themes/spaceship/assets/images/big-blue-badge-sunset.png";import m from"../../../../../../components/themes/spaceship/assets/images/teacher-play-sunset.png";import h from"../../../../../../components/themes/spaceship/assets/images/question-badge-sunset.png";import u from"../../../../../../components/themes/spaceship/assets/images/red-badge-sunset.png";import x from"../../../../../../components/themes/spaceship/assets/images/blue-badge-sunset.png";import g from"../../../../../../components/themes/spaceship/assets/images/red-wrapper-sunset.png";import f from"../../../../../../components/themes/spaceship/assets/images/blue-wrapper-sunset.png";import N from"../../../../../../components/themes/spaceship/assets/images/robot-avatar.png";import v from"../../../../../../components/themes/spaceship/assets/images/student-avatar.png";import y from"../../../../../../components/themes/spaceship/assets/images/next-small.webp";function b(e){if(!isFinite(e)||e<0)return"0:00";return`${Math.floor(e/60)}:${Math.floor(e%60).toString().padStart(2,"0")}`}function w({phase:a,isPlaying:i,togglePlayPause:l,partNumber:o,partnerName:c,currentTime:h,duration:u}){const x="playing-partner"===a?c||"Bạn thi":`PART ${o}`,g=u>0?h/u*100:0;return e("div",{className:d.examAudioContainer,children:t("div",{className:d.bigBlueBadge,children:[e(s,{src:p,alt:"Audio Badge",className:d.bigBlueBadgeBg,priority:!0}),e("div",{className:d.audioBarContent,children:t("div",{className:d.audioBarInner,children:[e("span",{className:d.partLabel,children:x}),t("div",{className:d.teacherAvatarContainer,onClick:l,title:i?"Tạm dừng":"Phát",children:[e("img",{src:m.src,alt:"Speaker",className:d.teacherPlayIcon}),e("div",{className:"absolute inset-0 flex items-center justify-center",children:i?e(n,{className:"h-5 w-5 text-white drop-shadow-md",fill:"currentColor"}):e(r,{className:"h-5 w-5 text-white drop-shadow-md ml-0.5",fill:"currentColor"})})]}),t("div",{className:d.audioControlsWrapper,children:[t("span",{className:d.audioTime,children:["idle"===a&&"0:00 / 0:00",i&&`${b(h)} / ${b(u)}`,"ready"===a&&`${b(u)} / ${b(u)}`]}),e("div",{className:d.sliderTrack,children:e("div",{className:d.sliderFill,style:{width:`${g}%`,transition:"width 0.25s linear"}})})]})]})})]})})}function P({text:n}){const[r,i]=a(!0);return n?e("div",{className:"flex flex-col items-center w-full",style:{maxWidth:"882px"},children:t("div",r?{className:"relative flex flex-col justify-center items-center",style:{width:"882px",maxWidth:"90%",paddingLeft:"77px",paddingRight:"77px",paddingTop:"26px",paddingBottom:"26px",backgroundColor:"rgba(232, 136, 154, 0.15)",borderRadius:"20px"},children:[t("div",{className:"absolute cursor-pointer",style:{top:"-19px"},onClick:()=>i(!1),children:[e(s,{src:h,alt:"",style:{width:"169px",height:"38px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center select-none",children:e("span",{className:"font-normal text-center leading-5 text-white",style:{fontSize:"18px"},children:"Ấn câu hỏi"})})]}),e("p",{className:"text-black font-bold leading-[26px] text-center m-0",style:{fontSize:"18px",fontFamily:'"Open Sans", sans-serif'},children:n})]}:{className:"relative cursor-pointer",onClick:()=>i(!0),children:[e(s,{src:h,alt:"",style:{width:"169px",height:"38px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center select-none",children:e("span",{className:"font-normal text-center leading-5 text-white",style:{fontSize:"18px"},children:"Hiện câu hỏi"})})]})}):null}function S({images:a}){if(!a||0===a.length)return null;const s=1===a.length,n=s?"grid-cols-1":2===a.length||4===a.length?"grid-cols-2":"grid-cols-3";return e("div",{className:`grid ${n} gap-4 w-full`,style:{maxWidth:s?"650px":"800px",margin:"0 auto"},children:a.map(a=>t("div",{className:"flex flex-col items-center gap-2",children:[e("div",{className:`relative w-full ${s?"":"aspect-square"} flex justify-center items-center rounded-xl overflow-hidden border-2 border-white/40 shadow-md bg-white/20`,children:e(i,{src:a.url,alt:a.label||"Image",className:"object-contain pointer-events-none "+(s?"max-h-[350px] w-auto":"w-full h-full p-1"),draggable:!1})}),a.label&&e("span",{className:"text-center font-bold",style:{fontSize:"14px",color:"#333"},children:a.label})]},a.id))})}function C({partnerName:a,partnerAvatarUrl:n,studentName:r,activeCharacter:l,isPartnerQuestion:o}){const c="partner"===l,d="student"===l;return t("div",{className:"flex justify-between select-none",style:{width:"990px",maxWidth:"95%",paddingBottom:"10px",paddingLeft:"20px",paddingRight:"20px"},children:[t("div",{className:"relative select-none",style:{opacity:c?1:.55},children:[t("div",{className:"relative flex",children:[e(s,{src:u,alt:"",style:{height:"57px",width:"258px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center",style:{paddingTop:"12px"},children:e("p",{className:"m-0 truncate select-none text-white font-normal text-center leading-5",style:{fontSize:"18px",paddingLeft:"60px",paddingRight:"60px"},children:a||"Bạn thi"})})]}),t("div",{className:"absolute",style:{top:"7px",right:"-58px"},children:[e(s,{src:g,alt:"",className:"relative",style:{width:"115px",height:"84px",zIndex:0}}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:t("div",{className:"relative",style:{width:"68px",height:"68px"},children:[n?e(i,{src:n,alt:a||"Partner",className:"object-cover rounded-full select-none",style:{width:"68px",height:"68px"},draggable:!1}):e(s,{src:N,alt:a||"Partner",width:68,height:68,className:"object-cover rounded-full select-none",draggable:!1}),c&&e("div",{className:"absolute inset-0 rounded-full border-4 border-yellow-400 shadow-[0_0_12px_4px_rgba(250,204,21,0.6)]"})]})})]})]}),t("div",{className:"relative select-none",style:{opacity:d||!o?1:.55},children:[t("div",{className:"relative flex",children:[e(s,{src:x,alt:"",style:{height:"57px",width:"258px"}}),e("div",{className:"absolute inset-0 flex justify-center items-center",style:{paddingTop:"12px"},children:e("p",{className:"m-0 truncate select-none text-white font-normal text-center leading-5",style:{fontSize:"18px",paddingLeft:"60px",paddingRight:"60px"},children:r||"Bạn"})})]}),t("div",{className:"absolute",style:{top:"7px",left:"-58px"},children:[e(s,{src:f,alt:"",className:"relative",style:{width:"115px",height:"84px",zIndex:0}}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:t("div",{className:"relative",style:{width:"68px",height:"68px"},children:[e(s,{src:v,alt:r||"Bạn",width:68,height:68,className:"object-cover rounded-full select-none",draggable:!1}),d&&e("div",{className:"absolute inset-0 rounded-full border-4 border-sky-400 shadow-[0_0_12px_4px_rgba(56,189,248,0.6)]"})]})})]})]})]})}function A({audioReady:a,onNext:n}){return a?e("div",{className:"flex flex-col items-center text-center",style:{maxWidth:"291px",marginTop:"-10px",marginBottom:"10px"},children:t("div",{className:"flex items-center gap-1",children:[e("p",{className:"m-0",style:{color:"#333",fontSize:"13px"},children:"Ấn nút"}),e("div",{className:"cursor-pointer",onClick:n,children:e(s,{src:y,alt:"next",width:30,height:30})}),e("p",{className:"m-0",style:{color:"#333",fontSize:"13px"},children:"để tiếp tục."})]})}):null}export function SpeakingConversationRenderer(s){const[n,r]=a(!1),i=l({...s,maxDurationMs:3e4,hasMic:!0}),d=c("SPACESHIP"),p=i.currentQuestion?.content,m=i.currentQuestion?.questionGroup?.payload,h="PARTNER"===p?.responder,u=o({interlocutorAudioUrl:p?.interlocutorAudioUrl,partnerAudioUrl:p?.partnerAudioUrl,onSequenceComplete:()=>r(!0)});if(!i.currentQuestion||!p)return null;const x="playing-interlocutor"===u.phase?"interlocutor":"playing-partner"===u.phase||h?"partner":n?"student":"none",g=()=>{r(!1),i.handleNext()};return e(d,{onExit:s.onExit,partName:s.part.name||`Part ${s.part.partNo}`,instruction:s.part.instructions||"SPEAKING CONVERSATION",audioUrl:"",questionNumber:i.nav.questionNumberInPart,onPrev:()=>{r(!1),i.handlePrev()},onNext:g,showPrev:i.nav.showPrev,showNext:i.nav.showNext,canGoPrev:i.nav.canGoPrev,canGoNext:i.nav.canGoNext,onAudioPlayingChange:i.onAudioPlayingChange,recorder:s.isReviewMode||h?null:i.recorder,showExistingBadge:!h&&i.showExistingBadge,teacherVideoUrl:s.teacherVideoUrl,onTeacherVideoEnded:s.onTeacherIntroPlayed,skipTeacherVideo:s.skipTeacherVideo,hideAudioBar:!0,hideFooterTitle:h,children:t("div",{className:"w-full h-full flex flex-col items-center relative",style:{paddingBottom:h?"0":"50px"},children:[e(w,{phase:u.phase,isPlaying:u.isPlaying,togglePlayPause:u.togglePlayPause,partNumber:i.nav.currentPartNo,partnerName:m?.partnerName,currentTime:u.currentTime,duration:u.duration}),e(P,{text:p.questionText}),m?.images&&m.images.length>0&&e("div",{className:"mt-4 w-full flex justify-center",children:e(S,{images:m.images})}),e("div",{className:"flex-1"}),h&&e(A,{audioReady:n,onNext:g}),e(C,{partnerName:m?.partnerName,partnerAvatarUrl:m?.partnerAvatarUrl,activeCharacter:x,isPartnerQuestion:h})]},i.currentQuestion.id)})}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { QuestionPart } from '../../../utils/question-transformers';
|
|
2
|
+
interface SpeakingCueCardRendererProps {
|
|
3
|
+
part: QuestionPart;
|
|
4
|
+
answers: Record<string, unknown>;
|
|
5
|
+
onAnswerChange: (questionId: string, value: unknown) => void;
|
|
6
|
+
isReviewMode?: boolean;
|
|
7
|
+
onExit: () => void;
|
|
8
|
+
onPartComplete?: () => void;
|
|
9
|
+
onPartBack?: () => void;
|
|
10
|
+
speakingTheme?: string;
|
|
11
|
+
teacherVideoUrl?: string;
|
|
12
|
+
onTeacherIntroPlayed?: () => void;
|
|
13
|
+
skipTeacherVideo?: boolean;
|
|
14
|
+
waitForTeacherVideo?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function SpeakingCueCardRenderer(props: SpeakingCueCardRendererProps): import("react").JSX.Element;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsxs as e,jsx as n}from"react/jsx-runtime";import{useEffect as t,useRef as r,useState as o}from"react";import{useSpeakingRendererSetup as a}from"../../../hooks/useSpeakingRendererSetup";import{getSpeakingLayout as i}from"../../../../../../components/themes";import s from"../../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import l from"next/image";import d from"../../../../../../components/themes/summer-sky/assets/images/mic_ver2_icon.png";import c from"../../../../../../components/themes/summer-sky/assets/images/stop_audio_ver2_icon.png";import p from"../../../../../../components/themes/summer-sky/assets/images/audio_ver2_icon.png";import u from"../../../../../../components/themes/summer-sky/assets/images/pause_audio_ver2_icon.png";import m from"../../../../../../components/themes/summer-sky/assets/images/lock_mic_ver2_icon.png";import h from"../SpeakingReadDisplayedContent.module.css";function g({total:t,currentIndex:r,answeredIds:o,questionIds:a}){return e("div",{className:h.taskIndicator,style:{color:"#78350f",textShadow:"none",fontWeight:800},children:[e("span",{children:["Question ",r+1,"/ ",t]}),n("div",{className:"flex gap-2",children:Array.from({length:t},(e,t)=>{const i=t===r,s=o.has(a[t]);return n("div",{className:`${h.taskDot} ${i?h.taskDotActive:""} ${s&&!i?h.taskDotCompleted:""}`},t)})})]})}function x({total:t,currentIndex:r,answeredIds:o,questionIds:a}){return e("div",{className:"flex items-center gap-2 font-bold text-[#78350f] font-['Quicksand'] z-10",children:[e("span",{className:"text-sm",children:["Question ",r+1,"/ ",t]}),n("div",{className:"flex gap-1.5",children:Array.from({length:t},(e,t)=>{const i=t===r,s=o.has(a[t]);return n("div",{className:"w-2.5 h-2.5 rounded-full "+(i?"bg-[#FF9900] scale-125 shadow-sm":s?"bg-[#16CA3B]":"bg-white/60")},t)})})]})}export function SpeakingCueCardRenderer(m){const h=a({...m,maxDurationMs:12e4}),f=i(m.speakingTheme),v=h.currentQuestion?.content,w=v?.speakingTimeSeconds??120;t(()=>{h.recorder&&(h.recorder.maxDurationMs=1e3*w)},[w,h.recorder]);const b=r(null),[y,N]=o(!1);if(t(()=>{const e=b.current;if(!e)return;const n=()=>{N(!0),h.onAudioPlayingChange?.(!0)},t=()=>{N(!1),h.onAudioPlayingChange?.(!1)},r=()=>{N(!1),h.onAudioPlayingChange?.(!1)};return e.addEventListener("play",n),e.addEventListener("pause",t),e.addEventListener("ended",r),()=>{e.removeEventListener("play",n),e.removeEventListener("pause",t),e.removeEventListener("ended",r),h.onAudioPlayingChange?.(!1)}},[h.recorder?.previewUrl,h.onAudioPlayingChange]),!h.currentQuestion||!v)return null;const k=new Set(m.part.questions.map(e=>e.id).filter(e=>!!m.answers[e])),_=m.part.questions.map(e=>e.id);if(m.speakingTheme&&"CAMBRIDGE_YLE"!==m.speakingTheme){const t=n(g,{total:m.part.questions.length,currentIndex:h.nav.currentIndex,answeredIds:k,questionIds:_});return e(f,{onExit:m.onExit,partName:m.part.name||`Part ${m.part.partNo}`,instruction:m.part.instructions||"READ CUE CARD AND SPEAK",audioUrl:"",questionNumber:h.nav.questionNumberInPart,onPrev:h.handlePrev,onNext:h.handleNext,showPrev:h.nav.showPrev,showNext:h.nav.showNext,canGoPrev:h.nav.canGoPrev,canGoNext:h.nav.canGoNext,onAudioPlayingChange:h.onAudioPlayingChange,recorder:m.isReviewMode?null:h.recorder,showExistingBadge:h.showExistingBadge,headerRight:t,teacherVideoUrl:m.teacherVideoUrl,onTeacherVideoEnded:m.onTeacherIntroPlayed,skipTeacherVideo:m.skipTeacherVideo,waitForTeacherVideo:m.waitForTeacherVideo,children:[n("div",{className:"w-full h-full flex flex-col items-center relative",children:n("div",{className:"w-full flex-1",style:{minHeight:0},children:n("div",{className:"mx-auto",style:{width:"850px",maxWidth:"95%",height:"calc(100% - 80px)"},children:n("div",{className:"w-full h-full flex flex-col items-center justify-center",children:e("div",{className:"relative flex flex-col justify-start",style:{width:"100%",paddingLeft:"50px",paddingRight:"50px",paddingTop:"16px",paddingBottom:"16px"},children:[h.showExistingBadge&&e("div",{className:"absolute right-12 top-4 z-10 rounded-full bg-green-500 px-4 py-1.5 flex items-center gap-2 text-sm font-bold text-white shadow-md border-2 border-white",children:[n("span",{className:"h-2.5 w-2.5 rounded-full bg-white animate-pulse"}),"Đã ghi âm"]}),n("div",{className:"cue-card-content",dangerouslySetInnerHTML:{__html:v.cueCardHtml},style:{fontSize:"22px",fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',fontWeight:600,lineHeight:"35px",letterSpacing:"-0.01em",color:"#2C38B6"}})]})})})})}),n("style",{jsx:!0,global:!0,children:"\n .cue-card-content p {\n margin: 0 0 12px 0;\n }\n .cue-card-content p:last-child {\n margin-bottom: 0;\n }\n .cue-card-content strong {\n font-weight: 700;\n font-size: 24px;\n color: #1a237e;\n line-height: 37px;\n }\n .cue-card-content ul {\n margin: 16px 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n .cue-card-content ul li {\n position: relative;\n padding: 9px 15px 9px 34px;\n font-size: 19px;\n line-height: 28px;\n font-weight: 500;\n color: #283593;\n background: rgba(44, 56, 182, 0.06);\n border-radius: 12px;\n border-left: 3px solid #5c6bc0;\n }\n .cue-card-content ul li::before {\n content: '';\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #5c6bc0;\n }\n .cue-card-content ul li p {\n margin: 0;\n }\n "})]})}return e("div",{className:"flex flex-col w-full h-full relative",style:{background:"linear-gradient(180deg, #E6F3FF 0%, #FFFFFF 100%)"},children:[e("div",{className:"relative w-full flex justify-between items-start pt-6 px-6 z-20 shrink-0",children:[n("div",{className:"flex-1"}),n("div",{className:"flex-none drop-shadow-md",children:n(s,{partNumber:m.part.partNo,questionCount:m.part.questions.length,partName:m.part.name||`Part ${m.part.partNo}`})}),n("div",{className:"flex-1 flex justify-end mt-2 z-20",children:n(x,{total:m.part.questions.length,currentIndex:h.nav.currentIndex,answeredIds:k,questionIds:_})})]}),e("div",{className:"flex-1 w-full flex flex-col items-center min-h-0 px-4 pb-6 pt-8",children:[n("div",{className:"flex-1 w-full flex flex-col items-center min-h-0 relative mb-6",children:e("div",{className:"w-full max-w-[850px] relative bg-white/60 backdrop-blur-md rounded-2xl shadow-[0_2px_15px_rgba(0,0,0,0.04)] border border-blue-50 p-8",children:[h.showExistingBadge&&e("div",{className:"absolute right-4 top-0 z-10 rounded-full bg-green-500 px-4 py-1.5 flex items-center gap-2 text-sm font-bold text-white shadow-lg border-2 border-white transform -translate-y-1/2",children:[n("span",{className:"h-2.5 w-2.5 rounded-full bg-white animate-pulse"}),"Đã ghi âm"]}),n("div",{className:"cue-card-content",dangerouslySetInnerHTML:{__html:v.cueCardHtml},style:{fontSize:"22px",fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',fontWeight:600,lineHeight:"35px",letterSpacing:"-0.01em",color:"#2C38B6"}})]})}),h.recorder&&!m.isReviewMode&&e("div",{className:"shrink-0 flex flex-col items-center z-50 gap-3",children:[n("div",{className:"bg-white rounded-[100px] shadow-[0_4px_10px_rgba(0,0,0,0.1)] whitespace-nowrap flex items-center justify-center",style:{padding:"10px 30px",color:"recording"===h.recorder.status?"#FF4D4D":["recorded","uploading","uploaded"].includes(h.recorder.status)?"#16CA3B":"#343C55",fontSize:"18px",fontFamily:'"Quicksand", sans-serif',fontWeight:700,lineHeight:"100%",letterSpacing:"-0.01em"},children:"recording"===h.recorder.status?"Ấn lần nữa để lưu kết quả":["recorded","uploading","uploaded"].includes(h.recorder.status)?"Câu trả lời đã được ghi nhận !":"Ấn biểu tượng Micro để trả lời"}),n("div",{className:"relative flex flex-col items-center",children:"recording"===h.recorder.status?e("div",{className:"relative flex flex-col justify-center items-center cursor-pointer drop-shadow-[0_0_15px_rgba(255,100,100,0.8)] transition-transform hover:scale-[1.05] active:scale-[0.95]",onClick:h.recorder.stopRecording,children:[n(l,{src:c,alt:"stop audio",className:"animate-pulse",style:{width:"120px",height:"120px"}}),e("span",{className:"absolute text-white text-[16px] font-bold font-['Quicksand']",style:{bottom:"30px"},children:[Math.floor(h.recorder.remainingSeconds/60),":",(h.recorder.remainingSeconds%60).toString().padStart(2,"0")]})]}):n(l,{src:["recorded","uploading","uploaded"].includes(h.recorder.status)?y?u:p:d,alt:"micro",className:"transition-transform cursor-pointer hover:scale-[1.05] active:scale-[0.95]",style:{width:"120px",height:"120px"},onClick:()=>{if("recording"===h.recorder?.status)h.recorder.stopRecording();else if("idle"===h.recorder?.status||"error"===h.recorder?.status)h.recorder.startRecording();else if("uploaded"===h.recorder?.status||"recorded"===h.recorder?.status){const e=b.current;e&&(y?e.pause():e.play().catch(console.error))}}})}),h.recorder.previewUrl&&n("audio",{ref:b,src:h.recorder.previewUrl})]})]}),n("style",{jsx:!0,global:!0,children:"\n .cue-card-content p {\n margin: 0 0 12px 0;\n }\n .cue-card-content p:last-child {\n margin-bottom: 0;\n }\n .cue-card-content strong {\n font-weight: 700;\n font-size: 24px;\n color: #1a237e;\n line-height: 37px;\n }\n .cue-card-content ul {\n margin: 16px 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n .cue-card-content ul li {\n position: relative;\n padding: 9px 15px 9px 34px;\n font-size: 19px;\n line-height: 28px;\n font-weight: 500;\n color: #283593;\n background: rgba(44, 56, 182, 0.06);\n border-radius: 12px;\n border-left: 3px solid #5c6bc0;\n }\n .cue-card-content ul li::before {\n content: '';\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #5c6bc0;\n }\n .cue-card-content ul li p {\n margin: 0;\n }\n "})]})}
|