Skip to content

Commit

Permalink
Use Vite now that CRA is getting quite old
Browse files Browse the repository at this point in the history
  • Loading branch information
nanreh committed Jan 6, 2025
1 parent cf36c0c commit cf3106f
Show file tree
Hide file tree
Showing 60 changed files with 2,720 additions and 8,422 deletions.
7 changes: 7 additions & 0 deletions .babelrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"presets": [
["@babel/preset-env", { "targets": { "esmodules": true } }], // It's the name of the lib you installed
["@babel/preset-react", { "runtime": "automatic" }], // It's the name of the lib you installed
"@babel/preset-typescript" // It's the name of the lib you installed
]
}
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
/coverage

# production
/build
/dist

# misc
.DS_Store
Expand Down
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
38 changes: 16 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,35 @@ More project details are available on [the About page](https://www.defy.org/hack
If you have a bugfix, a new feature, a new training plan, a UX/UI fix, or other contribution, please send a PR.
Feel free to create a GitHub issue if you want to call something out.

## Plans
Training plans are represented as YAML files that are easy to create and edit. They can be found in [plans/yaml](public/plans/yaml/). A JSON schema exists at [public/schema/plan-schema.json](public/schema/plan-schema.json)

## Running Locally

Calendar Hack is a React application. It was created using [Create React App](https://reactjs.org/docs/create-a-new-react-app.html#create-react-app) with the TypeScript template:
```
yarn create react-app ch-bootstrap --template typescript
```
So you can run locally with: `yarn start`

The other standard scripts exist also: `yarn test`, `yard build`, etc.


## Validating Plans
Calendar Hack is a React application. Using yarn, you can run it locally with: `yarn dev`

The plan validator depends on ajv to validate against a JSON schema
The other standard scripts exist also: `yarn test`, `yarn build`, etc.

Install ajv
`npm install -g ajv-cli`

then
## Plans
Training plans are represented as YAML files that are easy to create and edit. They can be found in [plans/yaml](public/plans/yaml/).

`yarn run validatePlans`
Plans can be validated against a JSON schema ([public/schema/plan-schema.json](public/schema/plan-schema.json)) as follows:

```
# Install ajv
npm install -g ajv-cli
# Run the validator with yarn
yarn run validatePlans
```

## Converting new plans

If you are adding a plan, you should write it in YAML and then run
`./bin/convertPlans` to generate the JSON version for the application. The converter is written in python and requires pyyaml
If you are adding a new plan or modifying an existing one, you should work with the YAML version of the plan.

A simple program then converts the YAML plans to JSON for the application to consume:
```
python3 -m venv my_env
source ./venv/bin/activate
pip install pyyaml
python3 ./bin/convertPlans
```
```

TODO: automate this step
28 changes: 28 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)
20 changes: 20 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="manifest" href="/manifest.json" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
<meta name="description" content="defy.org: Calendar Hack" />
<meta name="theme-color" content="#ffffff">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>defy.org: Calendar Hack</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
9 changes: 9 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default {
testEnvironment: "jest-environment-jsdom", // Same name of the lib you installed
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"], // The file you created to extend jest config and "implement" the jest-dom environment in the jest globals
moduleNameMapper: {
"\\.(gif|ttf|eot|svg|png)$": "<rootDir>/test/__mocks__/fileMock.js", // The global stub for weird files
"\\.(css|less|sass|scss)$": "identity-obj-proxy", // The mock for style related files
"^@/(.*)$": "<rootDir>/src/$1", // [optional] Are you using aliases?
},
};
6 changes: 6 additions & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import "@testing-library/jest-dom";

// nanoid gives a syntax error without this (see: https://github.com/ai/nanoid/issues/363)
jest.mock("nanoid", () => { return {
nanoid : ()=>{}
} });
94 changes: 49 additions & 45 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,68 +1,72 @@
{
"name": "ch-bootstrap",
"name": "calendar-hack",
"version": "0.1.0",
"homepage": "./",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
"test": "jest --watchAll",
"cov": "jest --coverage --collectCoverageFrom='src/**/*.{ts,tsx}'",
"validatePlans": "bash bin/validatePlans",
"pretty": "prettier src --write"
},
"dependencies": {
"copy-to-clipboard": "3.3.3",
"cross-fetch": "4.0.0",
"date-fns": "4.1.0",
"dnd-core": "^16.0.1",
"history": "5.3.0",
"ics": "3.6.3",
"ics": "3.8.1",
"moo": "0.5.2",
"rdndmb-html5-to-touch": "8.0.2",
"react": "17.0.2",
"rdndmb-html5-to-touch": "^7.1.3",
"react": "^18.3.1",
"react-datepicker": "6.6.0",
"react-dnd": "^15.1.2",
"react-dnd-multi-backend": "8.0.2",
"react-dom": "17.0.2",
"react-dnd": "^16.0.1",
"react-dnd-multi-backend": "^8.1.2",
"react-dom": "^18.3.1",
"react-icons": "5.3.0",
"react-scripts": "5.0.1",
"styled-components": "6.1.8",
"stylis": "4.0.0",
"use-query-params": "2.2.1",
"weekstart": "2.0.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"validatePlans": "bash bin/validatePlans"
},
"eslintConfig": {
"extends": [
"react-app"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
"resolutions": {
"@types/react": "18.3.1",
"@types/react-dom": "18.3.1"
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@testing-library/jest-dom": "4.2.4",
"@testing-library/react": "9.3.2",
"@testing-library/user-event": "7.1.2",
"@types/history": "5.0.0",
"@types/jest": "^29.5.12",
"@types/moo": "^0.5.9",
"@babel/core": "^7.26.0",
"@babel/preset-env": "^7.26.0",
"@babel/preset-react": "^7.26.3",
"@babel/preset-typescript": "^7.26.0",
"@eslint/js": "^9.17.0",
"@testing-library/dom": "^10.0.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.1.0",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.14",
"@types/moo": "^0.5.2",
"@types/react": "^18.3.18",
"@types/react-datepicker": "^6.2.0",
"eslint-config-prettier": "8.6.0",
"eslint-plugin-prettier": "4.2.1",
"prettier": "2.8.8",
"@types/react-dom": "^18.3.5",
"@vitejs/plugin-react": "^4.3.4",
"babel-jest": "^29.7.0",
"eslint": "^9.17.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.16",
"globals": "^15.14.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "3.4.2",
"timezone-mock": "1.3.6",
"typescript": "5.1.6"
},
"resolutions": {
"react-scripts/typescript": "5.1.6"
"ts-node": "^10.9.2",
"typescript": "~5.6.2",
"typescript-eslint": "^8.18.2",
"vite": "^6.0.5"
}
}
23 changes: 10 additions & 13 deletions public/plans/yaml/frr_multiple_distances_01.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,14 @@ schedule:
- title: General aerobic + Speed {6:10}
description: |-
General aerobic + Speed {6:10}
2 sets of 4 x 200m @ 800m to mile race pace
(jog 200m recovery and 4 min between sets)
2 sets of 4 x 200m @ 800m to mile race pace (jog 200m recovery and 4 min between sets)
distance: 6.0
- title: Endurance {8:13}
distance: 8.0
- title: Rest or cross-training
- title: VO2max {8:13}
- title: Lactate Threshold {8:13}
description: |-
VO2max {8:13}
Lactate Threshold {8:13}
12 min LT interval (jog 4 min recovery)
10 min LT interval (jog 4 min recovery)
8 min LT interval
Expand Down Expand Up @@ -78,7 +77,7 @@ schedule:
- title: General aerobic {7:11}
distance: 7.0
- title: Rest or cross-training
- title: Endurance {9:14}
- title: General Aerobic {9:14}
distance: 9.0
- workouts:
- title: Rest or cross-training
Expand All @@ -91,7 +90,7 @@ schedule:
- title: Rest or cross-training
- title: Lactate threshold {8:13}
description: |-
15 min LT interval (jog 4 min recovery)
14 min LT interval (jog 4 min recovery)
11 min LT interval (jog 4 min recovery)
8 min LT interval
distance: 8.0
Expand All @@ -111,7 +110,7 @@ schedule:
- title: Rest or cross-training
- title: General aerobic + Speed {7:11}
description: |-
2 sets of 6 x 100 m strides (job 3 min between sets)
2 sets of 6 x 100 m strides (jog 3 min between sets)
distance: 7.0
- title: Recovery {3:5}
distance: 3.0
Expand Down Expand Up @@ -153,24 +152,22 @@ schedule:
distance: 9.0
- workouts:
- title: Rest or cross-training
- title: General aerobic + speed {8:13}
- title: General aerobic + speed {7:11}
description: |-
8 x 100 m strides
distance: 8.0
- title: General aerobic {7:11}
distance: 7.0
- title: Recovery {4:6}
distance: 4.0
- title: VO2max {8:13}
description: |-
3 x 1000 m
6 x 600 m
All intervals @ 3K-5K race pace (job 50-90% interval time recovery)
3 x 600 m
All intervals @ 3K-5K race pace (jog 50-90% interval time recovery)
distance: 8.0
- title: Rest or cross-training
- title: Recovery {4:6}
distance: 4.0
- title: Endurance {9:14}
- title: General Aerobic {9:14}
distance: 9.0
- workouts:
- title: Race pace + speed {6:10}
Expand Down
12 changes: 6 additions & 6 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,18 @@ const App = () => {
s: NumberParam,
});
const [selectedUnits, setSelectedUnits] = useState<Units>(
u === "mi" || u === "km" ? u : getLocaleUnits()
u === "mi" || u === "km" ? u : getLocaleUnits(),
);
var [selectedPlan, setSelectedPlan] = useState(repo.find(p || ""));
var [racePlan, setRacePlan] = useState<RacePlan | undefined>(undefined);
var [undoHistory, setUndoHistory] = useState([] as RacePlan[]);
var [weekStartsOn, setWeekStartsOn] = useState<WeekStartsOn>(
s === 0 || s === 1 || s === 6 ? s : WeekStartsOnValues.Monday
s === 0 || s === 1 || s === 6 ? s : WeekStartsOnValues.Monday,
);
var [planEndDate, setPlanEndDate] = useState(
d && isAfter(d, new Date())
? d
: addWeeks(endOfWeek(new Date(), { weekStartsOn: weekStartsOn }), 20)
: addWeeks(endOfWeek(new Date(), { weekStartsOn: weekStartsOn }), 20),
);

useMountEffect(() => {
Expand All @@ -117,7 +117,7 @@ const App = () => {
units: Units,
plan: PlanSummary,
date: Date,
weekStartsOn: WeekStartsOn
weekStartsOn: WeekStartsOn,
) => {
return {
u: units,
Expand All @@ -131,7 +131,7 @@ const App = () => {
plan: PlanSummary,
endDate: Date,
units: Units,
weekStartsOn: WeekStartsOn
weekStartsOn: WeekStartsOn,
) => {
const racePlan = build(await repo.fetch(plan), endDate, weekStartsOn);
setRacePlan(racePlan);
Expand Down Expand Up @@ -202,7 +202,7 @@ const App = () => {

return (
<ThemeProvider theme={theme}>
<Toolbar downloadHandler={downloadHandler} />
<Toolbar />
<PlanAndDate
units={selectedUnits}
availablePlans={repo.available}
Expand Down
Loading

0 comments on commit cf3106f

Please sign in to comment.