A lightweight, offline-capable Progressive Web App (PWA) for studying for the Polish amateur radio exam. Features Q-codes flashcards with spaced repetition and phonetic alphabet trainers for both NATO and Polish alphabets.
Live Demo: https://piotrof.github.io/RadioExamHelper/
- Spaced Repetition System (SRS): Simple Leitner-based algorithm with 5 learning boxes
- Smart Scheduling: Cards are automatically scheduled for review based on your performance
- Filter by Letter: Focus on specific Q-code ranges (QRA, QRB, etc.)
- Shuffle Mode: Randomize card order for varied practice
- Progress Tracking: All progress stored locally in IndexedDB
- Dual Alphabet Support: Practice with NATO or Polish phonetic alphabets
- Random Word Generation: Built-in word lists for automatic practice
- Custom Words: Enter your own words to practice spelling
- Interactive Testing: Type your answer and get immediate feedback
- Visual Spelling Display: See letter-by-letter phonetic breakdown
- Detailed Analytics: Track reviews, accuracy, and learning streaks
- Due Card Counter: See how many cards need review today
- Progress by Level: Visual breakdown of cards in each learning stage
- Card-Level Details: Review individual Q-code performance and schedules
- Offline Support: Full functionality without internet connection
- Installable: Add to home screen on mobile and desktop
- Fast Loading: Optimized bundle size with code splitting
- Responsive Design: Works beautifully on all screen sizes
- Keyboard Shortcuts: Navigate efficiently with keyboard controls
- Node.js 18+ and npm
- Modern web browser with service worker support
-
Clone the repository
git clone https://github.com/Piotrof/RadioExamHelper.git cd RadioExamHelper -
Install dependencies
npm install
-
Fetch Q-codes data (optional)
npm run fetch-qcodes
This fetches Q-codes from the source website. If you skip this step, the app will use the built-in seed data.
-
Start development server
npm run dev
npm run buildThis will:
- Validate all data files with Zod schemas
- Build the static site with Astro
- Generate service worker for offline support
- Output to
dist/directory
Preview the production build:
npm run previewRadioExamHelper/
βββ public/
β βββ icons/ # PWA icons (72px to 512px)
β βββ manifest.webmanifest
β βββ favicon.svg
β βββ qcodes.json # Generated from fetch-qcodes script
βββ src/
β βββ components/ # React components (islands)
β β βββ ModePicker.tsx
β β βββ Flashcard.tsx
β β βββ QCodeTrainer.tsx
β β βββ PhoneticTrainer.tsx
β β βββ Stats.tsx
β βββ data/
β β βββ alphabets.ts # NATO & Polish phonetic data
β β βββ qcodes.seed.json # Fallback Q-codes
β βββ lib/
β β βββ data.ts # Zod schemas & data loading
β β βββ storage.ts # LocalForage wrappers
β β βββ srs.ts # Spaced repetition logic
β β βββ format.ts # Text normalization utilities
β βββ layouts/
β β βββ Layout.astro # Base HTML layout
β βββ pages/
β β βββ index.astro # Landing page
β β βββ qcodes.astro # Q-codes flashcards
β β βββ phonetic.astro # Phonetic trainer
β β βββ stats.astro # Statistics page
β βββ styles/
β βββ global.css # Tailwind + custom styles
βββ scripts/
β βββ fetch_qcodes.mjs # Fetch Q-codes from source
β βββ build_data.mjs # Validate data at build time
β βββ build_pwa.mjs # Generate service worker
βββ .github/
β βββ workflows/
β βββ deploy.yml # GitHub Pages deployment
βββ astro.config.mjs
βββ tailwind.config.cjs
βββ tsconfig.json
βββ package.json
βββ README.md
Q-Codes Flashcards:
Space- Reveal answer1orβ- Mark as "Again" (restart learning)2orβ- Mark as "Got It" (advance to next box)
General:
Tab- Navigate between interactive elementsEnter- Activate focused button
Q-codes data is sourced from the Polish amateur radio exam website: https://egzaminkf.pl/infusions/test_examination_a/examination.php
This app does not fetch data at runtime. Data is fetched manually once using the fetch-qcodes script and committed to the repository. This respects the source website's resources and ensures the app works completely offline.
The app uses a simplified Leitner system with 5 boxes:
| Box | Level | Review Interval |
|---|---|---|
| 0 | New | Immediate |
| 1 | Learning | 1 day |
| 2 | Review | 3 days |
| 3 | Mastered | 7 days |
| 4 | Completed | 14 days |
- β Correct Answer: Move to next box (increased interval)
- β Incorrect Answer: Return to Box 0 (start over)
-
Enable GitHub Pages
- Go to Settings β Pages
- Source: GitHub Actions
-
Push to main branch
git add . git commit -m "Initial commit" git push origin main
-
Automatic deployment The GitHub Actions workflow will automatically build and deploy on every push to
main.
Your site will be live at: https://<username>.github.io/RadioExamHelper/
Build and deploy to any static hosting:
npm run build
# Upload dist/ folder to your hosting providerCompatible with:
- Netlify
- Vercel
- Cloudflare Pages
- Any static file hosting
- Framework: Astro 4.x (Static Site Generation)
- UI Library: React 18 (Islands Architecture)
- Styling: Tailwind CSS 3.x
- Type Safety: TypeScript 5.x
- Validation: Zod 3.x
- Storage: LocalForage (IndexedDB wrapper)
- PWA: Workbox 7.x
- Bundler: Vite (via Astro)
- Chrome/Edge 90+
- Firefox 88+
- Safari 15+
- Mobile browsers with service worker support
Contributions are welcome! Please feel free to submit issues or pull requests.
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Run linting:
npm run lint - Run formatting:
npm run format - Commit:
git commit -m "Add amazing feature" - Push:
git push origin feature/amazing-feature - Open a Pull Request
MIT License - see LICENSE file for details
- Q-codes data sourced from egzaminkf.pl
- NATO phonetic alphabet from ICAO/ITU standards
- Polish phonetic alphabet from Polish radio communication standards
- Built with amazing open-source tools and libraries
If you encounter any issues or have questions:
- Open an issue on GitHub
- Check existing issues for solutions
- Review the documentation above
Happy studying and 73! π»β¨