Skip to content

kayspace/gate-ae-prep

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

150 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

gate ae β€” developer guide

A lightweight gate aerospace paper prep tracker built as a local-first browser app.

Overview

This repository contains the prep tracker app used to manage Gate AE study progress.

The app is intentionally simple:

  • React-based single-page interface (TanStack Router + TanStack Start)
  • no backend services
  • browser-only data storage (localStorage)
  • YouTube playlist and single-video support via a user-provided API key
  • in-app YouTube player with watched-time tracking and resume (for both playlists and single videos)
  • light/dark theme toggle that persists across refresh
  • floating back-to-top button for long pages
  • desktop-only experience (mobile viewports see a friendly block screen)
  • integrated feedback system backed by Notion

Contributing

We welcome contributions! Please see our Contributing Guidelines for detailed information on how to get started. It was written in a way that anyone can easily grasp the flow to contribute, do go through it thouroughly if u wanna contribute.

Repo contents

  • README.md β€” this developer guide.
  • USER_GUIDE.md β€” the user-facing guide intended for first-time visitors.
  • api/feedback.ts β€” Vercel serverless function that submits feedback to Notion.
  • src/routes/index.tsx β€” thin route shell. Wires app state, persistence, and the active view.
  • src/types/ β€” shared TypeScript types.
  • src/lib/ β€” pure utilities (storage, youtube, syllabus helpers, formatting, syllabus + books data).
  • src/data/ β€” static seed data (recommended resources).
  • src/components/ β€” reusable UI primitives and layout chrome.
  • src/features/ β€” one folder per tab/view (syllabus, books, resources, revise, log, guide).
  • src/styles.css β€” design tokens and app styling.
  • public/books/ β€” section-based PDF assets.

Development

Install dependencies

npm install

Run locally

npm run dev

Build for production

npm run build

Preview production build

npm run preview

Useful scripts

  • npm run books β€” build PDF metadata from public/books/
  • npm run dev β€” start the Vite dev server
  • npm run build β€” build the app for production
  • npm run preview β€” preview production output
  • npm run lint β€” lint the codebase
  • npm run format β€” format code with Prettier

Architecture

The app is a single-page React application using TanStack Router for routing and GSAP for entrance animations. It is intentionally local-first β€” all state lives in localStorage.

The codebase follows separation of concerns: the route file owns only top-level state and view selection; every tab is its own feature module; pure logic (storage, youtube API, syllabus stats) lives in src/lib/.

High-level flow

  1. User lands on / β†’ Home (in src/routes/index.tsx) mounts.
  2. Home hydrates state from localStorage via helpers in src/lib/storage.ts.
  3. User clicks a nav tab β†’ view state changes (ViewKey).
  4. Matching feature view renders from src/features/<view>/.
  5. User input updates state β†’ useEffect persists back to localStorage.

Directory layout

api/
└── feedback.ts                # feedback submission endpoint (Notion)
src/
β”œβ”€β”€ routes/
β”‚   β”œβ”€β”€ __root.tsx              # root layout
β”‚   └── index.tsx               # Home: state, persistence, view switch
β”œβ”€β”€ types/
β”‚   └── index.ts                # Progress, Notes, Resource, Revisions, ViewKey, ...
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ storage.ts              # STORAGE_KEYS, loadJSON, watch-state helpers
β”‚   β”œβ”€β”€ youtube.ts              # url parsing, Data API fetch, IFrame API loader
β”‚   β”œβ”€β”€ syllabus.ts             # syllabus data + Section type
β”‚   β”œβ”€β”€ syllabus-utils.ts       # topicKey, sectionStats
β”‚   β”œβ”€β”€ books.ts                # auto-generated PDF metadata
β”‚   └── format.ts               # fmtSize, etc.
β”œβ”€β”€ data/
β”‚   └── default-resources.ts    # recommended starter playlists
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ ConfirmModal.tsx        # styled confirm dialog
β”‚   β”œβ”€β”€ EmbeddedPlayer.tsx      # in-app yt player + watch tracking
β”‚   β”œβ”€β”€ BackToTop.tsx           # floating scroll-to-top button
β”‚   β”œβ”€β”€ MobileBlock.tsx         # desktop-only overlay for small viewports
β”‚   └── layout/
β”‚       β”œβ”€β”€ AppHeader.tsx       # title, progress, theme toggle, version
β”‚       β”œβ”€β”€ AppFooter.tsx
β”‚       └── ViewNav.tsx
└── features/
    β”œβ”€β”€ syllabus/SyllabusView.tsx
    β”œβ”€β”€ books/BooksView.tsx
    β”œβ”€β”€ resources/
    β”‚   β”œβ”€β”€ ResourcesView.tsx   # container: state + handlers
    β”‚   β”œβ”€β”€ ResourceItem.tsx    # single resource row + playlist drawer
    β”‚   └── YtApiKeyBox.tsx     # api-key editor
    β”œβ”€β”€ revise/ReviseView.tsx
    β”œβ”€β”€ log/LogView.tsx
    └── guide/GuideView.tsx

