mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-28 07:34: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
53
web/src/app/networks/NetworkYearsScreen.tsx
Normal file
53
web/src/app/networks/NetworkYearsScreen.tsx
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
|
||||
import { useApp } from '@/app/providers';
|
||||
import { TopBar } from '@/components/TopBar';
|
||||
import { LockIcon } from '@/components/icons';
|
||||
|
||||
/** Only year 1 has content, matching `build_net_years_page` in the desktop app. */
|
||||
const YEARS = [1, 2, 3, 4];
|
||||
|
||||
export function NetworkYearsScreen() {
|
||||
const { t } = useApp();
|
||||
|
||||
return (
|
||||
<div className="shell">
|
||||
<TopBar title={t('net_years_title')} backHref="/subjects" />
|
||||
|
||||
<main className="page">
|
||||
<div className="page__head">
|
||||
<h1 className="page__title">{t('net_years_title')}</h1>
|
||||
<p className="page__sub">{t('net_years_sub')}</p>
|
||||
</div>
|
||||
|
||||
<div className="grid">
|
||||
{YEARS.map((year) => {
|
||||
const label = t(`net_year${year}`);
|
||||
const locked = year !== 1;
|
||||
|
||||
if (locked) {
|
||||
return (
|
||||
<div className="card card--locked" key={year} aria-disabled>
|
||||
<span className="row" style={{ color: 'var(--overlay)' }}>
|
||||
<LockIcon size={22} />
|
||||
</span>
|
||||
<h2 className="card__title">{label}</h2>
|
||||
<p className="card__body">{t('net_year_locked_sub')}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Link className="card card--interactive" href={`/networks/year-${year}`} key={year}>
|
||||
<span className="card__kicker">{year}</span>
|
||||
<h2 className="card__title">{label}</h2>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
6
web/src/app/networks/page.tsx
Normal file
6
web/src/app/networks/page.tsx
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { NetworkYearsScreen } from './NetworkYearsScreen';
|
||||
|
||||
/** Year picker: year 1 has all 27 lessons, years 2-4 are placeholders. */
|
||||
export default function NetworkYearsPage() {
|
||||
return <NetworkYearsScreen />;
|
||||
}
|
||||
23
web/src/app/networks/year-1/[lesson]/page.tsx
Normal file
23
web/src/app/networks/year-1/[lesson]/page.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { notFound } from 'next/navigation';
|
||||
|
||||
import { getLesson, getLessonIds } from '@/content';
|
||||
import { LessonScreen } from '@/components/LessonScreen';
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const ids = await getLessonIds('networks');
|
||||
return ids.map((lesson) => ({ lesson }));
|
||||
}
|
||||
|
||||
export default async function NetworkLessonPage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ lesson: string }>;
|
||||
}) {
|
||||
const { lesson: id } = await params;
|
||||
|
||||
try {
|
||||
return <LessonScreen lesson={await getLesson('networks', id)} backHref="/networks/year-1" />;
|
||||
} catch {
|
||||
notFound();
|
||||
}
|
||||
}
|
||||
23
web/src/app/networks/year-1/page.tsx
Normal file
23
web/src/app/networks/year-1/page.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { notFound } from 'next/navigation';
|
||||
|
||||
import { getLessons, getPath } from '@/content';
|
||||
import { PathScreen } from '@/components/PathScreen';
|
||||
|
||||
export default async function NetworkYear1Page() {
|
||||
const path = await getPath('networks');
|
||||
if (!path) notFound();
|
||||
|
||||
const lessons = await getLessons('networks');
|
||||
const taskCounts = Object.fromEntries(lessons.map((l) => [l.id, l.tasks.length]));
|
||||
|
||||
return (
|
||||
<PathScreen
|
||||
path={path}
|
||||
titleKey="net_years_title"
|
||||
subtitleKey="net_sub"
|
||||
backHref="/networks"
|
||||
hrefBase="/networks/year-1"
|
||||
taskCounts={taskCounts}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue