Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/airgead-investment-calculator/llms.txt

Use this file to discover all available pages before exploring further.

Airgead uses a deliberately simple architecture — no framework, no bundler, and no npm dependencies. Every interactive behaviour is written in plain JavaScript organised into ES modules that are loaded natively by the browser via <script type="module"> tags. This keeps the project transparent, easy to read, and straightforward to extend without a build pipeline standing in the way.

Module Layers

The codebase is divided into four distinct layers, each with a clearly scoped responsibility:

Shell Component

js/components/shell.jsInjects the full page chrome — header, desktop nav, mobile nav with hamburger toggle, footer, and the toast notification container — into every page. Also exports the toast() helper used by page controllers to display feedback messages.

Calculation Library

js/lib/calculator.jsContains all compound interest logic, the money() currency formatter, localStorage read/write helpers (saveCurrentCalculation, getCurrentCalculation, getSavedPlans, setSavedPlans), and the downloadCsv() export utility.

Chart Library

js/lib/charts.jsHandles all Canvas API drawing. Exports drawGrowthChart() for the single-scenario area/line chart on the Results page, and drawComparisonChart() for the stacked bar chart on the Compare page. Both functions are responsive and re-draw on window resize.

Page Controllers

js/pages/Thin scripts, one per HTML page, that wire together the DOM, the calculation library, and the chart library. They contain no business logic of their own — their job is to read inputs, call library functions, and update the UI with the returned values.

Page Controller Responsibilities

Each script in js/pages/ corresponds to one HTML page and owns a narrow slice of the user interface:
ScriptPageResponsibility
calculator.jscalculator.htmlReads form inputs on every input event, calls calculateCompoundInterest(), animates the live balance display, updates quick-stat tiles, and calls saveCurrentCalculation() + redirects to results.html on form submit
results.jsresults.htmlCalls getCurrentCalculation() on load, populates the summary stats and year-by-year table, draws the growth chart via drawGrowthChart(), handles the Save Plan button (getSavedPlans / setSavedPlans), and triggers CSV export via downloadCsv()
compare.jscompare.htmlReads both scenario forms on every input event, calls calculateCompoundInterest() for each, updates the final-balance tiles, and redraws the comparison chart via drawComparisonChart()
login.jslogin.htmlHandles the mock sign-in form submission and stores the entered email under the airgead_user localStorage key for demonstration purposes
noop.jsStatic pagesImported by home.js for pages that only need the shell rendered and have no additional interactive behaviour of their own

Shell Injection

js/components/shell.js runs immediately on import — the final line of the file calls renderShell() at module evaluation time, so no explicit invocation is needed in page scripts. When renderShell() executes, it:
  1. Reads location.pathname to determine whether the page is inside the /pages/ subdirectory and sets root to '../' if so, or '' if not — ensuring all asset and navigation paths resolve correctly regardless of nesting depth
  2. Iterates the hardcoded links array to build <a> elements, comparing each href against the current filename (location.pathname.split('/').pop()) to apply an .active CSS class to the matching link
  3. Calls shell.insertAdjacentHTML('afterbegin', ...) to inject the <header> and mobile panel before the [data-shell] wrapper’s existing content
  4. Calls shell.insertAdjacentHTML('beforeend', ...) to inject the <footer> and toast container after the wrapper’s content
The toast(message) export sets the text content of the .toast element, adds a show class, and removes it after 2,400 ms.

Data Flow

The following steps trace the full path from user input on the Calculator page through to a saved plan:
  1. User fills the Calculator form → on every input event, calculator.js calls calculateCompoundInterest(inputs) from the library and updates the animated live display and quick-stat tiles in real time
  2. User submits the formcalculator.js calls saveCurrentCalculation(inputs, data), which serialises inputs, the full results array, and a timestamp into localStorage under airgead_current_calc, then redirects the browser to results.html
  3. Results page loadsresults.js immediately calls getCurrentCalculation() to read back the stored object; if the key is absent or unparseable, the user is redirected back to calculator.html
  4. Results page rendersresults.js populates the summary stat cards and the year-by-year <table>, then calls drawGrowthChart(canvas, results) to render the area chart via the Canvas API
  5. User clicks Save Planresults.js calls getSavedPlans() to load the existing array, pushes a new plan object (containing id, date, name, and the full data object), and calls setSavedPlans(plans) to write the updated array back to localStorage under airgead_saved_plans
Because Airgead uses native ES modules (<script type="module">), the project must be served over HTTP or HTTPS — it cannot be opened directly from the filesystem via a file:// URL. Modern browsers block cross-origin module imports when using the file:// protocol. Running a local development server (such as VS Code’s Live Server extension, Python’s http.server, or any static file server) is all that is needed.

Build docs developers (and LLMs) love