From e7c69ea6f7358e78acad36eca99c96eeeed096ce Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Tue, 10 Mar 2026 16:55:36 +0900 Subject: write app plus touchup --- ai_prompt.md | 521 +++++++++++++++++++++++++++++++++++ src/App.css | 42 --- src/App.tsx | 148 ++++++++-- src/assets/react.svg | 1 - src/components/ResultDisplay.tsx | 48 ++++ src/components/SizeSelector.tsx | 81 ++++++ src/data/tire_sizes.json | 74 +++++ src/index.css | 70 +---- src/types.ts | 26 ++ src/utils/calculate_circumference.ts | 36 +++ 10 files changed, 905 insertions(+), 142 deletions(-) create mode 100644 ai_prompt.md delete mode 100644 src/App.css delete mode 100644 src/assets/react.svg create mode 100644 src/components/ResultDisplay.tsx create mode 100644 src/components/SizeSelector.tsx create mode 100644 src/data/tire_sizes.json create mode 100644 src/types.ts create mode 100644 src/utils/calculate_circumference.ts diff --git a/ai_prompt.md b/ai_prompt.md new file mode 100644 index 0000000..89660db --- /dev/null +++ b/ai_prompt.md @@ -0,0 +1,521 @@ +## Me + +> Context: +> - .rules/daisyui.md +> - .rules/project.md +> - reference/tire-sizes.json +> - reference/howto.mdown +> - files + +I need you to use @{files} to build a frontend. + +It will contain the following +- 2 dropdowns: one for rim size and one for tire size + - the values in this dropdowns will come from the json file I have given you. place this json file in an appropriate spot in the project +- each of those dropdowns will have an accompanying text box + - these textboxes will only accept numbers + - when a dropdown option is selected, it will fill the text box with the corresponding value from the json + - whenever the textbox value is manually updated by the user, the dropdown should update automatically to match the number with the first matching value. if there are no matching values instead set the dropdown to a value called "custom". This "custom" value should be at the bottom of the selections. If custom is selected in the dropdown by a user nothing should happen or change in the text box +- an output box which will have the resulting value from the options selected based on the equation in the given howto.mdown file + +you may completely remove the default given code and start from scratch as you see fit. + +## CodeCompanion (Copilot) + + + +I'll start by exploring the project structure to understand what exists, then build the app. + +Searched files for `**/*`, 50 results +``` +.dockerignore +.gitignore +.tool-versions +Dockerfile +README.md +docker-compose.yml +docker-entrypoint.sh +docker_readme.md +eslint.config.js +index.html +package-lock.json +package.json +tsconfig.app.json +tsconfig.json +tsconfig.node.json +vite.config.ts +.git/COMMIT_EDITMSG +.git/HEAD +.git/config +.git/description +.git/index +.rules/daisyui.md +.rules/project.md +node_modules/.package-lock.json +public/vite.svg +reference/howto.mdown +reference/tire-sizes.json +src/App.css +src/App.tsx +src/index.css +src/main.tsx +.git/hooks/applypatch-msg.sample +.git/hooks/commit-msg.sample +.git/hooks/fsmonitor-watchman.sample +.git/hooks/post-update.sample +.git/hooks/pre-applypatch.sample +.git/hooks/pre-commit.sample +.git/hooks/pre-merge-commit.sample +.git/hooks/pre-push.sample +.git/hooks/pre-rebase.sample +.git/hooks/pre-receive.sample +.git/hooks/prepare-commit-msg.sample +.git/hooks/push-to-checkout.sample +.git/hooks/sendemail-validate.sample +.git/hooks/update.sample +.git/info/exclude +.git/logs/HEAD +node_modules/acorn/CHANGELOG.md +node_modules/acorn/LICENSE +node_modules/acorn/README.md +``` + + +Read file `package.json` (0 - end) + + +Read file `src/index.css` (0 - end) + + +Read file `src/App.tsx` (0 - end) + + +Read file `src/App.css` (0 - end) + + +Read file `src/main.tsx` (0 - end) + + +Read file `index.html` (0 - end) + + +Read file `vite.config.ts` (0 - end) + + +Now I have a clear picture. Let me plan the implementation: + +1. Copy the tire sizes JSON into `src/data/tire_sizes.json` +2. Create a TypeScript types file for the data +3. Create a `circumference_calculator` component +4. Rewrite `App.tsx` to use it +5. Clean up `index.css` (remove custom styles, keep Tailwind+daisyUI) +6. Delete `App.css` and the assets folder + +Let me build this step by step: + +Searched files for `src/assets/*`, 1 results +``` +src/assets/react.svg +``` + + +Created file `src/data/tire_sizes.json` + +````json +{ + "wheel_sizes": [ + { "label": "12.5\"", "diameter_mm": 203 }, + { "label": "14\"", "diameter_mm": 254 }, + { "label": "16\"", "diameter_mm": 305 }, + { "label": "20\"", "diameter_mm": 406 }, + { "label": "24\" BMX/Kids Bikes", "diameter_mm": 507 }, + { "label": "24\" Terry Bicycles", "diameter_mm": 520 }, + { "label": "24\"", "diameter_mm": 540 }, + { "label": "24\" Schwinn", "diameter_mm": 540 }, + { "label": "26\"", "diameter_mm": 559 }, + { "label": "650c", "diameter_mm": 571 }, + { "label": "650b", "diameter_mm": 584 }, + { "label": "27.5", "diameter_mm": 584 }, + { "label": "26 x 1 1/2\"", "diameter_mm": 584 }, + { "label": "650a", "diameter_mm": 590 }, + { "label": "26 x 1 3/8\"", "diameter_mm": 590 }, + { "label": "650", "diameter_mm": 597 }, + { "label": "26 x 1 1/4\"", "diameter_mm": 597 }, + { "label": "29er", "diameter_mm": 622 }, + { "label": "700c", "diameter_mm": 622 }, + { "label": "27 inch", "diameter_mm": 630 } + ], + "tire_sizes": [ + { "label": "18C", "diameter_mm": 18 }, + { "label": "19C", "diameter_mm": 19 }, + { "label": "20C", "diameter_mm": 20 }, + { "label": "21C", "diameter_mm": 21 }, + { "label": "23C", "diameter_mm": 23 }, + { "label": "25C", "diameter_mm": 25 }, + { "label": "26C", "diameter_mm": 26 }, + { "label": "28C", "diameter_mm": 28 }, + { "label": "30C", "diameter_mm": 30 }, + { "label": "32C", "diameter_mm": 32 }, + { "label": "35C", "diameter_mm": 35 }, + { "label": "38C", "diameter_mm": 38 }, + { "label": "40C", "diameter_mm": 40 }, + { "label": "44C", "diameter_mm": 44 }, + { "label": "50C", "diameter_mm": 50 }, + { "label": "56C", "diameter_mm": 56 }, + { "label": "1.00 inch", "diameter_mm": 25.4 }, + { "label": "1 1/8 inch", "diameter_mm": 28.575 }, + { "label": "1.25 inch", "diameter_mm": 31.75 }, + { "label": "1 3/8 inch", "diameter_mm": 34.925 }, + { "label": "1.4 inch", "diameter_mm": 35.56 }, + { "label": "1.5 inch", "diameter_mm": 38.1 }, + { "label": "1.75 inch", "diameter_mm": 44.45 }, + { "label": "1.95 inch", "diameter_mm": 49.5 }, + { "label": "2.00 inch", "diameter_mm": 50.8 }, + { "label": "2.10 inch", "diameter_mm": 53.34 }, + { "label": "2.125 inch", "diameter_mm": 54 }, + { "label": "2.20 inch", "diameter_mm": 55.88 }, + { "label": "2.25 inch", "diameter_mm": 57.15 }, + { "label": "2.30 inch", "diameter_mm": 58.42 }, + { "label": "2.35 inch", "diameter_mm": 59.69 }, + { "label": "2.40 inch", "diameter_mm": 60.69 }, + { "label": "2.50 inch", "diameter_mm": 63.5 }, + { "label": "2.60 inch", "diameter_mm": 66.04 }, + { "label": "2.70 inch", "diameter_mm": 68.58 }, + { "label": "2.80 inch", "diameter_mm": 71.12 }, + { "label": "2.90 inch", "diameter_mm": 73.66 }, + { "label": "3.0 inch", "diameter_mm": 76.2 }, + { "label": "3.1 inch", "diameter_mm": 78.74 }, + { "label": "3.2 inch", "diameter_mm": 81.28 }, + { "label": "3.3 inch", "diameter_mm": 83.82 }, + { "label": "3.4 inch", "diameter_mm": 86.36 }, + { "label": "3.5 inch", "diameter_mm": 88.9 }, + { "label": "3.6 inch", "diameter_mm": 91.44 }, + { "label": "3.7 inch", "diameter_mm": 93.98 }, + { "label": "3.8 inch", "diameter_mm": 96.52 }, + { "label": "3.9 inch", "diameter_mm": 99.06 }, + { "label": "4.0 inch", "diameter_mm": 101.6 } + ] +} + +```` + + +Created file `src/types.ts` + +````ts +/** + * Type definitions for the tire size data used throughout the app. + * Each size entry has a human-readable label and a diameter in millimeters. + */ + +/** A single rim or tire size option from our reference data. */ +export interface SizeOption { + label: string; + diameter_mm: number; +} + +/** The shape of the imported tire_sizes.json file. */ +export interface TireSizeData { + wheel_sizes: SizeOption[]; + tire_sizes: SizeOption[]; +} + +/** + * Results from the circumference calculation. + * All values derived from: circumference = 3.13772 * (2 * tire + rim) + */ +export interface CircumferenceResult { + mm: number; + cm: number; + inches: number; + mph_setting: number; +} + +```` + + +Created file `src/utils/calculate_circumference.ts` + +````ts +/** + * calculate_circumference.ts + * + * Pure function that computes the bicycle wheel circumference from rim and + * tire diameters (both in mm). The formula uses 3.13772 instead of exact π + * to approximate the "roll-out" circumference (tire compressed under rider + * weight). + * + * Formula: circumference_mm = 3.13772 × (2 × tire_diameter + rim_diameter) + */ + +import type { CircumferenceResult } from "../types"; + +/** The modified Pi constant that accounts for tire compression. */ +const ROLLOUT_PI = 3.13772; + +/** + * Returns circumference in multiple units, or null when inputs are invalid + * (non-positive or missing). + */ +export function calculate_circumference( + rim_mm: number, + tire_mm: number, +): CircumferenceResult | null { + if (rim_mm <= 0 || tire_mm <= 0 || isNaN(rim_mm) || isNaN(tire_mm)) { + return null; + } + + const circ_mm = ROLLOUT_PI * (2 * tire_mm + rim_mm); + + return { + mm: Math.round(circ_mm), + cm: Math.round(circ_mm / 10), + inches: Math.round((10 * circ_mm) / 25.4) / 10, + mph_setting: Math.round(circ_mm / 1.6), + }; +} + +```` + + +Now create the main component with the two dropdowns, text inputs, and result output: + +Created file `src/components/SizeSelector.tsx` + +````tsx +/** + * SizeSelector.tsx + * + * A reusable pair of for choosing a rim or tire size. + * + * Behaviour: + * - Selecting a dropdown option fills the text input with its diameter_mm. + * - Typing a number in the text input auto-selects the first matching + * dropdown option, or falls back to "Custom" if no match exists. + * - Choosing "Custom" in the dropdown does nothing to the text input. + */ + +import type { SizeOption } from "../types"; + +/** Sentinel value used as the