Vue 3 (Composition API + <script setup>) + TypeScript + Pinia + Vue Router + Vite + PWA + Tailwind CSS.
src/
├── main.js # App entry
├── App.vue # Root layout
├── index.css # Global styles
├── util.ts # Utility functions (localStorage, type aliases)
├── router/index.ts # Routes: /welcome → /exercise/:cat/:params/:n → /report
├── store/
│ ├── setting.ts # Persisted settings (category, quantity, params, avoidRepeat)
│ ├── question.ts # Question session state (questions, progress, timing, answer logic)
│ └── mistakes.ts # Mistake collection (persisted)
├── question/
│ ├── index.ts # Core types: Question, QuestionModule, QuestionProvider, AnswerResult, helpers
│ ├── loading.ts # Default loading module placeholder
│ ├── add-sub.ts # Category implementations (add, sub, mul, div, pow, pff, disc-2, sqrt...)
│ └── ...
├── components/
│ ├── Welcome.vue # Category/params form
│ ├── Exercise.vue # Main exercise UI (question display, answer input, progress)
│ ├── Report.vue # Score report / results (includes share modal)
│ ├── QuestionsPrint.vue # Printable question sheet
│ ├── MistakesCollection.vue # Mistake review page
│ └── report/
│ ├── QuestionDisplay.vue
│ └── QuestionShareDisplay.vue
└── assets/
└── components/
├── Duration.vue # Time display component
└── CustomizedFooter.vue # App footer
- Welcome → User selects category/params/quantity → URL navigation to
/exercise/:category/:params/:quantity - Exercise →
useSettingStorereads URL params →categoryIdchange triggersquestionStoreto dynamicallyimport()the question module →reset_questions()pre-generates all questions → user answers →answer_current_question()updates progress/duration/mistakes → all done → navigate to/report - Report → Reads completed
questionsfrom store → displays stats + each Q&A → can navigate to share or main page - Persistence →
settingstore syncs to localStorage;mistakesstore persists wrong answers for review
- Pinia stores use Composition API (
defineStorewith setup function) - Question modules export
QuestionModuleinterface withget_provider(),paramsConfig, and optionalvalidate() QUESTION_CONTEXTsingleton contains all question helper dependencies (reduces bundle via code splitting)- Dynamic imports for question categories (lazy loading)
- PWA via
vite-plugin-pwawith WorkboxNetworkOnlyfor umami analytics pnpm build— production buildpnpm test— run testspnpm ts-check— TypeScript type checkingpnpm check— type checking + test coverage