Skip to content

Commit 8ed6bac

Browse files
committed
Refactor shell and offline quiz loading
1 parent f6032b6 commit 8ed6bac

33 files changed

Lines changed: 883 additions & 553 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# next.js
1414
/.next/
1515
/out/
16+
/public/offline-manifest.json
1617

1718
# production
1819
/build

README.md

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
LogiCola 3 is an instructional program that goes with Gensler's Introduction to Logic (Routledge Press). Since Harry Gensler, the original creator has passed away, I decided to create a new version to preserve an important learning resource and honour his legacy.
44

5+
Logicola is a web-based remake of the original Logicola software, designed to help students learn logic more easily across modern devices while preserving the spirit of the original program.
6+
7+
The live project is available at [logicola.org](https://logicola.org).
8+
9+
## About
10+
11+
This project focuses on making logic instruction more accessible to students,teachers, and universities by combining:
12+
13+
- Interactive quizzes.
14+
- Installable web app support for offline quiz use.
15+
16+
Logicola is still growing. The current codebase reflects both ongoing content development and the practical goal of keeping the platform widely accessible on the web.
17+
518
## Getting Started
619

720
Install dependencies with pnpm:
@@ -18,7 +31,8 @@ pnpm dev
1831

1932
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
2033

21-
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
34+
You can start editing the app by modifying files in `app/`, `components/`, and
35+
`content/`.
2236

2337
## Verification
2438

@@ -29,21 +43,20 @@ pnpm build
2943
pnpm test
3044
```
3145

32-
For the dependency-upgrade workflow, use the checklist in [docs/modernization-checklist.md](/Users/malik/Code/logicola/docs/modernization-checklist.md).
33-
34-
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Roboto Flex.
35-
36-
## Learn More
46+
The production build also regenerates the offline cache manifest used by the service worker.
3747

38-
To learn more about Next.js, take a look at the following resources:
48+
## Offline Support
3949

40-
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
41-
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
50+
Logicola supports offline access for published quizzes after the app has been installed or loaded while online.
4251

43-
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
52+
Technical details and maintenance notes are documented in
53+
[docs/offline-support.md](docs/offline-support.md).
4454

45-
## Deploy on Vercel
55+
## Project Notes
4656

47-
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
57+
- Quiz route publishing is tracked in `content/quiz-catalog.json`.
58+
- The offline service worker is intentionally scoped to published quizzes and the app shell they need.
59+
- For maintenance and release verification, see
60+
[docs/release-checks.md](docs/release-checks.md).
4861

49-
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
62+
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to load Roboto Flex.

app/(quiz)/[...slugs]/page.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import Quiz from '@/components/quiz';
2+
import { findQuizCatalogEntry, quizRouteSlugs } from '@/lib/quizCatalog';
3+
import { loadPublishedQuizSubSet } from '@/lib/publishedQuizLookup';
4+
import { Metadata } from 'next';
5+
import { notFound } from 'next/navigation';
6+
7+
export interface QuizPageProps {
8+
params: Promise<{ slugs: string[] }>;
9+
}
10+
11+
export default async function QuizPage({ params }: QuizPageProps) {
12+
const { slugs } = await params;
13+
const publishedQuiz = findQuizCatalogEntry(slugs);
14+
15+
if (!publishedQuiz) {
16+
notFound();
17+
}
18+
19+
const subSet = await loadPublishedQuizSubSet(slugs);
20+
21+
if (!subSet) {
22+
notFound();
23+
}
24+
25+
return (
26+
<div className='flex w-full h-screen'>
27+
{/* <ExerciseSidebar
28+
chapter={3}
29+
path={params.slugs.slice(0, -1)}
30+
isQuestionActive={(index) => {
31+
return pathname === `/informal/definitions/${index + 1}`;
32+
}}
33+
initialQuestionIdx={0}
34+
/> */}
35+
<main className='p-4 w-full'>
36+
<Quiz subSet={subSet} />
37+
</main>
38+
</div>
39+
);
40+
}
41+
42+
export function generateStaticParams() {
43+
return quizRouteSlugs.map((slugs) => ({ slugs }));
44+
}
45+
46+
export async function generateMetadata({
47+
params,
48+
}: QuizPageProps): Promise<Metadata> {
49+
const { slugs } = await params;
50+
const publishedQuiz = findQuizCatalogEntry(slugs);
51+
52+
return {
53+
title: (publishedQuiz?.title || 'Not found') + ' | Logicola',
54+
};
55+
}

app/(quiz)/layout.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import ExerciseNavbar from '@/components/mobile/exerciseNavbar';
2+
3+
export default function QuizLayout({
4+
children,
5+
}: Readonly<{
6+
children: React.ReactNode;
7+
}>) {
8+
return (
9+
<>
10+
<ExerciseNavbar />
11+
{children}
12+
</>
13+
);
14+
}

app/(site)/layout.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Navbar from '@/components/navbar';
2+
import MobileNavbar from '@/components/mobile/navbar';
3+
import { Footer } from '@/components/footer';
4+
import { quizCatalog } from '@/lib/quizCatalog';
5+
6+
export default function SiteLayout({
7+
children,
8+
}: Readonly<{
9+
children: React.ReactNode;
10+
}>) {
11+
return (
12+
<>
13+
<MobileNavbar quizCatalog={quizCatalog} />
14+
<Navbar quizCatalog={quizCatalog} />
15+
<main className='flex'>{children}</main>
16+
<Footer />
17+
</>
18+
);
19+
}
File renamed without changes.
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Metadata, Viewport } from 'next';
22
import { Roboto_Flex } from 'next/font/google';
3-
import '../globals.css';
4-
import thumbnail from '../../public/thumbnail.jpg';
3+
import thumbnail from '../../../public/thumbnail.jpg';
54

65
const robotoFlex = Roboto_Flex({
76
subsets: ['latin'],
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use client';
2-
31
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
42
import { Progress } from '@/components/ui/progress';
53
import { Button } from '@/components/ui/button';

0 commit comments

Comments
 (0)