@tinyweb_dev/oe-exam-sdk 0.1.13 → 0.1.15
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/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -1
- package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -1
- package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.d.ts +5 -1
- package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.d.ts +5 -2
- package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationPassagePanel.d.ts +16 -2
- package/dist/components/themes/english-certification/EnglishCertificationPassagePanel.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionItem.d.ts +5 -6
- package/dist/components/themes/english-certification/EnglishCertificationQuestionItem.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.d.ts +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.d.ts +5 -1
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -1
- package/dist/components/themes/english-certification/grouped-question-utils.d.ts +17 -0
- package/dist/components/themes/english-certification/grouped-question-utils.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{useMemo as t}from"react";import{ResolvedImage as r}from"../../../components/common/ResolvedImage";import{cn as a}from"../../../shared/lib/utils";import{transformAnswerTheQuestion as
|
|
1
|
+
"use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{useMemo as t}from"react";import{ResolvedImage as r}from"../../../components/common/ResolvedImage";import{cn as a}from"../../../shared/lib/utils";import{transformAnswerTheQuestion as n}from"../../../components/exams/take/exam-taking.utils";import{englishCertQuestionDomId as i}from"./english-cert-scroll";export function EcAnswerTheQuestion({part:l,answers:o,onAnswerChange:d,isReviewMode:c=!1}){const{questions:m,imageUrl:x,title:p}=t(()=>n(l.questions),[l.questions]);return s("div",{className:"flex flex-col gap-4",children:[x&&e("div",{className:"flex items-center justify-center",children:e(r,{src:x,alt:p||"Group image",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),e("div",{className:"flex flex-col gap-3",children:m.map(t=>{const n=o[t.id]?.answer??t.exampleAnswer??"";return e("div",{id:i(t.id),className:a("scroll-mt-24 rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",t.isExample&&"opacity-90"),children:s("div",{className:"flex items-start gap-3",children:[e("span",{className:"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:t.questionNumber}),s("div",{className:"min-w-0 flex-1 space-y-2",children:[t.imageUrl&&e(r,{src:t.imageUrl,alt:`Question ${t.questionNumber}`,className:"max-h-28 w-auto rounded object-contain"}),e("p",{className:"text-sm text-[#0f1730]",children:t.question}),s("div",{className:"flex flex-wrap items-center gap-2",children:[t.prefixText&&e("span",{className:"text-sm text-[#64748b]",children:t.prefixText}),t.isExample?e("span",{className:"rounded-lg border border-[#b9edc8] bg-[#ddf8e7] px-3 py-1.5 text-sm font-semibold text-[#15803d]",children:t.exampleAnswer}):e("input",{type:"text",value:n,disabled:c,placeholder:"Enter your answer…",onChange:e=>{return s=t.id,r=e.target.value,void d(s,{answer:r});var s,r},className:a("min-w-[200px] flex-1 rounded-lg border-2 border-[#9cc4f5] bg-white px-3 py-2 text-sm font-medium text-[#0f1730] outline-none transition-all focus:border-[#1167e8]",c&&"cursor-not-allowed opacity-70")}),t.suffixText&&e("span",{className:"text-sm text-[#64748b]",children:t.suffixText})]}),t.suggestedAnswers&&t.suggestedAnswers.length>0&&e("div",{className:"flex flex-wrap gap-1.5",children:t.suggestedAnswers.map((s,r)=>e("span",{className:"rounded-full border border-[#e2ecf8] bg-[#f4f9ff] px-2.5 py-0.5 text-xs text-[#0b57d0]",children:s},`${t.id}-sa-${r}`))})]})]})},t.id)})})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as n}from"../../../components/common/ResolvedImage";import{cn as s}from"../../../shared/lib/utils";import{transformMatchByWritingAnswer as a}from"../../../components/exams/take/exam-taking.utils";import{englishCertQuestionDomId as o}from"./english-cert-scroll";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as n}from"../../../components/common/ResolvedImage";import{cn as s}from"../../../shared/lib/utils";import{transformMatchByWritingAnswer as a}from"../../../components/exams/take/exam-taking.utils";import{englishCertQuestionDomId as o}from"./english-cert-scroll";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),l={empty:"bg-[#eef3fb] text-[#94a3b8] border border-[#dbe5f2]",filled:"bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-white border border-transparent",correct:"bg-[#16a34a] text-white border border-transparent",wrong:"bg-[#ef4444] text-white border border-transparent"};function d({letter:t,tone:r}){return e("span",{className:s("flex h-9 w-9 shrink-0 items-center justify-center rounded-xl text-base font-bold transition-colors",l[r]),children:t||"—"})}export function EcMatchByWritingAnswer({part:l,answers:c,onAnswerChange:m,isReviewMode:f=!1}){const{questions:b,options:p,groupImageUrl:x}=r(()=>a(l.questions),[l.questions]),u=r(()=>{const e=new Map;return p.forEach((t,r)=>{e.set(t.answer,i[r]??String(r+1))}),e},[p]),h=e=>c[e.id]?.answer??e.exampleAnswer??"",g=r(()=>{const e=new Set;return b.forEach(t=>{const r=h(t),n=u.get(r);n&&e.add(n)}),e},[b,c,u]);return t("div",{className:"flex flex-col gap-4",children:[x&&e("div",{className:"flex items-center justify-center",children:e(n,{src:x,alt:"Group image",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),p.length>0&&t("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"ANSWER OPTIONS"}),e("div",{className:"mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2",children:p.map((r,a)=>{const o=i[a]??String(a+1),l=!f&&g.has(o);return t("div",{className:s("flex items-start gap-2.5 rounded-xl border border-[#e2ecf8] bg-[#f4f9ff] px-3 py-2 transition-opacity",l&&"opacity-50"),children:[t("span",{className:"relative flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:[o,l&&e("span",{className:"absolute -right-1 -top-1 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-[#16a34a] text-[8px] text-white",children:"✓"})]}),t("div",{className:"min-w-0 text-sm text-[#0f1730]",children:[r.imageUrl&&e(n,{src:r.imageUrl,alt:r.answer,className:"mb-1 max-h-24 w-auto rounded object-contain"}),e("span",{className:"font-medium",children:r.content||r.answer})]})]},`${r.answer}-${a}`)})})]}),e("div",{className:"flex flex-col gap-3",children:b.map(r=>{const a=h(r),l=u.get(a)??"",c=f&&r.isExample?a===(r.exampleAnswer??""):void 0,b=!0===c?"border-[#bbf7d0] bg-[#f0fdf4]":!1===c?"border-[#fecaca] bg-[#fef2f2]":"border-[#d9e4f2] bg-white/90",x=!0===c?"correct":!1===c?"wrong":l?"filled":"empty";return t("div",{id:o(r.id),className:s("scroll-mt-24 flex items-center gap-3 rounded-xl border p-3 shadow-sm transition-colors",b,r.isExample&&"opacity-90"),children:[e("span",{className:"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:r.questionNumber}),t("div",{className:"min-w-0 flex-1",children:[r.imageUrl&&e(n,{src:r.imageUrl,alt:`Question ${r.questionNumber}`,className:"mb-2 max-h-28 w-auto rounded object-contain"}),e("p",{className:"text-sm text-[#0f1730]",children:r.question})]}),t("div",{className:"flex shrink-0 items-center gap-2",children:[e(d,{letter:l,tone:x}),r.isExample?e("span",{className:"rounded-lg border border-[#b9edc8] bg-[#ddf8e7] px-3 py-1.5 text-sm font-semibold text-[#15803d]",children:r.exampleAnswer}):t("select",{value:a,disabled:f,onChange:e=>{return t=r.id,n=e.target.value,void m(t,{answer:n});var t,n},className:s("h-9 min-w-[150px] rounded-lg border-2 border-[#9cc4f5] bg-white px-3 text-sm font-semibold text-[#0f1730] outline-none transition-all focus:border-[#1167e8]",f&&"cursor-not-allowed opacity-70"),children:[e("option",{value:"",children:"—"}),p.map((t,n)=>{const s=i[n]??String(n+1),a=t.content||t.answer;return e("option",{value:t.answer,children:a?`${s} — ${a}`:s},`${r.id}-${n}`)})]})]})]},r.id)})})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as a}from"../../../components/common/ResolvedImage";import{cn as n}from"../../../shared/lib/utils";import{transformWordFillParagraph as
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as a}from"../../../components/common/ResolvedImage";import{cn as n}from"../../../shared/lib/utils";import{transformWordFillParagraph as l}from"../../../components/exams/take/exam-taking.utils";import{englishCertQuestionDomId as o}from"./english-cert-scroll";export function EcWordFillParagraph({part:s,answers:i,onAnswerChange:d,isReviewMode:c=!1}){const m=r(()=>l(s.questions),[s.questions]),{questionId:p,paragraph:x,title:b,imageUrl:f,wordBank:h,viewMode:u}=m,g=i[p]||[],w=r(()=>x.split(/(\{\d+\})/),[x]),N="WITH_WORD_BANK"===u,v=new Set(g.filter(Boolean)),_=(e,t)=>{if(c)return;const r=[...g];r[e]=t,d(p,r)};return t("div",{id:o(p),className:"scroll-mt-24 flex flex-col gap-4",children:[f&&e("div",{className:"flex items-center justify-center",children:e(a,{src:f,alt:b||"Illustration",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),N&&h.length>0&&t("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"Word bank"}),e("div",{className:"mt-2 flex flex-wrap gap-2",children:h.map((t,r)=>{const a=v.has(t.word);return e("span",{className:n("rounded-full border px-3 py-1 text-sm font-semibold transition-all",t.isExample?"border-[#b9edc8] bg-[#ddf8e7] text-[#15803d]":a?"border-[#d9e4f2] bg-[#f4f9ff] text-[#94a3b8] line-through":"border-[#9cc4f5] bg-white text-[#0b57d0]"),children:t.word},`${t.word}-${r}`)})})]}),e("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-5 text-base leading-loose text-[#0f1730] shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:w.map((r,a)=>{const l=r.match(/^\{(\d+)\}$/);if(!l)return e("span",{children:r},a);const o=parseInt(l[1],10),s=g[o]||"";return t("span",N?{className:"mx-1 inline-flex items-baseline gap-1 align-baseline",children:[t("span",{className:"text-[11px] font-bold text-[#1f7cff]",children:["(",o+1,")"]}),t("select",{value:s,disabled:c,onChange:e=>_(o,e.target.value),className:n("rounded-lg border-2 px-2 py-1 text-sm font-semibold outline-none transition-all",s?"border-[#1167e8] text-[#0b57d0]":"border-[#9cc4f5] text-[#64748b]",c&&"cursor-not-allowed opacity-70"),children:[e("option",{value:"",children:"———"}),h.filter(e=>!e.isExample).map((t,r)=>e("option",{value:t.word,children:t.word},`${o}-${r}`))]})]}:{className:"mx-1 inline-flex items-baseline gap-1 align-baseline",children:[t("span",{className:"text-[11px] font-bold text-[#1f7cff]",children:["(",o+1,")"]}),e("input",{type:"text",value:s,disabled:c,placeholder:"···",onChange:e=>_(o,e.target.value),style:{width:`${Math.max(4,s.length+1)}ch`},className:n("inline-block min-w-[4ch] max-w-[16ch] border-b-2 bg-transparent px-1 text-center text-sm font-semibold outline-none transition-colors",s?"border-[#1167e8] text-[#0b57d0]":"border-[#9cc4f5] text-[#64748b]",c&&"cursor-not-allowed opacity-70")})]},a)})})]})}
|
package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.d.ts
CHANGED
|
@@ -12,6 +12,10 @@ interface EnglishCertificationGroupedQuestionProps {
|
|
|
12
12
|
isListeningPart?: boolean;
|
|
13
13
|
/** Part-level audio URL (S3 key or absolute URL) for the Listening player. */
|
|
14
14
|
partAudioUrl?: string;
|
|
15
|
+
/** TOEIC play-once rule: whether this part's Listening audio was already started. */
|
|
16
|
+
isAudioLocked?: boolean;
|
|
17
|
+
/** Fired the first time the student starts this part's Listening audio. */
|
|
18
|
+
onAudioFirstPlay?: () => void;
|
|
15
19
|
}
|
|
16
20
|
/**
|
|
17
21
|
* Ocean Edu branded split-view renderer for grouped reading parts.
|
|
@@ -20,5 +24,5 @@ interface EnglishCertificationGroupedQuestionProps {
|
|
|
20
24
|
* reading passage (title, optional image, body, source bar) on the left and its
|
|
21
25
|
* MCQ questions on the right in a balanced 50/50 split.
|
|
22
26
|
*/
|
|
23
|
-
export declare function EnglishCertificationGroupedQuestion({ part, partConfig, answers, flaggedQuestions, onAnswerChange, onToggleFlag, isReviewMode, isListeningPart, partAudioUrl, }: EnglishCertificationGroupedQuestionProps): import("react").JSX.Element;
|
|
27
|
+
export declare function EnglishCertificationGroupedQuestion({ part, partConfig, answers, flaggedQuestions, onAnswerChange, onToggleFlag, isReviewMode, isListeningPart, partAudioUrl, isAudioLocked, onAudioFirstPlay, }: EnglishCertificationGroupedQuestionProps): import("react").JSX.Element;
|
|
24
28
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{FileText as
|
|
1
|
+
"use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{FileText as t,Info as a}from"lucide-react";import{EnglishCertificationQuestionCard as i}from"./EnglishCertificationQuestionCard";import{EnglishCertificationPassagePanel as r}from"./EnglishCertificationPassagePanel";import{EnglishCertificationReadingSection as n}from"./EnglishCertificationReadingSection";import{EnglishCertificationAudioPlayer as o}from"./EnglishCertificationAudioPlayer";import{EnglishCertificationInstructionBanner as l}from"./EnglishCertificationInstructionBanner";import{EnglishCertificationPartHeader as d}from"./EnglishCertificationPartHeader";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as c}from"./english-certification-theme";import{ENGLISH_CERT_STICKY_AUDIO_ATTR as p,englishCertQuestionDomId as g}from"./english-cert-scroll";import{isHtmlContent as u,stripInstruction as m}from"./grouped-question-utils";import{ResolvedImage as f}from"../../../components/common/ResolvedImage";function h(e){const s=e.articles;return Array.isArray(s)?s:[]}function x(e){return e.some(e=>Boolean(e?.content?.trim())||Boolean(e?.imageUrl))}export function EnglishCertificationGroupedQuestion({part:b,partConfig:w,answers:N,flaggedQuestions:v,onAnswerChange:I,onToggleFlag:q,isReviewMode:y=!1,isListeningPart:C=!1,partAudioUrl:T,isAudioLocked:U=!1,onAudioFirstPlay:_}){const P=w.startIndex??0,k=function(e,s){const t=e.questions[0];return(t?.questionGroup?.payload?.instructions??(s?.trim()||void 0)??t?.content?.question??"").trim()}(b,b.instructions??w.instructions),A=b.sections?.length?[(()=>{const e=b.questions[0]?.questionGroup?.payload??{},s=e.content??e.passage??"",t=m(s,k),a=e.imageUrl??e.passageImageUrl??"",i=h(e);return{groupId:b.partId,questions:b.questions,passage:t,passageTitle:e.passageTitle??e.title??"",passageSubtitle:e.subtitle??"",passageImageUrl:a,articles:i,hasPassageContent:Boolean(t.trim())||Boolean(a)||x(i)}})()]:function(e,s){const t=[],a=new Map;return e.questions.forEach(e=>{const s=e.group_id??e.id;a.has(s)||(a.set(s,[]),t.push(s)),a.get(s).push(e)}),t.map(e=>{const t=a.get(e),i=t[0]?.questionGroup?.payload??{},r=i.content??i.passage??"",n=m(r,s),o=i.imageUrl??i.passageImageUrl??"",l=h(i);return{groupId:e,questions:t,passage:n,passageTitle:i.passageTitle??i.title??"",passageSubtitle:i.subtitle??"",passageImageUrl:o,articles:l,hasPassageContent:Boolean(n.trim())||Boolean(o)||x(l)}})}(b,k);if(!A.length)return e("div",{className:"flex h-full items-center justify-center rounded-xl border border-red-200 bg-red-50 p-8 text-red-600",children:"No questions found for this part"});const B=A.some(e=>e.hasPassageContent),E=C&&Boolean(T),F=s=>b.sections?.length?e("div",{className:"flex-1 space-y-6 px-4 py-4",children:b.sections.map((t,a)=>{const i=s.questions.filter(e=>{const s=b.questions.indexOf(e);return s>=t.startIndex-P&&s<=t.endIndex-P});return i.length?e(n,{part:b,section:t,questions:i,startIndex:P,answers:N,flaggedQuestions:v,onAnswerChange:I,onToggleFlag:q,isReviewMode:y},`${s.groupId}-section-${a}`):null})}):e("div",{className:"flex-1 space-y-3 px-4 py-4",children:s.questions.map(s=>{const t=b.questions.indexOf(s)+1;return e(i,{question:s,globalQuestionNumber:P+t,answer:N[s.id],isFlagged:v.has(s.id),sharedInstruction:k,onAnswerChange:I,onToggleFlag:q,isReviewMode:y,domId:g(s.id)},s.id)})});return s("div",{className:"flex h-full flex-col gap-6 overflow-y-auto pb-4",children:[e(d,{partName:b.name,partNo:b.partNo,skill:w.category,isFullWidth:B}),e(l,{instruction:k,isListeningPart:C,isFullWidth:B}),E&&e("div",{[p]:"",className:`sticky top-0 z-20 ${c} w-full self-center`,children:e(o,{audioUrl:T,partNumber:b.partNo,isLocked:U,onFirstPlay:_})}),A.map(i=>{const n=b.questions.indexOf(i.questions[0])+P+1,o=b.questions.indexOf(i.questions[i.questions.length-1])+P+1,l=u(i.passage);return i.hasPassageContent?s("div",{className:"flex flex-col gap-3",children:[e("div",{className:"flex flex-wrap items-center gap-3 rounded-xl border border-[#d9e4f2] bg-white/85 px-4 py-3 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md",children:s("div",{className:"flex items-center gap-2.5 rounded-md border border-[#bfd8f8] bg-white/70 px-3 py-1.5 text-base font-bold text-[#0b57d0]",children:[e("span",{className:"grid h-[18px] w-[18px] place-items-center rounded-full bg-[#1167e8] text-white",children:e(a,{className:"h-3 w-3"})}),"Questions ",n,"–",o," refer to the following passage."]})}),s("div",{className:"grid gap-4",style:{gridTemplateColumns:"minmax(0, 1fr) minmax(0, 1fr)"},children:[e("div",{className:"h-full max-h-[calc(100vh-220px)] min-h-0 overflow-y-auto",children:e(r,{passage:i.passage,passageTitle:i.passageTitle,passageSubtitle:i.passageSubtitle,passageImageUrl:i.passageImageUrl,articles:i.articles,passageIsHtml:l})}),e("section",{className:"flex max-h-[calc(100vh-220px)] min-h-0 flex-col overflow-y-auto rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md",children:F(i)})]})]},i.groupId):s("div",{className:`${c} flex w-full flex-col gap-3 self-center`,children:[s("div",{className:"flex items-center gap-4 rounded-xl border border-[#d9e4f2] bg-white/90 px-5 py-4 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md",children:[e("span",{className:"grid h-12 w-12 shrink-0 place-items-center rounded-xl bg-[#eaf2ff] text-[#1167e8]",children:e(t,{className:"h-6 w-6"})}),s("div",{className:"min-w-0 flex-1",children:[s("span",{className:"inline-flex items-center gap-1.5 rounded-md border border-[#bfd8f8] bg-[#eaf2ff] px-2.5 py-1 text-xs font-bold text-[#0b57d0]",children:["Questions ",n,"–",o]}),i.passageTitle&&e("p",{className:"mt-2 text-lg font-bold leading-tight text-[#0f1730]",children:i.passageTitle}),i.passageSubtitle&&e("p",{className:"mt-1 text-[15px] font-medium text-[#475569]",children:i.passageSubtitle})]}),i.passageImageUrl&&e(f,{src:i.passageImageUrl,alt:i.passageTitle||"Illustration",className:"h-20 w-32 shrink-0 rounded-lg object-contain"})]}),e("section",{className:"flex flex-col overflow-hidden rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md",children:F(i)})]},i.groupId)})]})}
|
package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export interface EnglishCertificationOption {
|
|
|
4
4
|
text: string;
|
|
5
5
|
}
|
|
6
6
|
/** Visual layout variant for the option selector. */
|
|
7
|
-
export type EnglishCertificationOptionVariant = 'cards' | 'compact';
|
|
7
|
+
export type EnglishCertificationOptionVariant = 'cards' | 'list' | 'compact';
|
|
8
8
|
export interface EnglishCertificationOptionSelectorProps {
|
|
9
9
|
options: EnglishCertificationOption[];
|
|
10
10
|
selectedOptionId: string | null;
|
|
@@ -14,7 +14,10 @@ export interface EnglishCertificationOptionSelectorProps {
|
|
|
14
14
|
correctOptionId?: string;
|
|
15
15
|
/**
|
|
16
16
|
* Layout variant:
|
|
17
|
-
* - 'cards' (default): large A–D answer cards
|
|
17
|
+
* - 'cards' (default): large A–D answer cards, best suited to image-based
|
|
18
|
+
* choices (TOEIC Part 1) or short single-word/phrase responses.
|
|
19
|
+
* - 'list': vertical A–D rows matching the original TOEIC paper layout
|
|
20
|
+
* (Part 3/4/5 conversations, talks, incomplete sentences).
|
|
18
21
|
* - 'compact': tight radio rows for grouped reading.
|
|
19
22
|
*/
|
|
20
23
|
variant?: EnglishCertificationOptionVariant;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{
|
|
1
|
+
"use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{useRef as t}from"react";import{cn as d}from"../../../shared/lib/utils";import{Check as a,CheckCircle2 as o,X as i,XCircle as l}from"lucide-react";export function EnglishCertificationOptionSelector({options:n,selectedOptionId:s,onSelect:c,disabled:b=!1,isReviewMode:h=!1,correctOptionId:x,variant:p="cards"}){const f=t([]),g=n.findIndex(e=>e.id===s),m=g>=0?g:0,w=(e,r)=>{if(b)return;let t;switch(e.key){case"ArrowRight":case"ArrowDown":t=(r+1)%n.length;break;case"ArrowLeft":case"ArrowUp":t=(r-1+n.length)%n.length;break;default:return}e.preventDefault();const d=n[t];c(d.id),f.current[t]?.focus()};return e("div","compact"===p?{className:"flex flex-col gap-1",role:"radiogroup",children:n.map((t,a)=>{const i=t.id===s,n=h&&t.id===x,p=h&&i&&t.id!==x;return r("button",{ref:e=>{f.current[a]=e},type:"button",role:"radio","aria-checked":i,disabled:b,tabIndex:a===m?0:-1,onClick:()=>!b&&c(t.id),onKeyDown:e=>w(e,a),className:d("flex items-center gap-2.5 rounded-md border border-transparent px-2.5 py-1.5 text-left text-base transition-all","hover:border-[#c8def7] hover:bg-[#f4f9ff]",i&&!h&&"border-[#99c5f8] bg-[#eff7ff] shadow-[inset_0_0_0_1px_rgba(17,103,232,0.08)]",n&&"border-[#b9edc8] bg-[#ddf8e7]",p&&"border-red-300 bg-red-50",b&&"cursor-not-allowed opacity-60"),children:[e("span",{className:d("grid h-4 w-4 shrink-0 place-items-center rounded-full border-2 border-[#94a3b8]",i&&!h&&"border-[#0b57d0]",n&&"border-[#22c55e]",p&&"border-red-500"),children:i&&e("span",{className:d("h-2 w-2 rounded-full bg-[#0b57d0]",n&&"bg-[#22c55e]",p&&"bg-red-500")})}),e("span",{className:"font-bold text-[#23304c]",children:t.label}),e("span",{className:"flex-1 leading-snug text-[#1e293b]",children:t.text}),h&&n&&e(o,{className:"h-4 w-4 shrink-0 text-[#22c55e]","aria-label":"Correct"}),h&&p&&e(l,{className:"h-4 w-4 shrink-0 text-red-500","aria-label":"Incorrect"})]},t.id)})}:"list"===p?{className:"flex flex-col gap-3",role:"radiogroup",children:n.map((t,o)=>{const l=t.id===s,n=h&&t.id===x,p=h&&l&&t.id!==x,g=l&&!h;return r("button",{ref:e=>{f.current[o]=e},type:"button",role:"radio","aria-checked":l,disabled:b,tabIndex:o===m?0:-1,onClick:()=>!b&&c(t.id),onKeyDown:e=>w(e,o),className:d("flex items-center gap-4 rounded-2xl border-2 p-4 text-left transition-all","border-[#e5eefb] bg-white shadow-[0_5px_16px_rgba(13,71,161,0.08)]","hover:border-[#bfd8f8] hover:bg-[#fbfdff] hover:shadow-[0_10px_22px_rgba(13,71,161,0.14)]",g&&"border-transparent text-white shadow-[0_16px_30px_rgba(11,87,208,0.25)]",n&&"border-[#22c55e] bg-[#ddf8e7]",p&&"border-red-400 bg-red-50",b&&"cursor-not-allowed opacity-60"),style:g?{background:"linear-gradient(180deg, #1f7cff, #0b57d0)"}:void 0,children:[e("span",{className:d("grid h-11 w-11 shrink-0 place-items-center rounded-full border-2 text-lg font-black transition-colors","border-[#bfd8f8] bg-[#eef5ff] text-[#0b57d0]",g&&"border-white/70 bg-white/15 text-white",n&&"border-[#22c55e] bg-white text-[#22c55e]",p&&"border-red-500 bg-white text-red-500"),children:t.label}),e("span",{className:d("flex-1 text-[15px] font-semibold leading-relaxed text-[#0f1730]",g&&"text-white",n&&"text-[#15803d]",p&&"text-red-700"),children:t.text}),(g||n)&&e("span",{className:"grid h-7 w-7 shrink-0 place-items-center rounded-full bg-white text-[#0b57d0] shadow-[0_2px_6px_rgba(11,87,208,0.25)]",children:e(a,{className:"h-4 w-4",strokeWidth:3})}),p&&e("span",{className:"grid h-7 w-7 shrink-0 place-items-center rounded-full bg-white text-red-500 shadow-[0_2px_6px_rgba(239,68,68,0.25)]",children:e(i,{className:"h-4 w-4",strokeWidth:3})})]},t.id)})}:{className:"grid gap-4 sm:gap-5",style:{gridTemplateColumns:`repeat(${Math.min(n.length,4)}, minmax(0, 1fr))`},role:"radiogroup",children:n.map((t,o)=>{const l=t.id===s,n=h&&t.id===x,p=h&&l&&t.id!==x,g=l&&!h;return r("button",{ref:e=>{f.current[o]=e},type:"button",role:"radio","aria-checked":l,disabled:b,tabIndex:o===m?0:-1,onClick:()=>!b&&c(t.id),onKeyDown:e=>w(e,o),className:d("relative flex min-h-[104px] flex-col items-center justify-center rounded-2xl border-2 p-3 transition-all","border-[#e5eefb] bg-white shadow-[0_5px_16px_rgba(13,71,161,0.08)]","hover:-translate-y-0.5 hover:border-[#bfd8f8] hover:shadow-[0_10px_22px_rgba(13,71,161,0.14)]",g&&"border-transparent text-white shadow-[0_16px_30px_rgba(11,87,208,0.25)] hover:-translate-y-0.5",n&&"border-[#22c55e] bg-[#ddf8e7]",p&&"border-red-400 bg-red-50",b&&"cursor-not-allowed opacity-60 hover:translate-y-0"),style:g?{background:"linear-gradient(180deg, #1f7cff, #0b57d0)"}:void 0,children:[e("span",{className:d("grid h-[52px] w-[52px] place-items-center rounded-full border-2 text-2xl font-black transition-colors","border-[#bfd8f8] bg-[#eef5ff] text-[#0b57d0]",g&&"border-white/70 bg-white/15 text-white",n&&"border-[#22c55e] bg-white text-[#22c55e]",p&&"border-red-500 bg-white text-red-500"),children:t.label}),t.text&&e("span",{className:d("mt-2 text-center text-sm font-semibold leading-snug text-[#0f1730]",g&&"text-white",n&&"text-[#15803d]",p&&"text-red-700"),children:t.text}),(g||n)&&e("span",{className:"absolute right-2.5 top-2.5 grid h-6 w-6 place-items-center rounded-full bg-white text-[#0b57d0] shadow-[0_2px_6px_rgba(11,87,208,0.25)]",children:e(a,{className:"h-3.5 w-3.5",strokeWidth:3})}),p&&e("span",{className:"absolute right-2.5 top-2.5 grid h-6 w-6 place-items-center rounded-full bg-white text-red-500 shadow-[0_2px_6px_rgba(239,68,68,0.25)]",children:e(i,{className:"h-3.5 w-3.5",strokeWidth:3})})]},t.id)})})}
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
+
/** A single reading article (TOEIC Part 7 single/double/triple passages). */
|
|
2
|
+
interface PassageArticle {
|
|
3
|
+
name: string;
|
|
4
|
+
content: string;
|
|
5
|
+
imageUrl?: string;
|
|
6
|
+
}
|
|
1
7
|
interface EnglishCertificationPassagePanelProps {
|
|
2
8
|
passage: string;
|
|
3
9
|
passageTitle: string;
|
|
4
10
|
passageSubtitle: string;
|
|
5
11
|
/** S3 key, relative path, or absolute URL for the passage image. */
|
|
6
12
|
passageImageUrl: string;
|
|
13
|
+
/**
|
|
14
|
+
* TOEIC Part 7 reading articles (each with name, HTML content, and image).
|
|
15
|
+
* Rendered stacked below the passage body; empty for Part 6 / plain passages.
|
|
16
|
+
*/
|
|
17
|
+
articles?: PassageArticle[];
|
|
7
18
|
passageIsHtml: boolean;
|
|
8
19
|
/** Part display name (e.g. "Part 6") shown in the source bar. */
|
|
9
|
-
partName
|
|
20
|
+
partName?: string;
|
|
10
21
|
}
|
|
11
22
|
/**
|
|
12
23
|
* Reading passage panel for grouped English Certification parts.
|
|
@@ -16,6 +27,9 @@ interface EnglishCertificationPassagePanelProps {
|
|
|
16
27
|
* `questions/images/...`) which must be exchanged for a presigned URL before
|
|
17
28
|
* they can be rendered. Local paths (`/...`) and absolute URLs pass through
|
|
18
29
|
* unchanged.
|
|
30
|
+
*
|
|
31
|
+
* `{number}` tokens (e.g. `{141}`) in the passage are converted to styled
|
|
32
|
+
* blank-line spans so students see fill-in-the-blank positions clearly.
|
|
19
33
|
*/
|
|
20
|
-
export declare function EnglishCertificationPassagePanel({ passage, passageTitle, passageSubtitle, passageImageUrl,
|
|
34
|
+
export declare function EnglishCertificationPassagePanel({ passage, passageTitle, passageSubtitle, passageImageUrl, articles, passageIsHtml, }: EnglishCertificationPassagePanelProps): import("react").JSX.Element;
|
|
21
35
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{ResolvedImage as l}from"../../../components/common/ResolvedImage";import{useImageUrl as n}from"../../../shared/lib/hooks/useImageUrl";import{injectBlankPlaceholders as a}from"./grouped-question-utils";const r="ec-passage-html text-[17px] leading-[1.8] text-[#111827] [&_h1]:mb-2 [&_h1]:text-[1.6em] [&_h1]:font-black [&_h1]:leading-tight [&_h1]:text-[#111827] [&_h2]:mb-2 [&_h2]:text-[1.25em] [&_h2]:font-bold [&_h2]:leading-snug [&_h2]:text-[#111827] [&_h3]:mb-1.5 [&_h3]:text-[1.1em] [&_h3]:font-bold [&_h3]:text-[#111827] [&_p]:mb-3 [&_p]:whitespace-pre-wrap [&_strong]:font-bold [&_ul]:my-3 [&_ul]:list-disc [&_ul]:pl-6 [&_ol]:my-3 [&_ol]:list-decimal [&_ol]:pl-6 [&_li]:mb-1.5 [&_table]:my-3 [&_td]:border [&_td]:border-[#d9e4f2] [&_td]:px-2 [&_td]:py-1";function i({article:n,label:i}){const d=Boolean(i)||Boolean(n.name?.trim());return t("div",{className:"border-t border-[#e6eefb] pt-4 first:border-t-0 first:pt-0",children:[d&&t("div",{className:"mb-2 flex items-center gap-2",children:[i&&e("span",{className:"grid h-7 w-7 shrink-0 place-items-center rounded-full bg-[#1167e8] text-xs font-bold text-white",children:i}),n.name?.trim()&&e("h3",{className:"text-base font-bold text-[#061a55]",children:n.name})]}),n.imageUrl&&e("div",{className:"mb-3 overflow-hidden rounded-lg border border-[#d9e4f2]",children:e(l,{src:n.imageUrl,alt:n.name||"passage",className:"h-auto w-full object-contain"})}),n.content?.trim()&&e("div",{className:r,dangerouslySetInnerHTML:{__html:a(n.content)}})]})}export function EnglishCertificationPassagePanel({passage:l,passageTitle:d,passageSubtitle:s,passageImageUrl:o,articles:c,passageIsHtml:m}){const b=n(o||null),p=a(l),h=c??[],x=h.length>1;return t("article",{className:"flex h-full flex-col overflow-hidden rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md",children:[e("div",{className:"flex h-[52px] items-end border-b border-[#d9e4f2] bg-white/70 px-5",children:e("span",{className:"flex h-full items-center border-b-[3px] border-[#0b57d0] text-sm font-black tracking-wide text-[#0a3d9a]",children:"PASSAGE"})}),e("div",{className:"flex-1 overflow-y-auto custom-scrollbar",children:t("div",{className:"px-6 pt-6 leading-relaxed",children:[d&&e("h1",{className:"mb-1 text-[clamp(20px,1.6vw,28px)] font-black leading-tight text-[#061a55]",children:d}),s&&e("p",{className:"mb-4 text-[15px] font-semibold text-[#475569]",children:s}),b&&e("div",{className:"mb-4 overflow-hidden rounded-lg border border-[#d9e4f2]",children:e("img",{src:b,alt:"passage",className:"h-auto w-full object-cover"})}),l.trim()&&e("div",m?{className:r,dangerouslySetInnerHTML:{__html:p}}:{className:"whitespace-pre-wrap text-[17px] leading-[1.8] text-[#1e293b]",children:p}),h.length>0&&e("div",{className:"flex flex-col gap-4",children:h.map((t,l)=>e(i,{article:t,label:x?String.fromCharCode(65+l):void 0},l))})]})}),e("style",{children:"\n /* Wrapper: subtle pill around the entire blank unit */\n .ec-blank-placeholder {\n display: inline-flex;\n align-items: center;\n gap: 0;\n vertical-align: middle;\n white-space: nowrap;\n margin: 0 2px;\n padding: 1px 5px;\n background: rgba(11, 87, 208, 0.07);\n border: 1px solid rgba(11, 87, 208, 0.20);\n border-radius: 999px;\n }\n\n /* Flat line (not border-bottom) so it sits at vertical center correctly */\n .ec-blank-line {\n display: inline-block;\n width: 20px;\n height: 2px;\n background: #0b57d0;\n border-radius: 1px;\n opacity: 0.6;\n margin: 0 4px;\n }\n\n /* Number badge — plain bold blue text, no background */\n .ec-blank-label {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0 3px;\n color: #0b57d0;\n font-size: 15px;\n font-weight: 800;\n line-height: 1;\n letter-spacing: 0;\n }\n "})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationOptionSelector as t}from"./EnglishCertificationOptionSelector";import{EnglishCertificationFlagButton as n}from"./EnglishCertificationFlagButton";export function EnglishCertificationQuestionCard({question:o,globalQuestionNumber:
|
|
1
|
+
"use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationOptionSelector as t}from"./EnglishCertificationOptionSelector";import{EnglishCertificationFlagButton as n}from"./EnglishCertificationFlagButton";export function EnglishCertificationQuestionCard({question:o,globalQuestionNumber:s,answer:r,isFlagged:a,sharedInstruction:l,onAnswerChange:d,onToggleFlag:c,isReviewMode:g=!1,domId:m}){const p=o.content||{},f=p.options||[],u=p.question?.trim()??"",b=u.length>0&&u!==l;return e("article",{id:m,className:"scroll-mt-24 rounded-xl border border-[#d9e4f2] bg-white/90 px-4 py-4 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md transition-colors",children:i("div",{className:"grid grid-cols-[44px_1fr_32px] gap-1",children:[e("div",{className:"grid h-9 w-9 place-items-center rounded-full bg-[#eef5ff] text-base font-black leading-none text-[#0b57d0]",children:s}),i("div",{className:"min-w-0",children:[b&&e("div",{className:"mb-2 text-base font-black leading-snug text-[#10172f]",children:u}),e(t,{options:f.map((e,i)=>({id:String(e?.id||`${o.id}-opt-${i}`),label:String.fromCharCode(65+i),text:e?.text||String(e??"")})),selectedOptionId:r?.optionId??null,onSelect:e=>d(o.id,{optionId:e}),isReviewMode:g,disabled:g,variant:"compact"})]}),e(n,{isFlagged:a,onToggle:()=>c(o.id),size:"sm",className:"self-start justify-self-end"})]})})}
|
|
@@ -4,8 +4,6 @@ interface EnglishCertificationQuestionItemProps {
|
|
|
4
4
|
questionNumber: number;
|
|
5
5
|
questionConfig: string[];
|
|
6
6
|
defaultQuestion?: string;
|
|
7
|
-
/** Whether this question belongs to a LISTENING part (controls speaker icon). */
|
|
8
|
-
isListeningPart?: boolean;
|
|
9
7
|
answer: any;
|
|
10
8
|
isFlagged: boolean;
|
|
11
9
|
onAnswerChange: (questionId: string, answer: any) => void;
|
|
@@ -17,9 +15,10 @@ interface EnglishCertificationQuestionItemProps {
|
|
|
17
15
|
/**
|
|
18
16
|
* Ocean Edu branded card for a single multiple-choice question.
|
|
19
17
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
18
|
+
* Visual style matches EnglishCertificationQuestionCard (Part 7):
|
|
19
|
+
* compact grid layout, circular number badge, lightweight shadow.
|
|
20
|
+
* Audio is not rendered here — listening parts show one shared audio bar
|
|
21
|
+
* at the top of the list.
|
|
23
22
|
*/
|
|
24
|
-
export declare function EnglishCertificationQuestionItem({ question, questionNumber, questionConfig, defaultQuestion,
|
|
23
|
+
export declare function EnglishCertificationQuestionItem({ question, questionNumber, questionConfig, defaultQuestion, answer, isFlagged, onAnswerChange, onToggleFlag, isReviewMode, domId, }: EnglishCertificationQuestionItemProps): import("react").JSX.Element;
|
|
25
24
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{
|
|
1
|
+
"use client";import{jsx as e,jsxs as o}from"react/jsx-runtime";import{useMemo as i,useState as t}from"react";import{ZoomIn as n}from"lucide-react";import{Dialog as r,DialogContent as a,DialogHeader as l,DialogTitle as s}from"../../../components/ui/dialog";import{ResolvedImage as c}from"../../../components/common/ResolvedImage";import{EnglishCertificationOptionSelector as d}from"./EnglishCertificationOptionSelector";import{EnglishCertificationFlagButton as m}from"./EnglishCertificationFlagButton";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as g}from"./english-certification-theme";export function EnglishCertificationQuestionItem({question:p,questionNumber:u,questionConfig:h,defaultQuestion:f,answer:b,isFlagged:x,onAnswerChange:w,onToggleFlag:v,isReviewMode:N=!1,domId:C}){const[_,k]=t(!1),j=b?.optionId??null,y=i(()=>{const e=p.content?.options;return Array.isArray(e)?e.map((e,o)=>({id:String(e?.id||`${p.id}-opt-${o}`),label:String.fromCharCode(65+o),text:String(e?.text||e?.value||e||"")})):[]},[p.content?.options,p.id]),I=h.includes("imageUrl"),Q=p.content?.imageUrl,S=I&&Boolean(Q),$=p.content?.question?.trim()||f||"";return o("div",{id:C,className:`${g} scroll-mt-24`,children:[e("article",{className:"rounded-xl border border-[#d9e4f2] bg-white/90 px-4 py-4 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md transition-colors",children:o("div",{className:"grid grid-cols-[44px_1fr_32px] gap-1",children:[e("div",{className:"grid h-9 w-9 place-items-center rounded-full bg-[#eef5ff] text-base font-black leading-none text-[#0b57d0]",children:u}),o("div",{className:"min-w-0",children:[$&&e("div",{className:"mb-2 text-base font-black leading-snug text-[#10172f]",children:$}),S&&Q&&o("button",{type:"button",onClick:()=>k(!0),className:"group relative mb-3 block w-full overflow-hidden rounded-xl border border-[#cbdcf0] shadow-[0_8px_20px_rgba(6,26,85,0.10)]","aria-label":"Open image in large view",children:[e(c,{src:Q,alt:`Question ${u} visual prompt`,className:"h-auto max-h-[260px] w-full object-contain transition-transform group-hover:scale-[1.01]"}),e("span",{className:"absolute right-2 top-2 grid h-8 w-8 place-items-center rounded-full bg-black/50 text-white transition-colors group-hover:bg-black/70",children:e(n,{className:"h-3.5 w-3.5"})})]}),e(d,{options:y,selectedOptionId:j,onSelect:e=>w(p.id,{optionId:e}),disabled:N,isReviewMode:N,variant:"compact"})]}),e(m,{isFlagged:x,onToggle:()=>v(p.id),size:"sm",className:"self-start justify-self-end"})]})}),S&&Q&&e(r,{open:_,onOpenChange:k,children:o(a,{className:"max-w-4xl border-none bg-transparent p-0 shadow-none",children:[e(l,{className:"sr-only",children:e(s,{children:"Question image"})}),e("div",{className:"overflow-hidden rounded-lg bg-white",children:e(c,{src:Q,alt:`Question ${u} enlarged visual prompt`,className:"h-auto w-full object-contain"})})]})})]})}
|
package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{SkillEnum as i}from"../../../shared/types/common.types";import{EnglishCertificationSingleQuestionList as
|
|
1
|
+
"use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{SkillEnum as i}from"../../../shared/types/common.types";import{EnglishCertificationSingleQuestionList as o}from"./EnglishCertificationSingleQuestionList";import{EnglishCertificationGroupedQuestion as t}from"./EnglishCertificationGroupedQuestion";import{EnglishCertificationAudioPlayer as n}from"./EnglishCertificationAudioPlayer";import{EnglishCertificationPartHeader as s}from"./EnglishCertificationPartHeader";import{EnglishCertificationInstructionBanner as a}from"./EnglishCertificationInstructionBanner";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as l}from"./english-certification-theme";import{ENGLISH_CERT_STICKY_AUDIO_ATTR as d}from"./english-cert-scroll";import{EcWordFillStructuredForm as c}from"./EcWordFillStructuredForm";import{EcMatchByWritingAnswer as u}from"./EcMatchByWritingAnswer";import{EcAnswerTheQuestion as g}from"./EcAnswerTheQuestion";import{EcWordFillParagraph as m}from"./EcWordFillParagraph";import{EcWritingTask as p}from"./EcWritingTask";const f=new Set(["CHOOSE_THE_CORRECT_ANSWER"]);export function EnglishCertificationQuestionRenderer({part:h,partConfig:w,answers:A,flaggedQuestions:E,onAnswerChange:R,onToggleFlag:C,isReviewMode:N=!1,isAudioPlayed:T=!1,onAudioFirstPlay:y}){if(!h.questions.length)return e("div",{className:"flex h-full items-center justify-center rounded-xl border border-red-200 bg-red-50 p-8 text-red-600",children:"No questions found for this part"});const _=w.category===i.LISTENING,v=_?h.audioUrl??w.audioUrl??"":void 0,L=!N&&T,F=h.questionType,P=Boolean(h.isGroup)&&"DOCUMENT"===h.group?.type,x=w.isGroup&&f.has(F),M=Boolean(h.sections?.length);if(P||x||M)return e("div",{className:"h-full",children:e(t,{part:h,partConfig:w,answers:A,flaggedQuestions:E,onAnswerChange:R,onToggleFlag:C,isReviewMode:N,isListeningPart:_,partAudioUrl:v,isAudioLocked:L,onAudioFirstPlay:y})});if(f.has(F))return e(o,{part:h,partConfig:w,answers:A,flaggedQuestions:E,onAnswerChange:R,onToggleFlag:C,isReviewMode:N,isListeningPart:_,partAudioUrl:v,isAudioLocked:L,onAudioFirstPlay:y});const b=(h.questions[0]?.questionGroup?.payload?.instructions??h.instructions??w.instructions??"").trim();return r("div",{className:"flex flex-col items-center gap-6 pb-4",children:[e(s,{partName:h.name??w.name,partNo:h.partNo,skill:w.category}),e(a,{instruction:b,isListeningPart:_}),_&&e("div",{[d]:"",className:`sticky top-0 z-20 ${l}`,children:e(n,{audioUrl:v??"",partNumber:h.partNo,isLocked:L,onFirstPlay:y})}),e("div",{className:`${l} w-full`,children:(()=>{switch(F){case"WORD_FILL_STRUCTURED_FORM":return e(c,{part:h,answers:A,onAnswerChange:R,isReviewMode:N});case"MATCH_BY_WRITING_ANSWER":return e(u,{part:h,answers:A,onAnswerChange:R,isReviewMode:N});case"ANSWER_THE_QUESTION":return e(g,{part:h,answers:A,onAnswerChange:R,isReviewMode:N});case"WORD_FILL_PARAGRAPH":return e(m,{part:h,answers:A,onAnswerChange:R,isReviewMode:N});case"WRITE_A_SHORT_LETTER":return e(p,{part:h,answers:A,onAnswerChange:R,isReviewMode:N});default:return r("div",{className:"rounded-xl border border-amber-200 bg-amber-50 p-6 text-sm text-amber-700",children:['Loại câu hỏi "',F,'" chưa được hỗ trợ trong giao diện này.']})}})()})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationOptionSelector as t}from"./EnglishCertificationOptionSelector";import{EnglishCertificationFlagButton as n}from"./EnglishCertificationFlagButton";import{EcWordFillStructuredForm as r}from"./EcWordFillStructuredForm";import{EcMatchByWritingAnswer as s}from"./EcMatchByWritingAnswer";import{EcAnswerTheQuestion as o}from"./EcAnswerTheQuestion";import{EcWordFillParagraph as a}from"./EcWordFillParagraph";import{EcWritingTask as d}from"./EcWritingTask";import{englishCertQuestionDomId as l}from"./english-cert-scroll";function c(e){return e.map((e,
|
|
1
|
+
"use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationOptionSelector as t}from"./EnglishCertificationOptionSelector";import{EnglishCertificationFlagButton as n}from"./EnglishCertificationFlagButton";import{EcWordFillStructuredForm as r}from"./EcWordFillStructuredForm";import{EcMatchByWritingAnswer as s}from"./EcMatchByWritingAnswer";import{EcAnswerTheQuestion as o}from"./EcAnswerTheQuestion";import{EcWordFillParagraph as a}from"./EcWordFillParagraph";import{EcWritingTask as d}from"./EcWritingTask";import{englishCertQuestionDomId as l}from"./english-cert-scroll";function c(e,i){return e.map((e,t)=>{const n=String.fromCharCode(65+t),r=`${i}-opt-${t}`;return"string"==typeof e?{id:r,label:n,text:e}:{id:String(e?.id||r),label:n,text:String(e?.text??e?.value??e??"")}})}export function EnglishCertificationReadingSection({part:m,section:p,questions:u,startIndex:g,answers:f,flaggedQuestions:x,onAnswerChange:h,onToggleFlag:w,isReviewMode:R=!1}){if(!u.length)return null;const v=(p.instructions||p.name||"").trim();if("CHOOSE_THE_CORRECT_ANSWER"===p.questionType)return i("div",{className:"flex flex-col gap-3",children:[v&&e("p",{className:"text-sm font-semibold leading-relaxed text-[#0b57d0]",children:v}),e("div",{className:"divide-y divide-[#e8eef7]",children:u.map(r=>{const s=m.questions.indexOf(r)+g+1,o=r.content||{},a=Array.isArray(o.options)?o.options:p.defaultValue??[],d=o.question?.trim()??"",u=f[r.id];return i("article",{id:l(r.id),className:"scroll-mt-24 grid grid-cols-[44px_1fr_32px] gap-1 py-4",children:[i("div",{className:"text-[18px] font-black leading-snug text-[#0b57d0]",children:[s,"."]}),i("div",{className:"min-w-0",children:[d&&e("div",{className:"mb-2 text-[15px] font-black leading-snug text-[#10172f]",children:d}),e(t,{options:c(a,r.id),selectedOptionId:u?.optionId??null,onSelect:e=>h(r.id,{optionId:e}),isReviewMode:R,disabled:R,variant:"compact"})]}),e(n,{isFlagged:x.has(r.id),onToggle:()=>w(r.id),size:"sm",className:"self-start justify-self-end"})]},r.id)})})]});const T={...m,questionType:p.questionType,questions:u,instructions:v||m.instructions,isGroup:!1,group:void 0,sections:void 0,viewMode:p.viewMode,wordBankConfig:p.wordBankConfig,startIndex:p.startIndex,endIndex:p.endIndex};return i("div",{className:"flex flex-col gap-3",children:[v&&e("p",{className:"text-sm font-semibold leading-relaxed text-[#0b57d0]",children:v}),(()=>{switch(p.questionType){case"WORD_FILL_STRUCTURED_FORM":return e(r,{part:T,answers:f,onAnswerChange:h,isReviewMode:R});case"MATCH_BY_WRITING_ANSWER":return e(s,{part:T,answers:f,onAnswerChange:h,isReviewMode:R});case"ANSWER_THE_QUESTION":return e(o,{part:T,answers:f,onAnswerChange:h,isReviewMode:R});case"WORD_FILL_PARAGRAPH":return e(a,{part:T,answers:f,onAnswerChange:h,isReviewMode:R});case"WRITE_A_SHORT_LETTER":return e(d,{part:T,answers:f,onAnswerChange:h,isReviewMode:R});default:return i("div",{className:"rounded-xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-700",children:['Loại câu hỏi "',p.questionType,'" chưa được hỗ trợ.']})}})()]})}
|
package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.d.ts
CHANGED
|
@@ -27,5 +27,5 @@ interface EnglishCertificationSingleQuestionProps {
|
|
|
27
27
|
* shared audio bar for listening parts. Kept for review mode and any
|
|
28
28
|
* one-question-per-screen flow; multi-question screens use the question list.
|
|
29
29
|
*/
|
|
30
|
-
export declare function EnglishCertificationSingleQuestion({ question, questionNumber, questionConfig, defaultQuestion, partAudioUrl,
|
|
30
|
+
export declare function EnglishCertificationSingleQuestion({ question, questionNumber, questionConfig, defaultQuestion, partAudioUrl, answer, isFlagged, onAnswerChange, onToggleFlag, isReviewMode, }: EnglishCertificationSingleQuestionProps): import("react").JSX.Element;
|
|
31
31
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationAudioPlayer as n}from"./EnglishCertificationAudioPlayer";import{EnglishCertificationQuestionItem as
|
|
1
|
+
"use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{EnglishCertificationAudioPlayer as n}from"./EnglishCertificationAudioPlayer";import{EnglishCertificationQuestionItem as o}from"./EnglishCertificationQuestionItem";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as t}from"./english-certification-theme";export function EnglishCertificationSingleQuestion({question:s,questionNumber:r,questionConfig:a,defaultQuestion:l,partAudioUrl:u,answer:g,isFlagged:m,onAnswerChange:c,onToggleFlag:f,isReviewMode:d=!1}){const h=s.audio_url||u||"";return i("div",{className:"flex flex-col items-center gap-5",children:[h&&e("div",{className:t,children:e(n,{audioUrl:h,partNumber:s.part_no})}),e(o,{question:s,questionNumber:r,questionConfig:a,defaultQuestion:l,answer:g,isFlagged:m,onAnswerChange:c,onToggleFlag:f,isReviewMode:d})]})}
|
package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.d.ts
CHANGED
|
@@ -12,6 +12,10 @@ interface EnglishCertificationSingleQuestionListProps {
|
|
|
12
12
|
isListeningPart?: boolean;
|
|
13
13
|
/** Part-level audio URL (shown once at the top for listening parts). */
|
|
14
14
|
partAudioUrl?: string;
|
|
15
|
+
/** TOEIC play-once rule: whether this part's Listening audio was already started. */
|
|
16
|
+
isAudioLocked?: boolean;
|
|
17
|
+
/** Fired the first time the student starts this part's Listening audio. */
|
|
18
|
+
onAudioFirstPlay?: () => void;
|
|
15
19
|
}
|
|
16
20
|
/**
|
|
17
21
|
* Renders every question of a single-question part (or section) on one screen.
|
|
@@ -19,5 +23,5 @@ interface EnglishCertificationSingleQuestionListProps {
|
|
|
19
23
|
* Listening parts show a single shared audio bar at the top; all questions then
|
|
20
24
|
* stack vertically. Navigation across parts/sections is handled by the footer.
|
|
21
25
|
*/
|
|
22
|
-
export declare function EnglishCertificationSingleQuestionList({ part, partConfig, answers, flaggedQuestions, onAnswerChange, onToggleFlag, isReviewMode, isListeningPart, partAudioUrl, }: EnglishCertificationSingleQuestionListProps): import("react").JSX.Element;
|
|
26
|
+
export declare function EnglishCertificationSingleQuestionList({ part, partConfig, answers, flaggedQuestions, onAnswerChange, onToggleFlag, isReviewMode, isListeningPart, partAudioUrl, isAudioLocked, onAudioFirstPlay, }: EnglishCertificationSingleQuestionListProps): import("react").JSX.Element;
|
|
23
27
|
export {};
|
package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as i,jsxs as
|
|
1
|
+
"use client";import{jsx as i,jsxs as t}from"react/jsx-runtime";import{EnglishCertificationAudioPlayer as e}from"./EnglishCertificationAudioPlayer";import{EnglishCertificationQuestionItem as o}from"./EnglishCertificationQuestionItem";import{EnglishCertificationInstructionBanner as r}from"./EnglishCertificationInstructionBanner";import{EnglishCertificationPartHeader as n}from"./EnglishCertificationPartHeader";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as s}from"./english-certification-theme";import{ENGLISH_CERT_STICKY_AUDIO_ATTR as a,englishCertQuestionDomId as l}from"./english-cert-scroll";export function EnglishCertificationSingleQuestionList({part:u,partConfig:m,answers:c,flaggedQuestions:g,onAnswerChange:d,onToggleFlag:f,isReviewMode:p=!1,isListeningPart:h=!1,partAudioUrl:C,isAudioLocked:A=!1,onAudioFirstPlay:y}){const N=m.startIndex??0,w=Array.isArray(m.questionConfig)?m.questionConfig:[],x=m.defaultQuestion,q=h&&Boolean(C),P=(u.instructions??m.instructions)?.trim()||"",E=u.name??m.name;return t("div",{className:"flex flex-col items-center gap-6 pb-4",children:[i(n,{partName:E,partNo:u.partNo,skill:m.category}),i(r,{instruction:P,isListeningPart:h}),q&&i("div",{[a]:"",className:`sticky top-0 z-20 ${s}`,children:i(e,{audioUrl:C,partNumber:u.partNo,isLocked:A,onFirstPlay:y})}),u.questions.map((t,e)=>{const r=t.audio_url?Array.from(new Set([...w,"audioUrl"])):w;return i(o,{domId:l(t.id),question:t,questionNumber:N+e+1,questionConfig:r,defaultQuestion:x,answer:c[t.id],isFlagged:g.has(t.id),onAnswerChange:d,onToggleFlag:f,isReviewMode:p},t.id)})]})}
|
|
@@ -8,6 +8,23 @@
|
|
|
8
8
|
*/
|
|
9
9
|
/** Detects whether passage content carries HTML markup (Part 6) vs plain text (Part 7). */
|
|
10
10
|
export declare function isHtmlContent(value: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Replaces `{number}` tokens in passage HTML/text with a styled blank-line span.
|
|
13
|
+
*
|
|
14
|
+
* TOEIC Part 6 passages embed placeholders like `{141}`, `{142}`, `{143}` to
|
|
15
|
+
* mark the positions of fill-in-the-blank questions. This function converts
|
|
16
|
+
* each token into an inline HTML element that looks like an answer blank:
|
|
17
|
+
*
|
|
18
|
+
* _____(141)_____
|
|
19
|
+
*
|
|
20
|
+
* The resulting string is safe to inject via `dangerouslySetInnerHTML` because
|
|
21
|
+
* the surrounding HTML came from the CMS (trusted source) and only the token
|
|
22
|
+
* itself is replaced with a pre-defined, static HTML snippet.
|
|
23
|
+
*
|
|
24
|
+
* @param html - Raw passage string (HTML or plain text).
|
|
25
|
+
* @returns Transformed string with blank spans substituted for `{n}` tokens.
|
|
26
|
+
*/
|
|
27
|
+
export declare function injectBlankPlaceholders(html: string): string;
|
|
11
28
|
/** Collapses whitespace and strips tags so two instruction strings can be compared. */
|
|
12
29
|
export declare function normalizeText(value: string): string;
|
|
13
30
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function isHtmlContent(t){return/<[a-z][\s\S]*>/i.test(t)}export function normalizeText(t){return t.replace(/<[^>]*>/g," ").replace(/ /g," ").replace(/\s+/g," ").trim().toLowerCase()}const t=/^\s*<(p|div|h[1-6]|span|section|header)\b[^>]*>[\s\S]*?<\/\1>\s*/i;export function stripInstruction(r,
|
|
1
|
+
export function isHtmlContent(t){return/<[a-z][\s\S]*>/i.test(t)}export function injectBlankPlaceholders(t){return t.replace(/\{(\d+)\}/g,(t,e)=>`<span class="ec-blank-placeholder" data-qno="${e}" aria-label="Question ${e} blank"><span class="ec-blank-line"></span><span class="ec-blank-label">${e}</span><span class="ec-blank-line"></span></span>`)}export function normalizeText(t){return t.replace(/<[^>]*>/g," ").replace(/ /g," ").replace(/\s+/g," ").trim().toLowerCase()}const t=/^\s*<(p|div|h[1-6]|span|section|header)\b[^>]*>[\s\S]*?<\/\1>\s*/i;export function stripInstruction(r,s){if(!r||!s)return r;const n=normalizeText(s);if(!n)return r;if(isHtmlContent(r)){let s=r,i=!1,a="";for(;;){const e=t.exec(s);if(!e)break;const r=e[0],l=normalizeText(r);if(!l){s=s.slice(r.length),i=!0;continue}const o=normalizeText(a+" "+r).trim();if(!(n===o||n.startsWith(o)||o.startsWith(n)||n.startsWith(l)||l.startsWith(n)))break;if(a=o,s=s.slice(r.length),i=!0,a===n||a.startsWith(n))break}return i?s.trimStart():function(t,r){let s=0,n="",i=-1;for(;s<t.length;){const a=n.replace(/\s+/g," ").trim().toLowerCase();if(-1===i&&(a.length>=r.length&&a.startsWith(r)&&(i=s),a.length>0&&!r.startsWith(a)&&!a.startsWith(r)))return t;if("<"===t[s]){const e=t.indexOf(">",s);if(-1===e)return i>=0?t.slice(i).trimStart():t;const r=t.slice(s,e+1);if(s=e+1,i>=0&&!r.startsWith("</"))return t.slice(s-r.length).trimStart()}else if("&"===t[s]){if(i>=0)return t.slice(s).trimStart();const r=t.indexOf(";",s);-1!==r&&r-s<=10?(n+=e(t.slice(s,r+1)),s=r+1):n+=t[s++]}else{if(i>=0)return t.slice(s).trimStart();n+=t[s++]}}return i>=0?t.slice(i).trimStart():t}(r,n)}const i=r.split("\n");let a=0,l="";for(const t of i){const e=normalizeText(t);if(!e){a+=1;continue}const r=normalizeText(l+" "+t).trim();if(!(n===r||n.startsWith(r)||n.startsWith(e)||e.startsWith(n)))break;if(l=r,a+=1,l===n||l.startsWith(n))break}return a>0?i.slice(a).join("\n").trimStart():r}function e(t){const e=new Map([["nbsp"," "],["amp","&"],["lt","<"],["gt",">"],["quot",'"'],["#39","'"],["apos","'"],["ldquo","“"],["rdquo","”"],["lsquo","‘"],["rsquo","’"],["hellip","…"],["mdash","—"],["ndash","–"],["copy","©"],["reg","®"],["trade","™"]]),r=t.replace(/^&/,"").replace(/;$/,"").toLowerCase();return e.get(r)??" "}
|