Why this shape

  • routes/index.tsx is a thin shell β€” easy to read end-to-end.
  • Each tab is isolated; adding a new tab means a new folder under features/ + one nav entry.
  • Pure helpers in lib/ are trivially unit-testable and free of React.
  • Types live in one place (src/types) so they can be imported from anywhere without cycles.

Data storage

All data is stored in browser localStorage. Keys are centralized in STORAGE_KEYS (src/lib/storage.ts):

  • gate-ae-progress-v1 β€” topic completion state
  • gate-ae-notes-v1 β€” per-section notes
  • gate-ae-resources-v2 β€” saved videos/playlists/links
  • gate-ae-revise-v1 β€” per-section revision queue
  • gate-ae-yt-key-v1 β€” YouTube Data API key
  • gate-ae-watch-v1 β€” per-video watched seconds, last position, duration (keyed by resourceId::videoId)
  • gate-ae-theme-v1 β€” user-selected theme (light / dark), falls back to system preference

Use loadJSON() for safe parsing with a fallback. Watch-state read/write goes through loadWatch() / saveWatch() / clearWatchFor().

No server-side storage or authentication is used.

Key modules

src/routes/index.tsx

  • Owns top-level state (progress, notes, resources, revisions, active, view).
  • Hydrates from localStorage on mount; persists on every change.
  • Renders the active feature view.

src/lib/syllabus.ts

  • Section type + syllabus array. Edit this to change sections/topics.

src/lib/syllabus-utils.ts

  • topicKey(section, topic, point) β€” stable progress key.
  • sectionStats(section, progress) β€” { done, total, pct }.

src/lib/youtube.ts

  • detectKind(url) β€” classifies a URL as video | playlist | link.
  • extractPlaylistId(url) β€” pulls list=... out of a YouTube URL.
  • fetchPlaylistVideos(playlistId, apiKey) β€” paged Data API fetch.
  • loadYouTubeAPI() β€” singleton loader for the IFrame Player API.

src/components/EmbeddedPlayer.tsx

  • In-app YouTube player with anti-skip watched-time tracking (deltas ≀ 2.5s).
  • Auto-saves position every ~3s, on pause, tab switch, and unmount.
  • Resumes from saved position; auto-marks done at 90% watched.

src/components/ConfirmModal.tsx

  • Styled confirmation dialog used wherever a destructive action needs a prompt.

YouTube integration

  1. User provides an API key on the Resources page (YtApiKeyBox).
  2. Key is stored in localStorage under STORAGE_KEYS.ytKey.
  3. When a YouTube playlist URL is added, ResourcesView:
    • extracts the playlist ID via extractPlaylistId()
    • fetches videos via fetchPlaylistVideos()
    • merges saved done flags by videoId
  4. Each video can be marked done independently or auto-marked at 90% watched.

The embedded player logic lives in EmbeddedPlayer and relies on saved watch state to resume playback cleanly.

Feedback system

The app includes a built-in feedback page that allows users to submit suggestions, bug reports, questions, and general feedback directly from the application.

Flow

  1. User opens the Feedback tab.
  2. User enters a nickname, category, and message.
  3. Frontend sends a POST request to /api/feedback.
  4. Vercel executes the serverless function in api/feedback.ts.
  5. The function creates a new entry in the configured Notion database.
  6. The feedback becomes immediately available for review inside Notion.

Notion integration

The feedback endpoint requires:

  • NOTION_TOKEN environment variable
  • a shared Notion database
  • matching database properties:
Property Type
Nickname Title
Message Rich Text
Category Select
Submitted At Date

Deployment notes

The feedback feature requires deployment on Vercel because it depends on a serverless function.

Local frontend development (npm run dev) does not execute Vercel Functions.

Customization

Update the syllabus

Edit src/lib/syllabus.ts.

Add books and PDFs

Drop new PDFs into public/books/<section>/, then run npm run books to regenerate src/lib/books.ts.

Change default/recommended resources

Edit src/data/default-resources.ts.

Modify styling

Edit src/styles.css (design tokens live at the top).

Add a new tab

  1. Add the key to ViewKey in src/types/index.ts.
  2. Add it to the VIEWS array in src/components/layout/ViewNav.tsx.
  3. Create src/features/<name>/<Name>View.tsx.
  4. Render it from src/routes/index.tsx.

Development workflow

  1. Make changes in the relevant feature module or shared lib.
  2. Test locally with npm run dev.
  3. Update USER_GUIDE.md if user-facing behavior changes.
  4. Commit and push.

Show Your Support

If you found this project helpful, please give it a star! It helps others discover the project.

Contact

For inquiries or collaborations about using the content or the code, reach out to me at kayzspace@outlook.com

License

This project is licensed under the MIT License - see the LICENSE file for details.