mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-28 23:54:34 +00:00
Add the Next.js web app and shared lesson content.
Move lessons out of the C sources into JSON so the web client can use the same material as the desktop app, and point release builds at desktop/. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
4708c69d9c
commit
f7470d333c
113 changed files with 25817 additions and 9 deletions
69
web/src/components/exercises/TaskShell.tsx
Normal file
69
web/src/components/exercises/TaskShell.tsx
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
'use client';
|
||||
|
||||
import { useApp } from '@/app/providers';
|
||||
|
||||
export type CheckState = 'idle' | 'ok' | 'wrong';
|
||||
|
||||
/** The instruction lines every exercise takes from its task. */
|
||||
export interface TaskFrame {
|
||||
subtitle?: string;
|
||||
/** Worked example shown above the items. */
|
||||
example?: string;
|
||||
/** Extra guidance under the instruction, e.g. a word bank. */
|
||||
note?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frame shared by every exercise: the instruction, the task body, a check
|
||||
* button and the pass/fail feedback line.
|
||||
*/
|
||||
export function TaskShell({
|
||||
subtitle,
|
||||
example,
|
||||
note,
|
||||
state,
|
||||
checkLabel,
|
||||
onCheck,
|
||||
onReveal,
|
||||
revealed,
|
||||
children,
|
||||
}: TaskFrame & {
|
||||
state: CheckState;
|
||||
/** i18n key overriding the default "check" button label. */
|
||||
checkLabel?: string;
|
||||
onCheck: () => void;
|
||||
/** Provided by exercises that can show a model solution. */
|
||||
onReveal?: () => void;
|
||||
revealed?: boolean;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { t } = useApp();
|
||||
|
||||
return (
|
||||
<div className="stack">
|
||||
{subtitle && <p className="page__sub">{subtitle}</p>}
|
||||
{note && <p className="ex__note">{note}</p>}
|
||||
{example && <p className="ex__example">{example}</p>}
|
||||
|
||||
<div className="ex">{children}</div>
|
||||
|
||||
<div className="actions">
|
||||
<button className="btn" onClick={onCheck}>
|
||||
{t(checkLabel ?? 'check')}
|
||||
</button>
|
||||
|
||||
{onReveal && (
|
||||
<button className="btn btn--ghost" onClick={onReveal} disabled={revealed}>
|
||||
{t('net_solution')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{state !== 'idle' && (
|
||||
<p className={`feedback feedback--${state === 'ok' ? 'ok' : 'err'}`} role="status">
|
||||
{t(state === 'ok' ? 'feedback_ok' : 'feedback_retry_short')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue